Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
71 / 71
100.00% covered (success)
100.00%
17 / 17
CRAP
100.00% covered (success)
100.00%
1 / 1
ClassGenerator
100.00% covered (success)
100.00%
71 / 71
100.00% covered (success)
100.00%
17 / 17
39
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
5
 setParent
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getParent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasParent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addInterface
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 addInterfaces
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getInterfaces
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasInterfaces
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasInterface
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 removeInterface
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setAsReadonly
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isReadonly
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 render
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
13
 formatConstants
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 formatProperties
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 formatMethods
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <dev@noladev.com>
8 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Code\Generator;
16
17/**
18 * Class generator class
19 *
20 * @category   Pop
21 * @package    Pop\Code
22 * @author     Nick Sagona, III <dev@noladev.com>
23 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    6.0.0
26 */
27class ClassGenerator extends AbstractClassGenerator
28{
29
30    use Traits\UseTrait, Traits\PropertiesTrait, Traits\AbstractFinalTrait;
31
32    /**
33     * Parent class that is extended
34     * @var ?string
35     */
36    protected ?string $parent = null;
37
38    /**
39     * Interfaces that are implemented
40     * @var array
41     */
42    protected array $interfaces = [];
43
44    /**
45     * Readonly flag
46     * @var bool
47     */
48    protected bool $readonly = false;
49
50    /**
51     * Constructor
52     *
53     * Instantiate the class generator object
54     *
55     * @param  string  $name
56     * @param  ?string $parent
57     * @param  mixed   $interface
58     * @param  bool    $abstract
59     */
60    public function __construct(string $name, ?string $parent = null, mixed $interface = null, bool $abstract = false)
61    {
62        $this->setName($name);
63
64        if ($parent !== null) {
65            $this->setParent($parent);
66        }
67
68        if ($interface !== null) {
69            if (is_array($interface)) {
70                $this->addInterfaces($interface);
71            } else if (str_contains($interface, ',')) {
72                $this->addInterfaces(array_map('trim', explode(',', $interface)));
73            } else {
74                $this->addInterface($interface);
75            }
76        }
77
78        $this->setAsAbstract($abstract);
79    }
80
81    /**
82     * Set the class parent
83     *
84     * @param  ?string $parent
85     * @return ClassGenerator
86     */
87    public function setParent(?String $parent = null): ClassGenerator
88    {
89        $this->parent = $parent;
90        return $this;
91    }
92
93    /**
94     * Get the class parent
95     *
96     * @return string|null
97     */
98    public function getParent(): string|null
99    {
100        return $this->parent;
101    }
102
103    /**
104     * Has parent
105     *
106     * @return bool
107     */
108    public function hasParent(): bool
109    {
110        return ($this->parent !== null);
111    }
112
113    /**
114     * Add a class interface
115     *
116     * @param  string $interface
117     * @return ClassGenerator
118     */
119    public function addInterface(string $interface): ClassGenerator
120    {
121        if (!in_array($interface, $this->interfaces)) {
122            $this->interfaces[] = $interface;
123        }
124
125        return $this;
126    }
127
128    /**
129     * Add a class interface
130     *
131     * @param  array $interfaces
132     * @return ClassGenerator
133     */
134    public function addInterfaces(array $interfaces): ClassGenerator
135    {
136        foreach ($interfaces as $interface) {
137            $this->addInterface($interface);
138        }
139
140        return $this;
141    }
142
143    /**
144     * Get the class interfaces
145     *
146     * @return array
147     */
148    public function getInterfaces(): array
149    {
150        return $this->interfaces;
151    }
152
153    /**
154     * Has class interfaces
155     *
156     * @return bool
157     */
158    public function hasInterfaces(): bool
159    {
160        return (!empty($this->interfaces));
161    }
162
163    /**
164     * Has class interface
165     *
166     * @param  string $interface
167     * @return bool
168     */
169    public function hasInterface(string $interface): bool
170    {
171        return (in_array($interface, $this->interfaces));
172    }
173
174    /**
175     * Remove class interface
176     *
177     * @param  string $interface
178     * @return ClassGenerator
179     */
180    public function removeInterface(string $interface): ClassGenerator
181    {
182        if (in_array($interface, $this->interfaces)) {
183            $key = array_search($interface, $this->interfaces);
184            unset($this->interfaces[$key]);
185        }
186
187        return $this;
188    }
189
190    /**
191     * Set the readonly flag
192     *
193     * @param  bool $readonly
194     * @return ClassGenerator
195     */
196    public function setAsReadonly(bool $readonly = true): ClassGenerator
197    {
198        $this->readonly = $readonly;
199        return $this;
200    }
201
202    /**
203     * Get the readonly flag
204     *
205     * @return bool
206     */
207    public function isReadonly(): bool
208    {
209        return $this->readonly;
210    }
211
212    /**
213     * Render class
214     *
215     * @return string
216     */
217    public function render(): string
218    {
219        $classKeyword = null;
220
221        if ($this->isAbstract()) {
222            $classKeyword = 'abstract ';
223        } else if ($this->isFinal()) {
224            $classKeyword = 'final ';
225        }
226
227        if ($this->readonly) {
228            $classKeyword .= 'readonly ';
229        }
230
231        $this->output  = ($this->namespace !== null) ? $this->namespace->render() . PHP_EOL : null;
232        $this->output .= ($this->docblock !== null) ? $this->docblock->render() : null;
233        $this->output .= $this->formatAttributes(false);
234        $this->output .= $classKeyword . 'class ' . $this->name;
235
236        if ($this->parent !== null) {
237            $this->output .= ' extends ' . $this->parent;
238        }
239        if (!empty($this->interfaces)) {
240            $this->output .= ' implements ' . implode(', ', $this->interfaces);
241        }
242
243        $this->output .= PHP_EOL . '{' . PHP_EOL;
244
245        if ($this->hasUses()) {
246            $this->output .= PHP_EOL;
247            foreach ($this->uses as $ns => $as) {
248                // Unlike a namespace-level `use Foo\Bar as Baz;` import, a trait-use inside a
249                // class body has no whole-trait aliasing syntax -- `use SomeTrait as Alias;` here
250                // is not valid PHP (only per-method conflict resolution, `use A, B { A::m as n; }`,
251                // exists, and this simple $ns => $as map has no way to represent that). Any alias
252                // is therefore intentionally ignored when rendering a trait-use.
253                $this->output .= $this->printIndent() . 'use ' . $ns . ';' . PHP_EOL;
254            }
255        }
256
257        if ($this->hasConstants()) {
258            $this->output .= $this->formatConstants();
259        }
260        if ($this->hasProperties()) {
261            $this->output .= $this->formatProperties();
262        }
263        if ($this->hasMethods()) {
264            $this->output .= $this->formatMethods();
265        }
266
267        $this->output .= PHP_EOL . '}' . PHP_EOL;
268
269        return $this->output;
270    }
271
272    /**
273     * Format the constants
274     *
275     * @return string
276     */
277    protected function formatConstants(): string
278    {
279        $constants = null;
280
281        foreach ($this->constants as $constant) {
282            $constants .= $constant->render() . PHP_EOL;
283        }
284
285        return $constants;
286    }
287
288    /**
289     * Format the properties
290     *
291     * @return string
292     */
293    protected function formatProperties(): string
294    {
295        $props = null;
296
297        foreach ($this->properties as $prop) {
298            $props .= $prop->render() . PHP_EOL;
299        }
300
301        return $props;
302    }
303
304    /**
305     * Format the methods
306     *
307     * @return string
308     */
309    protected function formatMethods(): string
310    {
311        $methods = null;
312
313        foreach ($this->methods as $method) {
314            $methods .= $method->render() . PHP_EOL;
315        }
316
317        return $methods;
318    }
319
320    /**
321     * Print class
322     *
323     * @return string
324     */
325    public function __toString(): string
326    {
327        return $this->render();
328    }
329
330}