Completed
Push — develop ( ffe009...9d0b73 )
by Mike
09:33
created

Version3::convert()   B

Complexity

Conditions 9
Paths 32

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 32
nop 1
dl 0
loc 32
rs 8.0555
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * This file is part of phpDocumentor.
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @author    Mike van Riel <[email protected]>
11
 * @copyright 2010-2018 Mike van Riel / Naenius (http://www.naenius.com)
12
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
13
 * @link      http://phpdoc.org
14
 */
15
16
namespace phpDocumentor\Configuration\Factory;
17
18
use InvalidArgumentException;
19
use phpDocumentor\DomainModel\Dsn;
20
use phpDocumentor\DomainModel\Path;
21
use SimpleXMLElement;
22
23
/**
24
 * phpDocumentor3 strategy for converting the configuration xml to an array.
25
 */
26
final class Version3 implements Strategy
27
{
28
    /**
29
     * The path to the xsd that is used for validation of the configuration file.
30
     *
31
     * @var string
32
     */
33
    private $schemaPath;
34
35
    /**
36
     * Initializes the PhpDocumentor3 strategy.
37
     */
38
    public function __construct(string $schemaPath)
39
    {
40
        $this->schemaPath = $schemaPath;
41
    }
42
43
    public function convert(SimpleXMLElement $phpDocumentor): array
44
    {
45
        $this->validate($phpDocumentor);
46
47
        $versions = [];
48
        $templates = [];
49
50
        foreach ($phpDocumentor->children() as $child) {
51
            switch ($child->getName()) {
52
                case 'version':
53
                    $versions[(string) $child->attributes()->number] = $this->buildVersion($child);
54
                    break;
55
                case 'template':
56
                    $templates[] = $this->buildTemplate($child);
57
                    break;
58
                default:
59
                    break;
60
            }
61
        }
62
63
        return [
64
            'phpdocumentor' => [
65
                'use-cache' => $phpDocumentor->{'use-cache'} ?: true,
66
                'paths' => [
67
                    'output' => new Dsn(((string) $phpDocumentor->paths->output) ?: 'file://build/docs'),
68
                    'cache' => new Path(((string) $phpDocumentor->paths->cache) ?: '/tmp/phpdoc-doc-cache'),
69
                ],
70
                'versions' => ($versions) ?: $this->defaultVersions(),
71
                'templates' => ($templates) ?: [$this->defaultTemplate()],
72
            ],
73
        ];
74
    }
75
76
    public function supports(SimpleXMLElement $phpDocumentor): bool
77
    {
78
        return (string) $phpDocumentor->attributes()->version === '3';
79
    }
80
81
    public static function buildDefault(): array
82
    {
83
        return [
84
            'phpdocumentor' => [
85
                'title' => 'my docs',
86
                'use-cache' => true,
87
                'paths' => [
88
                    'output' => new Dsn('file://build/docs'),
89
                    'cache' => new Path('/tmp/phpdoc-doc-cache'),
90
                ],
91
                'versions' => static::defaultVersions(),
0 ignored issues
show
Comprehensibility introduced by
Since phpDocumentor\Configuration\Factory\Version3 is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
92
                'templates' => [static::defaultTemplate()],
0 ignored issues
show
Comprehensibility introduced by
Since phpDocumentor\Configuration\Factory\Version3 is declared final, using late-static binding will have no effect. You might want to replace static with self instead.

Late static binding only has effect in subclasses. A final class cannot be extended anymore so late static binding cannot occurr. Consider replacing static:: with self::.

To learn more about late static binding, please refer to the PHP core documentation.

Loading history...
93
            ],
94
        ];
95
    }
96
97
    /**
98
     * Builds the versions part of the array from the configuration xml.
99
     */
100
    private function buildVersion(SimpleXMLElement $version): array
101
    {
102
        $apis = [];
103
        $guides = [];
104
        foreach ($version->children() as $child) {
105
            switch ($child->getName()) {
106
                case 'api':
107
                    $apis[] = $this->buildApi($child);
108
                    break;
109
                case 'guide':
110
                    $guides[] = $this->buildGuide($child);
111
                    break;
112
                default:
113
                    break;
114
            }
115
        }
116
117
        $version = [
118
            'folder' => (string) $version->folder,
119
        ];
120
121
        if (count($apis) > 0) {
122
            $version['api'] = $apis;
123
        }
124
125
        if (count($guides) > 0) {
126
            $version['guide'] = $guides;
127
        }
128
129
        return $version;
130
    }
131
132
    /**
133
     * Builds the api part of the array from the configuration xml.
134
     */
135
    private function buildApi(SimpleXMLElement $api): array
136
    {
137
        $extensions = [];
138
        foreach ($api->extensions->children() as $extension) {
139
            if ((string) $extension !== '') {
140
                $extensions[] = (string) $extension;
141
            }
142
        }
143
144
        $ignoreHidden = filter_var($api->ignore->attributes()->hidden, FILTER_VALIDATE_BOOLEAN);
145
146
        return [
147
            'format' => ((string) $api->attributes()->format) ?: 'php',
148
            'source' => [
149
                'dsn' => ((string) $api->source->attributes()->dsn) ?: 'file://.',
150
                'paths' => ((array) $api->source->path) ?: ['.'],
151
            ],
152
            'ignore' => [
153
                'hidden' => $ignoreHidden,
154
                'paths' => (array) $api->ignore->path,
155
            ],
156
            'extensions' => $extensions,
157
            'visibility' => (array) $api->visibility,
158
            'default-package-name' => ((string) $api->{'default-package-name'}) ?: 'Default',
159
            'markers' => (array) $api->markers->children()->marker,
160
        ];
161
    }
162
163
    /**
164
     * Builds the guide part of the array from the configuration xml.
165
     */
166
    private function buildGuide(SimpleXMLElement $guide): array
167
    {
168
        return [
169
            'format' => ((string) $guide->attributes()->format) ?: 'rst',
170
            'source' => [
171
                'dsn' => ((string) $guide->source->attributes()->dsn) ?: 'file://.',
172
                'paths' => ((array) $guide->source->path) ?: [''],
173
            ],
174
        ];
175
    }
176
177
    /**
178
     * Builds the template part of the array from the configuration xml.
179
     */
180
    private function buildTemplate(SimpleXMLElement $template): array
181
    {
182
        if ((array) $template === []) {
183
            return $this->defaultTemplate();
184
        }
185
186
        $attributes = [];
187
        foreach ($template->attributes() as $attribute) {
188
            $attributes[$attribute->getName()] = (string) $attribute;
189
        }
190
191
        return $attributes;
192
    }
193
194
    /**
195
     * Default versions part if none is found in the configuration.
196
     */
197
    private static function defaultVersions(): array
198
    {
199
        return [
200
            '1.0.0' => [
201
                'folder' => 'latest',
202
                'api' => [
203
                    0 => [
204
                        'format' => 'php',
205
                        'source' => [
206
                            'dsn' => new Dsn('file://.'),
207
                            'paths' => [
208
                                0 => new Path('src'),
209
                            ],
210
                        ],
211
                        'ignore' => [
212
                            'hidden' => true,
213
                            'paths' => [],
214
                        ],
215
                        'extensions' => [
216
                            0 => 'php',
217
                            1 => 'php3',
218
                            2 => 'phtml',
219
                        ],
220
                        'visibility' => ['public'],
221
                        'default-package-name' => 'Default',
222
                        'encoding' => 'utf8',
223
                        'ignore-tags' => [],
224
                        'validate' => false,
225
                        'markers' => [
226
                            0 => 'TODO',
227
                            1 => 'FIXME',
228
                        ],
229
                    ],
230
                ],
231
                'guide' => [
232
                    0 => [
233
                        'format' => 'rst',
234
                        'source' => [
235
                            'dsn' => new Dsn('file://.'),
236
                            'paths' => [
237
                                0 => new Path('docs'),
238
                            ],
239
                        ],
240
                    ],
241
                ],
242
            ],
243
        ];
244
    }
245
246
    /**
247
     * Default template part if none is found in the configuration.
248
     */
249
    private static function defaultTemplate(): array
250
    {
251
        return [
252
            'name' => 'clean',
253
        ];
254
    }
255
256
    /**
257
     * Validates the configuration xml structure against the schema defined in the schemaPath.
258
     *
259
     * @throws InvalidArgumentException if the xml structure is not valid.
260
     */
261
    private function validate(SimpleXMLElement $phpDocumentor): void
262
    {
263
        libxml_clear_errors();
264
        $priorSetting = libxml_use_internal_errors(true);
265
266
        $dom = new \DOMDocument();
267
        $domElement = dom_import_simplexml($phpDocumentor);
268
        $domElement = $dom->importNode($domElement, true);
269
        $dom->appendChild($domElement);
270
271
        $dom->schemaValidate($this->schemaPath);
272
273
        $error = libxml_get_last_error();
274
275
        if ($error !== false) {
276
            throw new InvalidArgumentException(trim($error->message));
277
        }
278
279
        libxml_use_internal_errors($priorSetting);
280
    }
281
}
282