Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
HTML
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
3 / 3
11
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 save
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 writeHeader
n/a
0 / 0
n/a
0 / 0
1
 writeTask
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 writeFooter
n/a
0 / 0
n/a
0 / 0
1
1<?php
2
3/**
4 * This file is part of PHPProject - A pure PHP library for reading and writing
5 * project management files.
6 *
7 * PHPProject is free software distributed under the terms of the GNU Lesser
8 * General Public License version 3 as published by the Free Software Foundation.
9 *
10 * For the full copyright and license information, please read the LICENSE
11 * file that was distributed with this source code. For the full list of
12 * contributors, visit https://github.com/PHPOffice/PHPProject/contributors.
13 *
14 * @link        https://github.com/PHPOffice/PHPProject
15 * @copyright   2009-2014 PHPProject contributors
16 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
17 */
18
19declare(strict_types=1);
20
21namespace PhpOffice\PhpProject\Writer;
22
23use PhpOffice\PhpProject\PhpProject;
24use PhpOffice\PhpProject\Task;
25
26/**
27 * HTML writer (Gantt chart rendered with frappe-gantt)
28 */
29class HTML implements WriterInterface
30{
31    /**
32     * PHPProject object
33     *
34     * @var PhpProject
35     */
36    protected $phpProject;
37
38    /**
39     * Create a new HTML writer
40     *
41     * @param PhpProject $phpProject
42     */
43    public function __construct(PhpProject $phpProject)
44    {
45        $this->phpProject = $phpProject;
46    }
47
48    /**
49     * @param string $pFilename
50     * @throws \Exception
51     */
52    public function save(string $pFilename): void
53    {
54        // Tasks (frappe-gantt JS objects)
55        $tasks = '';
56        foreach ($this->phpProject->getAllTasks() as $task) {
57            $tasks .= $this->writeTask($task);
58        }
59
60        // Full HTML page : header + tasks + footer
61        $content = $this->writeHeader() . $tasks . $this->writeFooter();
62
63        // Writing the HTML page in file
64        if (file_exists($pFilename) && !is_writable($pFilename)) {
65            throw new \Exception("Could not open file $pFilename for writing.");
66        }
67        $fileHandle = fopen($pFilename, 'wb+');
68        fwrite($fileHandle, $content);
69        fclose($fileHandle);
70    }
71
72    /**
73     * Generate the HTML header : page skeleton, frappe-gantt includes and the
74     * opening of the tasks array.
75     *
76     * @return string
77     */
78    protected function writeHeader(): string
79    {
80        return <<<'HTML'
81<!DOCTYPE html>
82<html lang="en">
83<head>
84    <meta charset="UTF-8">
85    <title>PhpProject</title>
86    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/frappe-gantt/dist/frappe-gantt.css">
87    <script src="https://cdn.jsdelivr.net/npm/frappe-gantt/dist/frappe-gantt.umd.js"></script>
88</head>
89<body>
90    <div id="gantt"></div>
91    <script>
92        let tasks = [
93
94HTML;
95    }
96
97    /**
98     * Generate the JS object for one task (frappe-gantt format).
99     *
100     * @param Task $task
101     * @return string
102     */
103    protected function writeTask(Task $task): string
104    {
105        $data = array(
106            'id' => (string) $task->getIndex(),
107            'name' => $task->getName(),
108        );
109        if ($task->getStartDate() !== null) {
110            $data['start'] = date('Y-m-d', $task->getStartDate());
111        }
112        if ($task->getEndDate() !== null) {
113            $data['end'] = date('Y-m-d', $task->getEndDate());
114        }
115        $data['progress'] = (int) (($task->getProgress() ?? 0) * 100);
116
117        $line = '            ' . (string) json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ",\n";
118
119        // Sub-tasks (recursive)
120        foreach ($task->getTasks() as $taskChild) {
121            $line .= $this->writeTask($taskChild);
122        }
123
124        return $line;
125    }
126
127    /**
128     * Generate the HTML footer : close the tasks array, instantiate the Gantt
129     * chart and close the page.
130     *
131     * @return string
132     */
133    protected function writeFooter(): string
134    {
135        return <<<'HTML'
136        ];
137        let gantt = new Gantt("#gantt", tasks);
138    </script>
139</body>
140</html>
141HTML;
142    }
143}