Passed
Push — develop ( b778ba...260b0a )
by Mikaël
07:57
created

AbstractElement::getCalledClass()   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 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace WsdlToPhp\PhpGenerator\Element;
6
7
use InvalidArgumentException;
8
9
abstract class AbstractElement implements GenerateableInterface
10
{
11
    protected string $name;
12
13
    /**
14
     * @var AbstractElement[]|mixed[]
15
     */
16
    protected array $children;
17
18
    protected int $indentation;
19
20 338
    public function __construct(string $name)
21
    {
22 338
        $this->setName($name);
23 336
        $this->children = [];
24 336
        $this->indentation = 0;
25 336
    }
26
27
    public function __toString(): string
28
    {
29
        return $this->toString();
30
    }
31
32 338
    public function setName(string $name): self
33
    {
34 338
        if (!static::nameIsValid($name)) {
35 2
            throw new InvalidArgumentException(sprintf('Name "%s" is invalid when instantiating %s object', $name, $this->getCalledClass()));
36
        }
37 336
        $this->name = $name;
38
39 336
        return $this;
40
    }
41
42 240
    public function getName(): string
43
    {
44 240
        return $this->name;
45
    }
46
47 344
    public static function nameIsValid(string $name, bool $allowBackslash = false): bool
48
    {
49 344
        $pattern = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/';
50 344
        if (true === $allowBackslash) {
51 54
            $pattern = '/[a-zA-Z_\x7f-\xff\\\][a-zA-Z0-9_\x7f-\xff\\\]*/';
52
        }
53
54 344
        return 1 === preg_match($pattern, (string) $name);
55
    }
56
57 140
    public static function stringIsValid($string, bool $checkName = true, bool $allowBackslash = false): bool
58
    {
59 140
        return is_string($string) && !empty($string) && (!$checkName || static::nameIsValid($string, $allowBackslash));
60
    }
61
62 110
    public static function objectIsValid($object, ?string $checkClass = null): bool
63
    {
64 110
        return is_object($object) && (null === $checkClass || get_class($object) === $checkClass);
65
    }
66
67 100
    public function toString(?int $indentation = null): string
68
    {
69 50
        $lines = [
70 100
            $this->getToStringDeclaration($indentation),
71 100
            $this->getToStringBeforeChildren($indentation),
72
        ];
73 100
        foreach ($this->getChildren() as $child) {
74 64
            if (empty($childContent = $this->getChildContent($child, $indentation + ($this->useBracketsForChildren() ? 1 : 0)))) {
75 4
                continue;
76
            }
77 64
            $lines[] = $childContent;
78
        }
79 100
        $lines[] = $this->getToStringAfterChildren($indentation);
80
81 100
        return implode(self::BREAK_LINE_CHAR, self::cleanArrayToString($lines));
82
    }
83
84 212
    public function getPhpName(): string
85
    {
86 212
        return sprintf('%s', $this->getName());
87
    }
88
89 104
    public function addChild($child): self
90
    {
91 104
        if (!$this->childIsValid($child)) {
92 22
            $types = $this->getChildrenTypes();
93 22
            if (empty($types)) {
94 8
                throw new InvalidArgumentException('This element does not accept any child element');
95
            }
96
97 14
            throw new InvalidArgumentException(sprintf('Element of type "%s:%s" is not authorized, please provide one of these types: %s', gettype($child), is_object($child) ? get_class($child) : 'unknown', implode(', ', $this->getChildrenTypes())));
98
        }
99 82
        $this->children[] = $child;
100
101 82
        return $this;
102
    }
103
104
    /**
105
     * @return AbstractElement[]|mixed[]
106
     */
107 140
    public function getChildren(): array
108
    {
109 140
        return $this->children;
110
    }
111
112
    abstract public function getPhpDeclaration(): string;
113
114
    /**
115
     * defines authorized children element types.
116
     *
117
     * @return string[]
118
     */
119
    abstract public function getChildrenTypes(): array;
120
121
    /**
122
     * Allows to generate content before children content is generated.
123
     */
124 78
    public function getLineBeforeChildren(?int $indentation = null): string
125
    {
126 78
        return '';
127
    }
128
129
    /**
130
     * Allows to generate content after children content is generated.
131
     */
132 82
    public function getLineAfterChildren(?int $indentation = null): string
133
    {
134 82
        return '';
135
    }
136
137
    /**
138
     * Allows to indicate that children are contained by brackets,
139
     * in the case the method returns true, getBracketBeforeChildren
140
     * is called instead of getLineBeforeChildren and getBracketAfterChildren
141
     * is called instead of getLineAfterChildren, but be aware that these methods
142
     * call the two others.
143
     */
144 80
    public function useBracketsForChildren(): bool
145
    {
146 80
        return false;
147
    }
148
149
    /**
150
     * Allows to generate content before children content is generated.
151
     */
152 52
    public function getBracketBeforeChildren(?int $indentation = null): string
153
    {
154 52
        $line = $this->getIndentedString(self::OPEN_BRACKET, $indentation);
155 52
        $this->setIndentation((null === $indentation ? $this->getIndentation() : $indentation) + 1);
156
157 52
        return $line;
158
    }
159
160
    /**
161
     * Allows to generate content after children content is generated.
162
     */
163 52
    public function getBracketAfterChildren(?int $indentation = null): string
164
    {
165 52
        $this->setIndentation((null === $indentation ? $this->getIndentation() : $indentation) - 1);
166
167 52
        return $this->getIndentedString(self::CLOSE_BRACKET, $indentation);
168
    }
169
170 52
    public function setIndentation(int $indentation): self
171
    {
172 52
        $this->indentation = $indentation;
173
174 52
        return $this;
175
    }
176
177 98
    public function getIndentation(): int
178
    {
179 98
        return $this->indentation;
180
    }
181
182 98
    public function getIndentationString(?int $indentation = null): string
183
    {
184 98
        return str_repeat(self::INDENTATION_CHAR, null === $indentation ? $this->getIndentation() : $indentation);
185
    }
186
187 98
    public function getIndentedString(string $string, ?int $indentation = null): string
188
    {
189 98
        $strings = explode(self::BREAK_LINE_CHAR, $string);
190 98
        foreach ($strings as $i => $s) {
191 98
            $strings[$i] = sprintf('%s%s', $this->getIndentationString($indentation), $s);
192
        }
193
194 98
        return implode(self::BREAK_LINE_CHAR, $strings);
195
    }
196
197 6
    final public function getCalledClass(): string
198
    {
199 6
        return substr(get_called_class(), strrpos(get_called_class(), '\\') + 1);
200
    }
201
202 64
    protected function getChildContent($child, int $indentation = null): string
203
    {
204 64
        $content = '';
205 64
        if (is_string($child)) {
206 14
            $content = $this->getIndentedString($child, $indentation);
207 64
        } elseif ($child instanceof AbstractElement) {
208 64
            $content = $child->toString(null === $indentation ? $this->getIndentation() : $indentation);
209
        }
210
211 64
        return $content;
212
    }
213
214 118
    protected function childIsValid($child): bool
215
    {
216 118
        $valid = false;
217 118
        $authorizedTypes = $this->getChildrenTypes();
218 118
        if (!empty($authorizedTypes)) {
219 110
            foreach ($authorizedTypes as $authorizedType) {
220 110
                $valid |= (gettype($child) === $authorizedType) || static::objectIsValid($child, $authorizedType);
221
            }
222
        }
223
224 118
        return (bool) $valid;
225
    }
226
227 100
    private function getToStringDeclaration(int $indentation = null): ?string
228
    {
229 100
        $declaration = $this->getPhpDeclaration();
230 100
        if (!empty($declaration)) {
231 98
            return $this->getIndentedString($declaration, $indentation);
232
        }
233
234 36
        return null;
235
    }
236
237 100
    private function getToStringBeforeChildren(int $indentation = null): ?string
238
    {
239 100
        $before = $this->getContextualLineBeforeChildren($indentation);
240 100
        if (!empty($before)) {
241 68
            return $before;
242
        }
243
244 82
        return null;
245
    }
246
247 100
    private function getToStringAfterChildren(int $indentation = null): ?string
248
    {
249 100
        $after = $this->getContextualLineAfterChildren($indentation);
250 100
        if (!empty($after)) {
251 68
            return $after;
252
        }
253
254 82
        return null;
255
    }
256
257 100
    private static function cleanArrayToString(array $array): array
258
    {
259 100
        $newArray = [];
260 100
        foreach ($array as $line) {
261 100
            if (null !== $line) {
262 98
                $newArray[] = $line;
263
            }
264
        }
265
266 100
        return $newArray;
267
    }
268
269 100
    private function getContextualLineBeforeChildren(int $indentation = null): string
270
    {
271 100
        if ($this->useBracketsForChildren()) {
272 52
            $line = $this->getBracketBeforeChildren($indentation);
273
        } else {
274 82
            $line = $this->getLineBeforeChildren($indentation);
275
        }
276
277 100
        return $line;
278
    }
279
280 100
    private function getContextualLineAfterChildren(int $indentation = null): string
281
    {
282 100
        if ($this->useBracketsForChildren()) {
283 52
            $line = $this->getBracketAfterChildren($indentation);
284
        } else {
285 82
            $line = $this->getLineAfterChildren($indentation);
286
        }
287
288 100
        return $line;
289
    }
290
}
291