DataProviderGenerator   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 344
Duplicated Lines 0 %

Test Coverage

Coverage 99.31%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 128
c 2
b 0
f 0
dl 0
loc 344
ccs 143
cts 144
cp 0.9931
rs 9.68
wmc 34

15 Methods

Rating   Name   Duplication   Size   Complexity  
A generate() 0 15 2
A __construct() 0 10 1
A getTypeHint() 0 11 3
A convertUnderlines() 0 8 1
A addUnsetter() 0 6 1
A addGetter() 0 7 1
A createDataProviderClass() 0 20 2
A addSingleSetter() 0 26 4
A addProperty() 0 13 3
A addHas() 0 7 1
A formatElementName() 0 9 2
A createNewDataProvider() 0 15 1
B getDefaultValue() 0 28 8
A addElementsGetter() 0 7 1
A addSetter() 0 24 3
1
<?php
2
declare(strict_types=1);
3
4
5
namespace Xervice\DataProvider\Business\Model\Generator;
6
7
8
use Nette\PhpGenerator\ClassType;
9
use Nette\PhpGenerator\Helpers;
10
use Nette\PhpGenerator\PhpNamespace;
11
use Xervice\DataProvider\Business\Model\DataProvider\DataProviderInterface;
12
use Xervice\DataProvider\Business\Model\Parser\DataProviderParserInterface;
13
14
class DataProviderGenerator implements DataProviderGeneratorInterface
15
{
16
    /**
17
     * @var \Xervice\DataProvider\Business\Model\Parser\DataProviderParserInterface
18
     */
19
    private $parser;
20
21
    /**
22
     * @var FileWriterInterface
23
     */
24
    private $fileWriter;
25
26
    /**
27
     * @var string
28
     */
29
    private $namespace;
30
31
    /**
32
     * @var string
33
     */
34
    private $dataProviderExtends;
35
36
    /**
37
     * DataProviderGenerator constructor.
38
     *
39
     * @param \Xervice\DataProvider\Business\Model\Parser\DataProviderParserInterface $parser
40
     * @param FileWriterInterface $fileWriter
41
     * @param string $namespace
42
     */
43 10
    public function __construct(
44
        DataProviderParserInterface $parser,
45
        FileWriterInterface $fileWriter,
46
        string $namespace,
47
        string $dataProviderExtends
48
    ) {
49 10
        $this->parser = $parser;
50 10
        $this->fileWriter = $fileWriter;
51 10
        $this->namespace = $namespace;
52 10
        $this->dataProviderExtends = $dataProviderExtends;
53 10
    }
54
55
    /**
56
     * @return array
57
     * @throws \Nette\InvalidArgumentException
58
     */
59 10
    public function generate(): array
60
    {
61 10
        $fileGenerated = [];
62
63 10
        foreach ($this->parser->getDataProvider() as $providerName => $providerData) {
64 10
            $namespace = new PhpNamespace($this->namespace);
65 10
            $dataProvider = $this->createDataProviderClass($providerName, $providerData, $namespace);
66 10
            $classContent = (string)$namespace;
67 10
            $classContent = str_replace('\?', '?', $classContent);
68 10
            $classContent = Helpers::tabsToSpaces($classContent, 4);
69 10
            $this->fileWriter->writeToFile($dataProvider->getName() . '.php', $classContent);
70 10
            $fileGenerated[] = $dataProvider->getName() . '.php';
71
        }
72
73 10
        return $fileGenerated;
74
    }
75
76
    /**
77
     * @param string $provider
78
     * @param \Nette\PhpGenerator\PhpNamespace $namespace
79
     *
80
     * @return ClassType
81
     * @throws \Nette\InvalidArgumentException
82
     */
83 10
    private function createNewDataProvider($provider, PhpNamespace $namespace): ClassType
84
    {
85 10
        $dataProvider = $namespace->addClass($provider . 'DataProvider');
86
        $dataProvider
87 10
            ->setFinal()
88 10
            ->setExtends($this->dataProviderExtends)
89 10
            ->setImplements(
90
                [
91 10
                    DataProviderInterface::class
92
                ]
93
            )
94 10
            ->setComment('Auto generated data provider')
95
        ;
96
97 10
        return $dataProvider;
98
    }
99
100
    /**
101
     * @param \Nette\PhpGenerator\ClassType $dataProvider
102
     * @param array $element
103
     * @param array $configs
104
     */
105 10
    private function addGetter(ClassType $dataProvider, array $element, array $configs): void
106
    {
107 10
        $dataProvider->addMethod('get' . $this->formatElementName($element['name'], $configs))
108 10
                     ->addComment('@return ' . $element['type'])
109 10
                     ->setVisibility('public')
110 10
                     ->setBody('return $this->' . $element['name'] . ';')
111 10
                     ->setReturnType($this->getTypeHint($element['type'], $element['allownull']))
112
        ;
113 10
    }
114
115
    /**
116
     * @param \Nette\PhpGenerator\ClassType $dataProvider
117
     * @param array $element
118
     * @param array $configs
119
     */
120 10
    private function addUnsetter(ClassType $dataProvider, array $element, array $configs): void
121
    {
122 10
        $dataProvider->addMethod('unset' . $this->formatElementName($element['name'], $configs))
123 10
                     ->addComment('@return ' . $dataProvider->getName())
124 10
                     ->setVisibility('public')
125 10
                     ->setBody('$this->' . $element['name'] . ' = null;' . PHP_EOL . PHP_EOL . 'return $this;')
126
        ;
127 10
    }
128
129
    /**
130
     * @param \Nette\PhpGenerator\ClassType $dataProvider
131
     * @param array $element
132
     * @param array $configs
133
     */
134 10
    private function addHas(ClassType $dataProvider, array $element, array $configs): void
135
    {
136 10
        $dataProvider->addMethod('has' . $this->formatElementName($element['name'], $configs))
137 10
                     ->addComment('@return bool')
138 10
                     ->setVisibility('public')
139 10
                     ->setBody(
140 10
                         'return ($this->' . $element['name'] . ' !== null && $this->' . $element['name'] . ' !== []);'
141
                     )
142
        ;
143 10
    }
144
145
    /**
146
     * @param \Nette\PhpGenerator\ClassType $dataProvider
147
     * @param array $element
148
     * @param array $configs
149
     */
150 10
    private function addSetter(ClassType $dataProvider, array $element, array $configs): void
151
    {
152 10
        $setter = $dataProvider->addMethod('set' . $this->formatElementName($element['name'], $configs))
153 10
                               ->addComment(
154 10
                                   '@param ' . $element['type'] . ' $'
155 10
                                   . $element['name']
156
                               )
157 10
                               ->addComment('@return ' . $dataProvider->getName())
158 10
                               ->setVisibility('public')
159 10
                               ->setBody(
160 10
                                   '$this->' . $element['name'] . ' = $' . $element['name'] . ';' . PHP_EOL . PHP_EOL
161 10
                                   . 'return $this;'
162
                               )
163
        ;
164
165 10
        $param = $setter->addParameter($element['name'])
0 ignored issues
show
Deprecated Code introduced by
The function Nette\PhpGenerator\Parameter::setTypeHint() has been deprecated: use setType() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

165
        $param = /** @scrutinizer ignore-deprecated */ $setter->addParameter($element['name'])

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
166 10
                        ->setTypeHint($this->getTypeHint($element['type'], $element['allownull']))
167
        ;
168 10
        if ($element['default']) {
169 10
            $default = $this->getDefaultValue($element);
170 10
            $param->setDefaultValue($default);
171
        }
172 10
        elseif ($element['allownull']) {
173 10
            $param->setDefaultValue(null);
174
        }
175 10
    }
176
177
    /**
178
     * @param array $element
179
     * @param \Nette\PhpGenerator\ClassType $dataProvider
180
     * @param array $configs
181
     */
182 10
    private function addSingleSetter(array $element, ClassType $dataProvider, array $configs): void
183
    {
184 10
        if (isset($element['singleton']) && $element['singleton'] !== '') {
185 10
            $methodName = $configs['convertUnderlines']
186
                ? $this->convertUnderlines($element['singleton'])
187 10
                : $element['singleton'];
188
189
            $singleSetter = $dataProvider
190 10
                ->addMethod('add' . $methodName)
191 10
                ->addComment(
192 10
                    '@param ' . $element['singleton_type'] . ' $'
193 10
                    . $element['singleton']
194
                )
195 10
                ->addComment('@return ' . $dataProvider->getName())
196 10
                ->setVisibility('public')
197 10
                ->setBody(
198 10
                    sprintf(
199 10
                        '$this->%s[] = $%s; return $this;',
200 10
                        $element['name'],
201 10
                        $element['singleton']
202
                    )
203
                )
204
            ;
205
206 10
            $singleSetter->addParameter($element['singleton'])
0 ignored issues
show
Deprecated Code introduced by
The function Nette\PhpGenerator\Parameter::setTypeHint() has been deprecated: use setType() ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

206
            /** @scrutinizer ignore-deprecated */ $singleSetter->addParameter($element['singleton'])

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
207 10
                         ->setTypeHint($element['singleton_type'])
208
            ;
209
        }
210 10
    }
211
212
    /**
213
     * @param \Nette\PhpGenerator\ClassType $dataProvider
214
     * @param array $element
215
     */
216 10
    private function addProperty(ClassType $dataProvider, array $element): void
217
    {
218 10
        $property = $dataProvider->addProperty($element['name'])
219 10
                                 ->setVisibility('protected')
220 10
                                 ->addComment('@var ' . $element['type'])
221
        ;
222
223 10
        if ($element['default']) {
224 10
            $default = $this->getDefaultValue($element);
225 10
            $property->setValue($default);
226
        }
227 10
        elseif (strpos($element['type'], '[]') !== false) {
228 10
            $property->setValue([]);
229
        }
230 10
    }
231
232
    /**
233
     * @param string $type
234
     * @param bool $allowNull
235
     *
236
     * @return string
237
     */
238 10
    private function getTypeHint(string $type, bool $allowNull = null): string
239
    {
240 10
        if (strpos($type, '[]') !== false) {
241 10
            $type = 'array';
242
        }
243
244 10
        if ($allowNull === true) {
245 10
            $type = '?' . $type;
246
        }
247
248 10
        return $type;
249
    }
250
251
    /**
252
     * @param \Nette\PhpGenerator\ClassType $dataProvider
253
     * @param array $elements
254
     */
255 10
    private function addElementsGetter(ClassType $dataProvider, array $elements): void
256
    {
257 10
        $dataProvider->addMethod('getElements')
258 10
                     ->setReturnType('array')
259 10
                     ->setVisibility('protected')
260 10
                     ->addComment('@return array')
261 10
                     ->setBody('return ' . var_export($elements, true) . ';')
262
        ;
263 10
    }
264
265
    /**
266
     * @param string $providerName
267
     * @param array $providerData
268
     * @param \Nette\PhpGenerator\PhpNamespace $namespace
269
     *
270
     * @return \Nette\PhpGenerator\ClassType
271
     */
272 10
    private function createDataProviderClass(
273
        string $providerName,
274
        array $providerData,
275
        PhpNamespace $namespace
276
    ): ClassType {
277 10
        $dataProvider = $this->createNewDataProvider($providerName, $namespace);
278 10
        $providerElements = $providerData['elements'];
279
280 10
        foreach ($providerElements as $element) {
281 10
            $this->addProperty($dataProvider, $element);
282 10
            $this->addGetter($dataProvider, $element, $providerData['configs']);
283 10
            $this->addSetter($dataProvider, $element, $providerData['configs']);
284 10
            $this->addUnsetter($dataProvider, $element, $providerData['configs']);
285 10
            $this->addHas($dataProvider, $element, $providerData['configs']);
286 10
            $this->addSingleSetter($element, $dataProvider, $providerData['configs']);
287
288
        }
289
290 10
        $this->addElementsGetter($dataProvider, $providerElements);
291 10
        return $dataProvider;
292
    }
293
294
    /**
295
     * @param array $element
296
     *
297
     * @return bool
298
     */
299 10
    private function getDefaultValue($element)
300
    {
301 10
        $default = $element['default'];
302
303 10
        switch ($element['type']) {
304 10
            case 'bool':
305 10
            case 'boolean':
306
                {
307 10
                    $default = $default === 'false' ? false : $default;
308 10
                    $default = $default === 'true' ? true : $default;
309
                }
310 10
                break;
311
312 10
            case 'array':
313
                {
314 10
                    $default = [];
315
                }
316 10
                break;
317
318 10
            case 'string':
319
                {
320 10
                    $default = $default === '\'\'' ? '' : $default;
321
                }
322 10
                break;
323
        }
324
325 10
        settype($default, $element['type']);
326 10
        return $default;
327
    }
328
329
    /**
330
     * @param string $elementName
331
     *
332
     * @return string
333
     */
334 10
    private function formatElementName(string $elementName, array $configs): string
335
    {
336 10
        $elementName = ucfirst($elementName);
337
338 10
        if ($configs['convertUnderlines']) {
339 10
            $elementName = $this->convertUnderlines($elementName);
340
        }
341
342 10
        return $elementName;
343
    }
344
345
    /**
346
     * @param string $methodName
347
     *
348
     * @return string
349
     */
350 10
    private function convertUnderlines(string $methodName): string
351
    {
352 10
        return preg_replace_callback(
353 10
            '@\_([a-z]{1,1})@',
354
            function ($matches) {
355 10
                return strtoupper($matches[1] ?? '');
356 10
            },
357 10
            $methodName
358
        );
359
    }
360
}
361