Entities   B
last analyzed

Complexity

Total Complexity 50

Size/Duplication

Total Lines 373
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 50
eloc 186
c 1
b 0
f 0
dl 0
loc 373
rs 8.4

16 Methods

Rating   Name   Duplication   Size   Complexity  
A setRelations() 0 15 5
A setRelation() 0 8 1
A resetContent() 0 20 1
A setIncrementingProperty() 0 8 2
A setCodeState() 0 3 1
C createRelationMethod() 0 35 14
A createPivot() 0 20 6
A isSoftDelete() 0 3 1
A setPivotContent() 0 26 1
A resetPivotContent() 0 17 1
A __construct() 0 7 1
B createPivotClass() 0 13 7
A setIsSoftDelete() 0 3 1
A getRelationReturn() 0 16 3
A setPivot() 0 16 3
A setContent() 0 36 2

How to fix   Complexity   

Complex Class

Complex classes like Entities often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Entities, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SoliDry\Blocks;
4
5
use Illuminate\Database\Eloquent\SoftDeletes;
6
use SoliDry\Extension\BaseFormRequest;
7
use SoliDry\Extension\BaseModel;
8
use SoliDry\Helpers\Classes;
9
use SoliDry\Helpers\Console;
10
use SoliDry\Helpers\MethodOptions;
11
use SoliDry\Helpers\MigrationsHelper;
12
use SoliDry\ApiGenerator;
13
use SoliDry\Types\CustomsInterface;
14
use SoliDry\Types\DefaultInterface;
15
use SoliDry\Types\ModelsInterface;
16
use SoliDry\Types\PhpInterface;
17
use SoliDry\Types\ApiInterface;
18
19
/**
20
 * Class FormRequest
21
 * @package SoliDry\Blocks
22
 * @property ApiGenerator generator
23
 */
24
class Entities extends FormRequestModel
25
{
26
    use ContentManager, EntitiesTrait;
0 ignored issues
show
Bug introduced by
The trait SoliDry\Blocks\EntitiesTrait requires the property $types which is not provided by SoliDry\Blocks\Entities.
Loading history...
introduced by
The trait SoliDry\Blocks\ContentManager requires some properties which are not provided by SoliDry\Blocks\Entities: $options, $version, $modulesDir
Loading history...
27
28
    /**
29
     * @var ApiGenerator
30
     */
31
    private ApiGenerator $generator;
32
33
    /**
34
     * @var string
35
     */
36
    private string $className;
37
38
    /**
39
     * @var string
40
     */
41
    protected string $sourceCode   = '';
42
43
    /**
44
     * @var bool
45
     */
46
    protected bool $isSoftDelete = false;
47
48
    /**
49
     * Entities constructor.
50
     * @param $generator
51
     */
52
    public function __construct($generator)
53
    {
54
        $this->generator = $generator;
55
        $this->className = Classes::getClassName($this->generator->objectName);
56
        $isSoftDelete    = empty($this->generator->types[$this->generator->objectName . CustomsInterface::CUSTOM_TYPES_ATTRIBUTES]
57
                                 [ApiInterface::RAML_PROPS][ModelsInterface::COLUMN_DEL_AT]) === false;
58
        $this->setIsSoftDelete($isSoftDelete);
59
    }
60
61
    public function setCodeState($generator)
62
    {
63
        $this->generator = $generator;
64
    }
65
66
    /**
67
     * @return bool
68
     */
69
    public function isSoftDelete() : bool
70
    {
71
        return $this->isSoftDelete;
72
    }
73
74
    /**
75
     * @param bool $isSoftDelete
76
     */
77
    public function setIsSoftDelete(bool $isSoftDelete) : void
78
    {
79
        $this->isSoftDelete = $isSoftDelete;
80
    }
81
82
    private function setRelations()
83
    {
84
        $formRequestEntity = $this->getFormRequestEntity($this->generator->version, $this->className);
85
        /** @var BaseFormRequest $formRequest * */
86
        $formRequest = new $formRequestEntity();
87
        if (method_exists($formRequest, ModelsInterface::MODEL_METHOD_RELATIONS)) {
88
            $this->sourceCode .= PHP_EOL;
89
            $relations        = $formRequest->relations();
90
            foreach ($relations as $relationEntity) {
91
                $ucEntity = MigrationsHelper::getObjectName($relationEntity);
92
                // determine if ManyToMany, OneToMany, OneToOne rels
93
                $current = $this->getRelationType($this->generator->objectName);
94
                $related = $this->getRelationType($ucEntity);
95
                if (empty($current) === false && empty($related) === false) {
96
                    $this->createRelationMethod($current, $related, $relationEntity);
97
                }
98
            }
99
        }
100
    }
101
102
    /**
103
     * @param string $current current entity relations
104
     * @param string $related entities from raml file based on relations method array
105
     * @param string $relationEntity
106
     */
107
    private function createRelationMethod(string $current, string $related, string $relationEntity)
108
    {
109
        $ucEntity    = ucfirst($relationEntity);
110
        $currentRels = explode(PhpInterface::PIPE, $current);
111
        $relatedRels = explode(PhpInterface::PIPE, $related);
112
        foreach ($relatedRels as $rel) {
113
            if (strpos($rel, $this->generator->objectName) !== false) {
114
                foreach ($currentRels as $cur) {
115
                    if (strpos($cur, $ucEntity) !== false) {
116
                        $isManyCurrent = strpos($cur, self::CHECK_MANY_BRACKETS);
117
                        $isManyRelated = strpos($rel, self::CHECK_MANY_BRACKETS);
118
                        if ($isManyCurrent === false && $isManyRelated === false) {// OneToOne
119
                            $this->setRelation($relationEntity, ModelsInterface::MODEL_METHOD_HAS_ONE);
120
                        }
121
                        if ($isManyCurrent !== false && $isManyRelated === false) {// ManyToOne
122
                            $this->setRelation($relationEntity, ModelsInterface::MODEL_METHOD_HAS_MANY);
123
                        }
124
                        if ($isManyCurrent === false && $isManyRelated !== false) {// OneToMany inverse
125
                            $this->setRelation($relationEntity, ModelsInterface::MODEL_METHOD_BELONGS_TO);
126
                        }
127
                        if ($isManyCurrent !== false && $isManyRelated !== false) {// ManyToMany
128
                            // check inversion of a pivot
129
                            $entityFile = $this->generator->formatEntitiesPath()
130
                                . PhpInterface::SLASH . $this->generator->objectName .
131
                                ucfirst($relationEntity) .
132
                                PhpInterface::PHP_EXT;
133
                            $relEntity  = $relationEntity;
134
                            $objName    = $this->generator->objectName;
135
                            if (file_exists($entityFile) === false) {
136
                                $relEntity = $this->generator->objectName;
137
                                $objName   = $relationEntity;
138
                            }
139
                            $this->setRelation(
140
                                $relationEntity, ModelsInterface::MODEL_METHOD_BELONGS_TO_MANY,
141
                                MigrationsHelper::getTableName($objName . ucfirst($relEntity))
142
                            );
143
                        }
144
                    }
145
                }
146
            }
147
        }
148
    }
149
150
    /**
151
     * @param string $ucEntity
152
     * @throws \ReflectionException
153
     */
154
    public function setPivot(string $ucEntity): void
155
    {
156
        $file = $this->generator->formatEntitiesPath() .
157
            PhpInterface::SLASH .
158
            $this->className . Classes::getClassName($ucEntity) . PhpInterface::PHP_EXT;
159
        if ($this->generator->isMerge === true) {
160
            $this->resetPivotContent($ucEntity, $file);
161
        } else {
162
            $this->setPivotContent($ucEntity);
163
        }
164
        $isCreated = FileManager::createFile(
165
            $file, $this->sourceCode,
166
            FileManager::isRegenerated($this->generator->options)
167
        );
168
        if ($isCreated) {
169
            Console::out($file . PhpInterface::SPACE . Console::CREATED, Console::COLOR_GREEN);
170
        }
171
    }
172
173
    public function createPivot()
174
    {
175
        $formRequestEntity = $this->getFormRequestEntity($this->generator->version, $this->className);
176
        /** @var BaseFormRequest $formRequest * */
177
        $formRequest = new $formRequestEntity();
178
        if (method_exists($formRequest, ModelsInterface::MODEL_METHOD_RELATIONS)) {
179
            $relations        = $formRequest->relations();
180
            $this->sourceCode .= PHP_EOL; // margin top from props
181
            foreach ($relations as $relationEntity) {
182
                $ucEntity = ucfirst($relationEntity);
183
                $file     = $this->generator->formatEntitiesPath()
184
                    . PhpInterface::SLASH . ucfirst($relationEntity) . $this->generator->objectName .
185
                    PhpInterface::PHP_EXT;
186
                // check if inverse Entity pivot exists
187
                if (file_exists($file) === false) {
188
                    // determine if ManyToMany, OneToMany, OneToOne rels
189
                    $current = $this->getRelationType($this->generator->objectName);
190
                    $related = $this->getRelationType($ucEntity);
191
                    if (empty($current) === false && empty($related) === false) {
192
                        $this->createPivotClass($current, $related, $relationEntity);
193
                    }
194
                }
195
            }
196
        }
197
    }
198
199
    /**
200
     * @param string $current current entity relations
201
     * @param string $related entities from raml file based on relations method array
202
     * @param string $relationEntity
203
     * @throws \ReflectionException
204
     */
205
    private function createPivotClass(string $current, string $related, string $relationEntity): void
206
    {
207
        $ucEntity    = ucfirst($relationEntity);
208
        $currentRels = explode(PhpInterface::PIPE, $current);
209
        $relatedRels = explode(PhpInterface::PIPE, $related);
210
        foreach ($relatedRels as $rel) {
211
            if (strpos($rel, $this->generator->objectName) !== false) {
212
                foreach ($currentRels as $cur) {
213
                    if (strpos($cur, $ucEntity) !== false) {
214
                        $isManyCurrent = strpos($cur, self::CHECK_MANY_BRACKETS);
215
                        $isManyRelated = strpos($rel, self::CHECK_MANY_BRACKETS);
216
                        if ($isManyCurrent !== false && $isManyRelated !== false) {// ManyToMany
217
                            $this->setPivot($ucEntity);
218
                        }
219
                    }
220
                }
221
            }
222
        }
223
    }
224
225
    /**
226
     * @param string $entity
227
     * @param string $method
228
     * @param \string[] ...$args
229
     */
230
    private function setRelation(string $entity, string $method, string ...$args): void
231
    {
232
        $methodOptions = new MethodOptions();
233
        $methodOptions->setName($entity);
234
        $this->startMethod($methodOptions);
235
        $toReturn = $this->getRelationReturn($entity, $method, $args);
236
        $this->setMethodReturn($toReturn);
237
        $this->endMethod(1);
238
    }
239
240
    /**
241
     * @param string $entity
242
     * @param string $method
243
     * @param \string[] ...$args
244
     * @return string
245
     */
246
    private function getRelationReturn(string $entity, string $method, array $args): string
247
    {
248
        $toReturn = PhpInterface::DOLLAR_SIGN . PhpInterface::PHP_THIS
249
            . PhpInterface::ARROW . $method
250
            . PhpInterface::OPEN_PARENTHESES . Classes::getClassName($entity)
251
            . PhpInterface::DOUBLE_COLON . PhpInterface::PHP_CLASS;
252
253
        if (empty($args) === false) {
254
            foreach ($args as $val) {
255
                $toReturn .= PhpInterface::COMMA
256
                    . PhpInterface::SPACE . PhpInterface::QUOTES . $val .
257
                    PhpInterface::QUOTES;
258
            }
259
        }
260
        $toReturn .= PhpInterface::CLOSE_PARENTHESES;
261
        return $toReturn;
262
    }
263
264
    /**
265
     * Sets entity content to $sourceCode
266
     */
267
    private function setContent(): void
0 ignored issues
show
Unused Code introduced by
The method setContent() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
268
    {
269
        $this->setTag();
270
        $this->setNamespace(
271
            $this->generator->entitiesDir
272
        );
273
        $baseMapper     = BaseModel::class;
274
        $baseMapperName = Classes::getName($baseMapper);
275
276
        if ($this->isSoftDelete()) {
277
            $this->setUse(SoftDeletes::class);
278
        }
279
280
        $this->setUse($baseMapper, false, true);
281
        $this->startClass($this->className, $baseMapperName);
282
        $this->setUseSoftDelete();
283
        $this->setComment(DefaultInterface::PROPS_START);
284
        $this->setPropSoftDelete();
285
        $this->createProperty(
286
            ModelsInterface::PROPERTY_PRIMARY_KEY, PhpInterface::PHP_MODIFIER_PROTECTED,
287
            ApiInterface::RAML_ID, true
288
        );
289
        $this->createProperty(
290
            ModelsInterface::PROPERTY_TABLE, PhpInterface::PHP_MODIFIER_PROTECTED,
291
            MigrationsHelper::getTableName($this->generator->objectName), true
292
        );
293
        $this->createProperty(
294
            ModelsInterface::PROPERTY_TIMESTAMPS, PhpInterface::PHP_MODIFIER_PUBLIC,
295
            PhpInterface::PHP_TYPES_BOOL_FALSE
296
        );
297
        $this->setIncrementingProperty();
298
        $this->setComment(DefaultInterface::PROPS_END);
299
        $this->setComment(DefaultInterface::METHOD_START);
300
        $this->setRelations();
301
        $this->setComment(DefaultInterface::METHOD_END);
302
        $this->endClass();
303
    }
304
305
    private function setIncrementingProperty()
306
    {
307
        // O(4)
308
        $idObject = $this->generator->types[$this->generator->types[$this->generator->objectName][ApiInterface::RAML_PROPS][ApiInterface::RAML_ID]];
309
        if ($idObject[ApiInterface::RAML_TYPE] === ApiInterface::RAML_TYPE_STRING) {
310
            $this->createProperty(
311
                ModelsInterface::PROPERTY_INCREMENTING, PhpInterface::PHP_MODIFIER_PUBLIC,
312
                PhpInterface::PHP_TYPES_BOOL_FALSE
313
            );
314
        }
315
    }
316
317
    /**
318
     * Sets entity content to $sourceCode
319
     */
320
    private function resetContent(): void
0 ignored issues
show
Unused Code introduced by
The method resetContent() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
321
    {
322
        $this->setBeforeProps($this->getEntityFile($this->generator->formatEntitiesPath()));
323
        $this->setComment(DefaultInterface::PROPS_START, 0);
324
        $this->createProperty(
325
            ModelsInterface::PROPERTY_PRIMARY_KEY, PhpInterface::PHP_MODIFIER_PROTECTED,
326
            ApiInterface::RAML_ID, true
327
        );
328
        $this->createProperty(
329
            ModelsInterface::PROPERTY_TABLE, PhpInterface::PHP_MODIFIER_PROTECTED,
330
            strtolower($this->generator->objectName), true
331
        );
332
        $this->createProperty(
333
            ModelsInterface::PROPERTY_TIMESTAMPS, PhpInterface::PHP_MODIFIER_PUBLIC,
334
            PhpInterface::PHP_TYPES_BOOL_FALSE
335
        );
336
        $this->setAfterProps(DefaultInterface::METHOD_START);
337
        $this->setComment(DefaultInterface::METHOD_START, 0);
338
        $this->setRelations();
339
        $this->setAfterMethods();
340
    }
341
342
    /**
343
     *  Sets pivot entity content to $sourceCode
344
     * @param string $ucEntity an entity upper case first name
345
     * @throws \ReflectionException
346
     */
347
    private function setPivotContent(string $ucEntity): void
348
    {
349
        $this->setTag();
350
        $this->setNamespace(
351
            $this->generator->entitiesDir
352
        );
353
        $baseMapper     = BaseModel::class;
354
        $baseMapperName = Classes::getName($baseMapper);
355
356
        $this->setUse($baseMapper, false, true);
357
        $this->startClass($this->className . Classes::getClassName($ucEntity), $baseMapperName);
358
        $this->setComment(DefaultInterface::PROPS_START);
359
        $this->createProperty(
360
            ModelsInterface::PROPERTY_PRIMARY_KEY, PhpInterface::PHP_MODIFIER_PROTECTED,
361
            ApiInterface::RAML_ID, true
362
        );
363
        $this->createProperty(
364
            ModelsInterface::PROPERTY_TABLE, PhpInterface::PHP_MODIFIER_PROTECTED,
365
            strtolower($this->generator->objectName . PhpInterface::UNDERSCORE . $ucEntity), true
366
        );
367
        $this->createProperty(
368
            ModelsInterface::PROPERTY_TIMESTAMPS, PhpInterface::PHP_MODIFIER_PUBLIC,
369
            PhpInterface::PHP_TYPES_BOOL_TRUE
370
        );
371
        $this->setComment(DefaultInterface::PROPS_END);
372
        $this->endClass();
373
    }
374
375
    /**
376
     *  Re-Sets pivot entity content to $sourceCode
377
     * @param string $ucEntity an entity upper case first name
378
     * @param string $file
379
     */
380
    private function resetPivotContent(string $ucEntity, string $file)
381
    {
382
        $this->setBeforeProps($file);
383
        $this->setComment(DefaultInterface::PROPS_START, 0);
384
        $this->createProperty(
385
            ModelsInterface::PROPERTY_PRIMARY_KEY, PhpInterface::PHP_MODIFIER_PROTECTED,
386
            ApiInterface::RAML_ID, true
387
        );
388
        $this->createProperty(
389
            ModelsInterface::PROPERTY_TABLE, PhpInterface::PHP_MODIFIER_PROTECTED,
390
            strtolower($this->generator->objectName . PhpInterface::UNDERSCORE . $ucEntity), true
391
        );
392
        $this->createProperty(
393
            ModelsInterface::PROPERTY_TIMESTAMPS, PhpInterface::PHP_MODIFIER_PUBLIC,
394
            PhpInterface::PHP_TYPES_BOOL_TRUE
395
        );
396
        $this->setAfterProps();
397
    }
398
}