Passed
Push — master ( 1cc59e...6d77e0 )
by Mike
01:59 queued 10s
created

DataProviderGenerator::formatElementName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 6
    public function __construct(
44
        DataProviderParserInterface $parser,
45
        FileWriterInterface $fileWriter,
46
        string $namespace,
47
        string $dataProviderExtends
48
    ) {
49 6
        $this->parser = $parser;
50 6
        $this->fileWriter = $fileWriter;
51 6
        $this->namespace = $namespace;
52 6
        $this->dataProviderExtends = $dataProviderExtends;
53 6
    }
54
55
    /**
56
     * @return array
57
     * @throws \Nette\InvalidArgumentException
58
     */
59 6
    public function generate(): array
60
    {
61 6
        $fileGenerated = [];
62
63 6
        foreach ($this->parser->getDataProvider() as $providerName => $providerElements) {
64 6
            $namespace = new PhpNamespace($this->namespace);
65 6
            $dataProvider = $this->createDataProviderClass($providerName, $providerElements, $namespace);
66 6
            $classContent = (string)$namespace;
67 6
            $classContent = str_replace('\?', '?', $classContent);
68 6
            $classContent = Helpers::tabsToSpaces($classContent, 4);
69 6
            $this->fileWriter->writeToFile($dataProvider->getName() . '.php', $classContent);
70 6
            $fileGenerated[] = $dataProvider->getName() . '.php';
71
        }
72
73 6
        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 6
    private function createNewDataProvider($provider, PhpNamespace $namespace): ClassType
84
    {
85 6
        $dataProvider = $namespace->addClass($provider . 'DataProvider');
86
        $dataProvider
87 6
            ->setFinal()
88 6
            ->setExtends($this->dataProviderExtends)
89 6
            ->setImplements(
90
                [
91 6
                    DataProviderInterface::class
92
                ]
93
            )
94 6
            ->setComment('Auto generated data provider')
95
        ;
96
97 6
        return $dataProvider;
98
    }
99
100
    /**
101
     * @param \Nette\PhpGenerator\ClassType $dataProvider
102
     * @param array $element
103
     */
104 6
    private function addGetter(ClassType $dataProvider, array $element): void
105
    {
106 6
        $dataProvider->addMethod('get' . $this->formatElementName($element['name']))
107 6
                     ->addComment('@return ' . $element['type'])
108 6
                     ->setVisibility('public')
109 6
                     ->setBody('return $this->' . $element['name'] . ';')
110 6
                     ->setReturnType($this->getTypeHint($element['type'], $element['allownull']))
111
        ;
112 6
    }
113
114
    /**
115
     * @param \Nette\PhpGenerator\ClassType $dataProvider
116
     * @param array $element
117
     */
118 6
    private function addUnsetter(ClassType $dataProvider, array $element): void
119
    {
120 6
        $dataProvider->addMethod('unset' . $this->formatElementName($element['name']))
121 6
                     ->addComment('@return ' . $dataProvider->getName())
122 6
                     ->setVisibility('public')
123 6
                     ->setBody('$this->' . $element['name'] . ' = null;' . PHP_EOL . PHP_EOL . 'return $this;')
124
        ;
125 6
    }
126
127
    /**
128
     * @param \Nette\PhpGenerator\ClassType $dataProvider
129
     * @param array $element
130
     */
131 6
    private function addHas(ClassType $dataProvider, array $element): void
132
    {
133 6
        $dataProvider->addMethod('has' . $this->formatElementName($element['name']))
134 6
                     ->addComment('@return bool')
135 6
                     ->setVisibility('public')
136 6
                     ->setBody(
137 6
                         'return ($this->' . $element['name'] . ' !== null && $this->' . $element['name'] . ' !== []);'
138
                     )
139
        ;
140 6
    }
141
142
    /**
143
     * @param \Nette\PhpGenerator\ClassType $dataProvider
144
     * @param array $element
145
     */
146 6
    private function addSetter(ClassType $dataProvider, array $element): void
147
    {
148 6
        $setter = $dataProvider->addMethod('set' . $this->formatElementName($element['name']))
149 6
                               ->addComment(
150 6
                                   '@param ' . $element['type'] . ' $'
151 6
                                   . $element['name']
152
                               )
153 6
                               ->addComment('@return ' . $dataProvider->getName())
154 6
                               ->setVisibility('public')
155 6
                               ->setBody(
156 6
                                   '$this->' . $element['name'] . ' = $' . $element['name'] . ';' . PHP_EOL . PHP_EOL
157 6
                                   . 'return $this;'
158
                               )
159
        ;
160
161 6
        $param = $setter->addParameter($element['name'])
162 6
                        ->setTypeHint($this->getTypeHint($element['type'], $element['allownull']))
163
        ;
164 6
        if ($element['default']) {
165 6
            $default = $this->getDefaultValue($element);
166 6
            $param->setDefaultValue($default);
167
        }
168 6
        elseif ($element['allownull']) {
169 6
            $param->setDefaultValue(null);
170
        }
171 6
    }
172
173
    /**
174
     * @param array $element
175
     * @param \Nette\PhpGenerator\ClassType $dataProvider
176
     */
177 6
    private function addSingleSetter(array $element, ClassType $dataProvider): void
178
    {
179 6
        if (isset($element['singleton']) && $element['singleton'] !== '') {
180
            $singleSetter = $dataProvider
181 6
                ->addMethod('add' . $element['singleton'])
182 6
                ->addComment(
183 6
                    '@param ' . $element['singleton_type'] . ' $'
184 6
                    . $element['singleton']
185
                )
186 6
                ->addComment('@return ' . $dataProvider->getName())
187 6
                ->setVisibility('public')
188 6
                ->setBody(
189 6
                    sprintf(
190 6
                        '$this->%s[] = $%s; return $this;',
191 6
                        $element['name'],
192 6
                        $element['singleton']
193
                    )
194
                )
195
            ;
196
197 6
            $singleSetter->addParameter($element['singleton'])
198 6
                         ->setTypeHint($element['singleton_type'])
199
            ;
200
        }
201 6
    }
202
203
    /**
204
     * @param \Nette\PhpGenerator\ClassType $dataProvider
205
     * @param array $element
206
     */
207 6
    private function addProperty(ClassType $dataProvider, array $element): void
208
    {
209 6
        $property = $dataProvider->addProperty($element['name'])
210 6
                                 ->setVisibility('protected')
211 6
                                 ->addComment('@var ' . $element['type'])
212
        ;
213
214 6
        if ($element['default']) {
215 6
            $default = $this->getDefaultValue($element);
216 6
            $property->setValue($default);
217
        }
218 6
        elseif (strpos($element['type'], '[]') !== false) {
219 6
            $property->setValue([]);
220
        }
221 6
    }
222
223
    /**
224
     * @param string $type
225
     * @param bool $allowNull
226
     *
227
     * @return string
228
     */
229 6
    private function getTypeHint(string $type, bool $allowNull = null): string
230
    {
231 6
        if (strpos($type, '[]') !== false) {
232 6
            $type = 'array';
233
        }
234
235 6
        if ($allowNull === true) {
236 6
            $type = '?' . $type;
237
        }
238
239 6
        return $type;
240
    }
241
242
    /**
243
     * @param \Nette\PhpGenerator\ClassType $dataProvider
244
     * @param array $elements
245
     */
246 6
    private function addElementsGetter(ClassType $dataProvider, array $elements): void
247
    {
248 6
        $dataProvider->addMethod('getElements')
249 6
                     ->setReturnType('array')
250 6
                     ->setVisibility('protected')
251 6
                     ->addComment('@return array')
252 6
                     ->setBody('return ' . var_export($elements, true) . ';')
253
        ;
254 6
    }
255
256
    /**
257
     * @param string $providerName
258
     * @param array $providerElements
259
     * @param \Nette\PhpGenerator\PhpNamespace $namespace
260
     *
261
     * @return \Nette\PhpGenerator\ClassType
262
     */
263 6
    private function createDataProviderClass(
264
        string $providerName,
265
        array $providerElements,
266
        PhpNamespace $namespace
267
    ): ClassType {
268 6
        $dataProvider = $this->createNewDataProvider($providerName, $namespace);
269
270 6
        foreach ($providerElements as $element) {
271 6
            $this->addProperty($dataProvider, $element);
272 6
            $this->addGetter($dataProvider, $element);
273 6
            $this->addSetter($dataProvider, $element);
274 6
            $this->addUnsetter($dataProvider, $element);
275 6
            $this->addHas($dataProvider, $element);
276 6
            $this->addSingleSetter($element, $dataProvider);
277
278
        }
279
280 6
        $this->addElementsGetter($dataProvider, $providerElements);
281 6
        return $dataProvider;
282
    }
283
284
    /**
285
     * @param array $element
286
     *
287
     * @return bool
288
     */
289 6
    private function getDefaultValue($element)
290
    {
291 6
        $default = $element['default'];
292
293 6
        switch ($element['type']) {
294 6
            case 'bool':
295 6
            case 'boolean':
296
                {
297 6
                    $default = $default === 'false' ? false : $default;
298 6
                    $default = $default === 'true' ? true : $default;
299
                }
300 6
                break;
301
302 6
            case 'array':
303
                {
304 6
                    $default = [];
305
                }
306 6
                break;
307
308 6
            case 'string':
309
                {
310 6
                    $default = $default === '\'\'' ? '' : $default;
311
                }
312 6
                break;
313
        }
314
315 6
        settype($default, $element['type']);
316 6
        return $default;
317
    }
318
319
    /**
320
     * @param string $elementName
321
     * @return string
322
     */
323 6
    private function formatElementName(string $elementName) : string
324
    {
325 6
        return strtoupper($elementName[0]) . substr($elementName, 1);
326
    }
327
}