Completed
Branch master (3b8125)
by
unknown
01:25
created

StructureResolver::getNewPropertyPosition()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
cc 4
nc 4
nop 1
1
<?php
2
3
namespace HelloWordPl\SimpleEntityGeneratorBundle\Lib;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Exception;
7
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Exceptions\StructureResolverException;
8
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Interfaces\DumpableInterface;
9
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Interfaces\MethodInterface;
10
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Interfaces\StructureWithMethodsInterface;
11
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Items\ClassConstructorManager;
12
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Items\ClassManager;
13
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Items\InterfaceManager;
14
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Items\TestClassManager;
15
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Renderer;
16
use HelloWordPl\SimpleEntityGeneratorBundle\Lib\Tools;
17
use ReflectionClass;
18
use UnrecognizedItemToDumpException;
19
use ReflectionMethod;
20
21
/**
22
 * Resolve Classes content elements
23
 *
24
 * @author Sławomir Kania <[email protected]>
25
 */
26
class StructureResolver
27
{
28
    /**
29
     * @var Renderer
30
     */
31
    private $renderer;
32
33
    /**
34
     * CONSTR
35
     *
36
     * @param Renderer $renderer
37
     */
38
    public function __construct(Renderer $renderer)
39
    {
40
        $this->renderer = $renderer;
41
    }
42
43
    /**
44
     * @param string $content
45
     * @param DumpableInterface $item
46
     * @param ReflectionClass $reflectionClass
47
     * @return string
48
     * @throws UnrecognizedItemToDumpException
49
     */
50
    public function getUpdatedItemSourceContent($content, DumpableInterface $item, ReflectionClass $reflectionClass)
51
    {
52
        switch (true) {
53
            case $item instanceof ClassManager:
54
                return $this->getUpdatedClassContent($content, $item, $reflectionClass);
55
            case $item instanceof InterfaceManager:
56
                return $this->getUpdatedInterfaceContent($content, $item, $reflectionClass);
57
            case $item instanceof TestClassManager:
58
                return $this->getUpdatedTestClassContent($content, $item, $reflectionClass);
59
            default:
60
                throw $this->getExceptionUnrecognizedItem($item);
61
        }
62
    }
63
64
    /**
65
     * @param string $content
66
     * @param TestClassManager $item
67
     * @param ReflectionClass $reflectionClass
68
     * @return string
69
     */
70
    protected function getUpdatedTestClassContent($content, TestClassManager $item, ReflectionClass $reflectionClass)
71
    {
72
        $item->setMethods($this->resolveMethodsToRender($item, $reflectionClass));
73
        return $this->getRenderer()->renderAndPutItemsToContent($content, $item->getMethods(), $this->getNewMethodPostion($reflectionClass));
74
    }
75
76
    /**
77
     * @param string $content
78
     * @param ClassManager $item
79
     * @param ReflectionClass $reflectionClass
80
     * @return string
81
     */
82
    protected function getUpdatedClassContent($content, ClassManager $item, ReflectionClass $reflectionClass)
83
    {
84
        $this->resolveClassContent($content, $item, $reflectionClass);
85
        $updatedContent = $this->getRenderer()->renderAndPutItemsToContent($content, $item->getMethods(), $this->getNewMethodPostion($reflectionClass));
86
        $updatedContent = $this->getRenderer()->renderAndPutConstructorBodyToContent($updatedContent, $item->getConstructor(), $this->getNewInitPropertyPosition($reflectionClass));
87
        $updatedContent = $this->getRenderer()->renderAndPutItemsToContent($updatedContent, $item->getProperties(), $this->getNewPropertyPosition($reflectionClass));
88
        return $updatedContent;
89
    }
90
91
    /**
92
     * @param string $content
93
     * @param InterfaceManager $item
94
     * @param ReflectionClass $reflectionClass
95
     * @return string
96
     */
97
    protected function getUpdatedInterfaceContent($content, InterfaceManager $item, ReflectionClass $reflectionClass)
98
    {
99
        $this->resolveInterfaceContent($item, $reflectionClass);
100
        $updatedContent = $this->getRenderer()->renderAndPutItemsToContent($content, $item->getMethods(), $this->getNewMethodPostion($reflectionClass));
101
        return $updatedContent;
102
    }
103
104
    /**
105
     * @param string $content
106
     * @param ClassManager $item
107
     * @param ReflectionClass $reflectionClass
108
     * @return ClassManager
109
     */
110
    protected function resolveClassContent($content, ClassManager $item, ReflectionClass $reflectionClass)
111
    {
112
        $item->setConstructor($this->resolveConstructorToRender($content, $item, $reflectionClass));
113
        $item->setProperties($this->resolvePropertiesToRender($item, $reflectionClass));
114
        $item->setMethods($this->resolveMethodsToRender($item, $reflectionClass));
115
        return $item;
116
    }
117
118
    /**
119
     * @param InterfaceManager $item
120
     * @param ReflectionClass $reflectionClass
121
     * @return InterfaceManager
122
     */
123
    protected function resolveInterfaceContent(InterfaceManager $item, ReflectionClass $reflectionClass)
124
    {
125
        $item->setMethods($this->resolveMethodsToRender($item, $reflectionClass));
126
        return $item;
127
    }
128
129
    /**
130
     * Get properties to render in item file
131
     *
132
     * @param ClassManager $item
133
     * @param ReflectionClass $reflectionClass
134
     * @return ArrayCollection
135
     */
136
    protected function resolvePropertiesToRender(ClassManager $item, ReflectionClass $reflectionClass)
137
    {
138
        $propertiesToRender = new ArrayCollection();
139
        foreach ($item->getProperties() as $itemProperty) {
140
            $found = false;
141
            foreach ($reflectionClass->getProperties() as $reflectionProperty) {
142
                if ($itemProperty->getPreparedName() == $reflectionProperty->name) {
143
                    $found = true;
144
                    break;
145
                }
146
            }
147
            if (false === $found) {
148
                $propertiesToRender->add($itemProperty);
149
            }
150
        }
151
152
        return $propertiesToRender;
153
    }
154
155
    /**
156
     * Get methods to render in item file
157
     *
158
     * @param StructureWithMethodsInterface $item
159
     * @param ReflectionClass $reflectionClass
160
     * @return ArrayCollection
161
     * @throws Exception
162
     */
163
    protected function resolveMethodsToRender(StructureWithMethodsInterface $item, ReflectionClass $reflectionClass)
164
    {
165
        $methodsToRender = new ArrayCollection();
166
        foreach ($item->getMethods() as $itemMethod) {
167
            if (false === ($itemMethod instanceof MethodInterface)) {
168
                throw new StructureResolverException(sprintf("Item %s does not implement Method Interface", get_class($itemMethod)));
169
            }
170
171
            $found = false;
172
            foreach ($reflectionClass->getMethods() as $reflectionMethod) {
173
                if ($itemMethod->getPreparedName() == $reflectionMethod->name) {
174
                    $found = true;
175
                    break;
176
                }
177
            }
178
            if (false === $found) {
179
                $methodsToRender->add($itemMethod);
180
            }
181
        }
182
183
        return $methodsToRender;
184
    }
185
186
    /**
187
     * @param string $content
188
     * @param ClassManager $item
189
     * @param ReflectionClass $reflectionClass
190
     * @return ClassConstructorManager
191
     */
192
    protected function resolveConstructorToRender($content, ClassManager $item, ReflectionClass $reflectionClass)
193
    {
194
        $constructor = $item->getConstructor();
195
        $constructorFromFile = $reflectionClass->getConstructor();
196
        $source = Tools::explodeTemplateStringToArray($content);
197
198
        $constructorBody = implode("", array_slice($source, $constructorFromFile->getStartLine(), $constructorFromFile->getEndLine() - $constructorFromFile->getStartLine()));
199
200
        $matches = [];
201
        preg_match_all("/this->[\S]+/", $constructorBody, $matches);
202
203
        $initPropertiesFromConstructor = [];
204
        if (count($matches) > 0) {
205
            foreach ($matches[0] as $match) {
206
                $initPropertiesFromConstructor[] = str_replace("this->", "", trim($match));
207
            }
208
        }
209
210
        $newInitProperties = new ArrayCollection();
211
        foreach ($constructor->getInitProperties() as $initProperty) {
212
            if (in_array($initProperty->getProperty()->getPreparedName(), $initPropertiesFromConstructor)) {
213
                continue;
214
            }
215
216
            $newInitProperties->add($initProperty);
217
        }
218
219
        $constructor->setInitProperties($newInitProperties);
220
        $item->setConstructor($constructor);
221
222
        return $constructor;
223
    }
224
225
    /**
226
     * @param ReflectionClass $reflectionClass
227
     * @return integer
228
     */
229
    protected function getNewMethodPostion(ReflectionClass $reflectionClass)
230
    {
231
        return $reflectionClass->getEndLine() - 1;
232
    }
233
234
    /**
235
     * @param ReflectionClass $reflectionClass
236
     * @return type
237
     */
238
    protected function getNewInitPropertyPosition(ReflectionClass $reflectionClass)
239
    {
240
        $constructor = $reflectionClass->getConstructor();
241
242
        if ($constructor instanceof ReflectionMethod) {
243
            return $constructor->getEndLine() - 1;
244
        }
245
246
        return $reflectionClass->getEndLine() - 1;
247
    }
248
249
    /**
250
     * @param ReflectionClass $reflectionClass
251
     * @return type
252
     */
253
    protected function getNewPropertyPosition(ReflectionClass $reflectionClass)
254
    {
255
        $constructor = $reflectionClass->getConstructor();
256
        if ($constructor instanceof ReflectionMethod) {
257
            $commentParts = Tools::explodeTemplateStringToArray($constructor->getDocComment());
258
            return ($constructor->getStartLine() - count($commentParts)) - 1;
259
        }
260
261
        $methods = $reflectionClass->getMethods();
262
263
        if (count($methods) > 0) {
264
            $firstMethod = reset($methods);
265
            if ($firstMethod instanceof ReflectionMethod) {
266
                return $firstMethod->getStartLine() - 1;
267
            }
268
        }
269
270
        return $reflectionClass->getEndLine() - 1;
271
    }
272
273
    /**
274
     * @return Renderer
275
     */
276
    protected function getRenderer()
277
    {
278
        return $this->renderer;
279
    }
280
281
    /**
282
     * @param mixed $item
283
     * @return UnrecognizedItemToDumpException
284
     */
285
    protected function getExceptionUnrecognizedItem($item)
286
    {
287
        return new UnrecognizedItemToDumpException(sprintf("Unrecognized item class: %s", get_class($item)));
288
    }
289
}
290