GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — master (#221)
by joseph
03:45
created

getEntityFqnFromEntityDtoFactoryFqn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 10
ccs 8
cts 8
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration;
4
5
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\AbstractCommand;
6
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\AbstractGenerator;
7
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\RelationsGenerator;
8
use EdmondsCommerce\DoctrineStaticMeta\Config;
9
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
10
use EdmondsCommerce\DoctrineStaticMeta\MappingHelper;
11
use Exception;
12
use RuntimeException;
13
use SplFileInfo;
14
use Symfony\Component\Finder\Finder;
15
use function array_merge;
16
use function array_slice;
17
use function get_class;
18
use function implode;
19
use function in_array;
20
use function str_replace;
21
use function strlen;
22
use function strrpos;
23
use function substr;
24
use function ucfirst;
25
26
/**
27
 * Class NamespaceHelper
28
 *
29
 * Pure functions for working with namespaces and to calculate namespaces
30
 *
31
 * @package EdmondsCommerce\DoctrineStaticMeta\CodeGeneration
32
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
33
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
34
 * @SuppressWarnings(PHPMD.ExcessivePublicCount)
35
 */
36
class NamespaceHelper
37
{
38 1
    public function getAllArchetypeFieldFqns(): array
39
    {
40 1
        $archetypeFqns = [];
41 1
        $namespaceBase = 'EdmondsCommerce\\DoctrineStaticMeta\\Entity\\Fields\\Traits';
42 1
        $finder        = (new Finder())->files()
43 1
                                       ->name('*.php')
44 1
                                       ->in(__DIR__ . '/../Entity/Fields/Traits/');
45 1
        foreach ($finder as $file) {
46
            /** @var SplFileInfo $file */
47 1
            $realpath = $file->getRealPath();
48 1
            if (\ts\stringContains($realpath, '/PrimaryKey/')) {
49 1
                continue;
50
            }
51 1
            $subPath         = substr(
52 1
                $realpath,
53 1
                strpos($realpath, 'Entity/Fields/Traits/') + strlen('Entity/Fields/Traits/')
54
            );
55 1
            $subPath         = substr($subPath, 0, -4);
56 1
            $subFqn          = str_replace('/', '\\', $subPath);
57 1
            $archetypeFqns[] = $namespaceBase . '\\' . $subFqn;
58
        }
59
60 1
        return $archetypeFqns;
61
    }
62
63 1
    public function swapSuffix(string $fqn, string $currentSuffix, string $newSuffix): string
64
    {
65 1
        return $this->cropSuffix($fqn, $currentSuffix) . $newSuffix;
66
    }
67
68
    /**
69
     * Crop a suffix from an FQN if it is there.
70
     *
71
     * If it is not there, do nothing and return the FQN as is
72
     *
73
     * @param string $fqn
74
     * @param string $suffix
75
     *
76
     * @return string
77
     */
78 3
    public function cropSuffix(string $fqn, string $suffix): string
79
    {
80 3
        if ($suffix === substr($fqn, -strlen($suffix))) {
81 2
            return substr($fqn, 0, -strlen($suffix));
82
        }
83
84 1
        return $fqn;
85
    }
86
87 1
    public function getEmbeddableObjectFqnFromEmbeddableObjectInterfaceFqn(string $interfaceFqn): string
88
    {
89 1
        return str_replace(
90 1
            ['\\Interfaces\\', 'Interface'],
91 1
            ['\\', ''],
92 1
            $interfaceFqn
93
        );
94
    }
95
96
    /**
97
     * @param mixed|object $object
98
     *
99
     * @return string
100
     */
101 1
    public function getObjectShortName($object): string
102
    {
103 1
        return $this->getClassShortName($this->getObjectFqn($object));
104
    }
105
106
    /**
107
     * @param string $className
108
     *
109
     * @return string
110
     */
111 2
    public function getClassShortName(string $className): string
112
    {
113 2
        $exp = explode('\\', $className);
114
115 2
        return end($exp);
116
    }
117
118
    /**
119
     * @param mixed|object $object
120
     *
121
     * @return string
122
     * @see https://gist.github.com/ludofleury/1708784
123
     */
124 2
    public function getObjectFqn($object): string
125
    {
126 2
        return get_class($object);
127
    }
128
129
    /**
130
     * Get the basename of a namespace
131
     *
132
     * @param string $namespace
133
     *
134
     * @return string
135
     */
136 1
    public function basename(string $namespace): string
137
    {
138 1
        $strrpos = strrpos($namespace, '\\');
139 1
        if (false === $strrpos) {
140
            return $namespace;
141
        }
142
143 1
        return $this->tidy(substr($namespace, $strrpos + 1));
144
    }
145
146
    /**
147
     * Checks and tidies up a given namespace
148
     *
149
     * @param string $namespace
150
     *
151
     * @return string
152
     * @throws RuntimeException
153
     */
154 20
    public function tidy(string $namespace): string
155
    {
156 20
        if (\ts\stringContains($namespace, '/')) {
157
            throw new RuntimeException('Invalid namespace ' . $namespace);
158
        }
159
        #remove repeated separators
160 20
        $namespace = preg_replace(
161 20
            '#' . '\\\\' . '+#',
162 20
            '\\',
163 20
            $namespace
164
        );
165
166 20
        return $namespace;
167
    }
168
169
    /**
170
     * Get the fully qualified name of the Fixture class for a specified Entity fully qualified name
171
     *
172
     * @param string $entityFqn
173
     *
174
     * @return string
175
     */
176 2
    public function getFixtureFqnFromEntityFqn(string $entityFqn): string
177
    {
178 2
        return str_replace(
179 2
            '\\Entities',
180 2
            '\\Assets\\Entity\\Fixtures',
181 2
            $entityFqn
182 2
        ) . 'Fixture';
183
    }
184
185
    /**
186
     * Get the fully qualified name of the Entity for a specified Entity fully qualified name
187
     *
188
     * @param string $fixtureFqn
189
     *
190
     * @return string
191
     */
192
    public function getEntityFqnFromFixtureFqn(string $fixtureFqn): string
193
    {
194
        return substr(
195
            str_replace(
196
                '\\Assets\\Entity\\Fixtures',
197
                '\\Entities',
198
                $fixtureFqn
199
            ),
200
            0,
201
            -strlen('Fixture')
202
        );
203
    }
204
205
    /**
206
     * Get the namespace root up to and including a specified directory
207
     *
208
     * @param string $fqn
209
     * @param string $directory
210
     *
211
     * @return null|string
212
     */
213
    public function getNamespaceRootToDirectoryFromFqn(string $fqn, string $directory): ?string
214
    {
215
        $strPos = strrpos(
216
            $fqn,
217
            $directory
218
        );
219
        if (false !== $strPos) {
220
            return $this->tidy(substr($fqn, 0, $strPos + strlen($directory)));
221
        }
222
223
        return null;
224
    }
225
226
    /**
227
     * Get the sub path for an Entity file, start from the Entities path - normally `/path/to/project/src/Entities`
228
     *
229
     * @param string $entityFqn
230
     *
231
     * @return string
232
     */
233 1
    public function getEntityFileSubPath(
234
        string $entityFqn
235
    ): string {
236 1
        return $this->getEntitySubPath($entityFqn) . '.php';
237
    }
238
239
    /**
240
     * Get the folder structure for an Entity, start from the Entities path - normally `/path/to/project/src/Entities`
241
     *
242
     * This is not the path to the file, but the sub path of directories for storing entity related items.
243
     *
244
     * @param string $entityFqn
245
     *
246
     * @return string
247
     */
248 2
    public function getEntitySubPath(
249
        string $entityFqn
250
    ): string {
251 2
        $entityPath = str_replace(
252 2
            '\\',
253 2
            '/',
254 2
            $this->getEntitySubNamespace($entityFqn)
255
        );
256
257 2
        return '/' . $entityPath;
258
    }
259
260
    /**
261
     * Get the Namespace for an Entity, start from the Entities Fully Qualified Name base - normally
262
     * `\My\Project\Entities\`
263
     *
264
     * @param string $entityFqn
265
     *
266
     * @return string
267
     */
268 7
    public function getEntitySubNamespace(
269
        string $entityFqn
270
    ): string {
271 7
        return $this->tidy(
272 7
            substr(
273 7
                $entityFqn,
274 7
                strrpos(
275 7
                    $entityFqn,
276 7
                    '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\'
277
                )
278 7
                + strlen('\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\')
279
            )
280
        );
281
    }
282
283
    /**
284
     * Get the Fully Qualified Namespace root for Traits for the specified Entity
285
     *
286
     * @param string $entityFqn
287
     *
288
     * @return string
289
     */
290 1
    public function getTraitsNamespaceForEntity(
291
        string $entityFqn
292
    ): string {
293 1
        $traitsNamespace = $this->getProjectNamespaceRootFromEntityFqn($entityFqn)
294 1
                           . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE
295 1
                           . '\\' . $this->getEntitySubNamespace($entityFqn)
296 1
                           . '\\Traits';
297
298 1
        return $traitsNamespace;
299
    }
300
301
    /**
302
     * Use the fully qualified name of two Entities to calculate the Project Namespace Root
303
     *
304
     * - note: this assumes a single namespace level for entities, eg `Entities`
305
     *
306
     * @param string $entityFqn
307
     *
308
     * @return string
309
     */
310 5
    public function getProjectNamespaceRootFromEntityFqn(string $entityFqn): string
311
    {
312 5
        return $this->tidy(
313 5
            substr(
314 5
                $entityFqn,
315 5
                0,
316 5
                strrpos(
317 5
                    $entityFqn,
318 5
                    '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\'
319
                )
320
            )
321
        );
322
    }
323
324
    /**
325
     * Get the Fully Qualified Namespace for the "HasEntities" interface for the specified Entity
326
     *
327
     * @param string $entityFqn
328
     *
329
     * @return string
330
     */
331 1
    public function getHasPluralInterfaceFqnForEntity(
332
        string $entityFqn
333
    ): string {
334 1
        $interfaceNamespace = $this->getInterfacesNamespaceForEntity($entityFqn);
335
336 1
        return $interfaceNamespace . '\\Has' . ucfirst($entityFqn::getDoctrineStaticMeta()->getPlural()) . 'Interface';
337
    }
338
339
    /**
340
     * Get the Fully Qualified Namespace root for Interfaces for the specified Entity
341
     *
342
     * @param string $entityFqn
343
     *
344
     * @return string
345
     */
346 3
    public function getInterfacesNamespaceForEntity(
347
        string $entityFqn
348
    ): string {
349 3
        $interfacesNamespace = $this->getProjectNamespaceRootFromEntityFqn($entityFqn)
350 3
                               . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE
351 3
                               . '\\' . $this->getEntitySubNamespace($entityFqn)
352 3
                               . '\\Interfaces';
353
354 3
        return $this->tidy($interfacesNamespace);
355
    }
356
357
    /**
358
     * Get the Fully Qualified Namespace for the "HasEntity" interface for the specified Entity
359
     *
360
     * @param string $entityFqn
361
     *
362
     * @return string
363
     * @throws DoctrineStaticMetaException
364
     */
365 1
    public function getHasSingularInterfaceFqnForEntity(
366
        string $entityFqn
367
    ): string {
368
        try {
369 1
            $interfaceNamespace = $this->getInterfacesNamespaceForEntity($entityFqn);
370
371 1
            return $interfaceNamespace . '\\Has' . ucfirst($entityFqn::getDoctrineStaticMeta()->getSingular())
372 1
                   . 'Interface';
373
        } catch (Exception $e) {
374
            throw new DoctrineStaticMetaException(
375
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
376
                $e->getCode(),
377
                $e
378
            );
379
        }
380
    }
381
382
    /**
383
     * Get the Fully Qualified Namespace for the Relation Trait for a specific Entity and hasType
384
     *
385
     * @param string      $hasType
386
     * @param string      $ownedEntityFqn
387
     * @param string|null $projectRootNamespace
388
     * @param string      $srcFolder
389
     *
390
     * @return string
391
     * @throws DoctrineStaticMetaException
392
     */
393 2
    public function getOwningTraitFqn(
394
        string $hasType,
395
        string $ownedEntityFqn,
396
        ?string $projectRootNamespace = null,
397
        string $srcFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER
398
    ): string {
399
        try {
400 2
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, $projectRootNamespace);
0 ignored issues
show
Bug introduced by
It seems like $projectRootNamespace can also be of type null; however, parameter $projectRootNamespace of EdmondsCommerce\Doctrine...lper::getOwnedHasName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

400
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, /** @scrutinizer ignore-type */ $projectRootNamespace);
Loading history...
401 2
            if (null === $projectRootNamespace) {
402
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
403
            }
404 2
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
405 2
                $ownedEntityFqn,
406 2
                $srcFolder,
407 2
                $projectRootNamespace
408
            );
409 2
            $traitSubDirectories = array_slice($ownedSubDirectories, 2);
410 2
            $owningTraitFqn      = $this->getOwningRelationsRootFqn(
411 2
                $projectRootNamespace,
412 2
                $traitSubDirectories
413
            );
414 2
            $required            = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED)
415 1
                ? RelationsGenerator::PREFIX_REQUIRED
416 2
                : '';
417 2
            $owningTraitFqn      .= $ownedClassName . '\\Traits\\Has' . $required . $ownedHasName
418 2
                                    . '\\' . $this->getBaseHasTypeTraitFqn($ownedHasName, $hasType);
419
420 2
            return $this->tidy($owningTraitFqn);
421
        } catch (Exception $e) {
422
            throw new DoctrineStaticMetaException(
423
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
424
                $e->getCode(),
425
                $e
426
            );
427
        }
428
    }
429
430
    /**
431
     * Based on the $hasType, we calculate exactly what type of `Has` we have
432
     *
433
     * @param string $hasType
434
     * @param string $ownedEntityFqn
435
     * @param string $srcOrTestSubFolder
436
     *
437
     * @param string $projectRootNamespace
438
     *
439
     * @return string
440
     * @SuppressWarnings(PHPMD.StaticAccess)
441
     * @throws DoctrineStaticMetaException
442
     */
443 4
    public function getOwnedHasName(
444
        string $hasType,
445
        string $ownedEntityFqn,
446
        string $srcOrTestSubFolder,
447
        string $projectRootNamespace
448
    ): string {
449 4
        $parsedFqn = $this->parseFullyQualifiedName(
450 4
            $ownedEntityFqn,
451 4
            $srcOrTestSubFolder,
452 4
            $projectRootNamespace
453
        );
454
455 4
        $subDirectories = $parsedFqn[2];
456
457 4
        if (in_array(
458 4
            $hasType,
459 4
            RelationsGenerator::HAS_TYPES_PLURAL,
460 4
            true
461
        )) {
462 4
            return $this->getPluralNamespacedName($ownedEntityFqn, $subDirectories);
463
        }
464
465 2
        return $this->getSingularNamespacedName($ownedEntityFqn, $subDirectories);
466
    }
467
468
    /**
469
     * From the fully qualified name, parse out:
470
     *  - class name,
471
     *  - namespace
472
     *  - the namespace parts not including the project root namespace
473
     *
474
     * @param string      $fqn
475
     *
476
     * @param string      $srcOrTestSubFolder eg 'src' or 'test'
477
     *
478
     * @param string|null $projectRootNamespace
479
     *
480
     * @return array [$className,$namespace,$subDirectories]
481
     * @throws DoctrineStaticMetaException
482
     */
483 5
    public function parseFullyQualifiedName(
484
        string $fqn,
485
        string $srcOrTestSubFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER,
486
        string $projectRootNamespace = null
487
    ): array {
488
        try {
489 5
            $fqn = $this->root($fqn);
490 5
            if (null === $projectRootNamespace) {
491
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcOrTestSubFolder);
492
            }
493 5
            $projectRootNamespace = $this->root($projectRootNamespace);
494 5
            if (false === \ts\stringContains($fqn, $projectRootNamespace)) {
0 ignored issues
show
introduced by
The condition false === stringContains... $projectRootNamespace) is always false.
Loading history...
495
                throw new DoctrineStaticMetaException(
496
                    'The $fqn [' . $fqn . '] does not contain the project root namespace'
497
                    . ' [' . $projectRootNamespace . '] - are you sure it is the correct FQN?'
498
                );
499
            }
500 5
            $fqnParts       = explode('\\', $fqn);
501 5
            $className      = array_pop($fqnParts);
502 5
            $namespace      = implode('\\', $fqnParts);
503 5
            $rootParts      = explode('\\', $projectRootNamespace);
504 5
            $subDirectories = [];
505 5
            foreach ($fqnParts as $k => $fqnPart) {
506 5
                if (isset($rootParts[$k]) && $rootParts[$k] === $fqnPart) {
507 5
                    continue;
508
                }
509 5
                $subDirectories[] = $fqnPart;
510
            }
511 5
            array_unshift($subDirectories, $srcOrTestSubFolder);
512
513
            return [
514 5
                $className,
515 5
                $this->root($namespace),
516 5
                $subDirectories,
517
            ];
518
        } catch (Exception $e) {
519
            throw new DoctrineStaticMetaException(
520
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
521
                $e->getCode(),
522
                $e
523
            );
524
        }
525
    }
526
527
    /**
528
     * Generate a tidy root namespace without a leading \
529
     *
530
     * @param string $namespace
531
     *
532
     * @return string
533
     */
534 6
    public function root(string $namespace): string
535
    {
536 6
        return $this->tidy(ltrim($namespace, '\\'));
537
    }
538
539
    /**
540
     * Read src autoloader from composer json
541
     *
542
     * @param string $dirForNamespace
543
     *
544
     * @return string
545
     * @throws DoctrineStaticMetaException
546
     * @SuppressWarnings(PHPMD.StaticAccess)
547
     */
548 16
    public function getProjectRootNamespaceFromComposerJson(
549
        string $dirForNamespace = 'src'
550
    ): string {
551
        try {
552 16
            $dirForNamespace = trim($dirForNamespace, '/');
553 16
            $jsonPath        = Config::getProjectRootDirectory() . '/composer.json';
554 16
            $json            = json_decode(\ts\file_get_contents($jsonPath), true);
555 16
            if (JSON_ERROR_NONE !== json_last_error()) {
556
                throw new RuntimeException(
557
                    'Error decoding json from path ' . $jsonPath . ' , ' . json_last_error_msg()
558
                );
559
            }
560
            /**
561
             * @var string[][][][] $json
562
             */
563 16
            if (isset($json['autoload']['psr-4'])) {
564 16
                foreach ($json['autoload']['psr-4'] as $namespace => $dirs) {
565 16
                    if(!is_array($dirs))
566
                    {
567
                        $dirs = [$dirs];
568
                    }
569 16
                    foreach ($dirs as $dir) {
570 16
                        $dir = trim($dir, '/');
571 16
                        if ($dir === $dirForNamespace) {
572 16
                            return $this->tidy(rtrim($namespace, '\\'));
573
                        }
574
                    }
575
                }
576
            }
577
        } catch (Exception $e) {
578
            throw new DoctrineStaticMetaException(
579
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
580
                $e->getCode(),
581
                $e
582
            );
583
        }
584
        throw new DoctrineStaticMetaException('Failed to find psr-4 namespace root');
585
    }
586
587
    /**
588
     * @param string $entityFqn
589
     * @param array  $subDirectories
590
     *
591
     * @return string
592
     * @SuppressWarnings(PHPMD.StaticAccess)
593
     */
594 4
    public function getPluralNamespacedName(string $entityFqn, array $subDirectories): string
595
    {
596 4
        $plural = ucfirst(MappingHelper::getPluralForFqn($entityFqn));
597
598 4
        return $this->getNamespacedName($plural, $subDirectories);
599
    }
600
601
    /**
602
     * @param string $entityName
603
     * @param array  $subDirectories
604
     *
605
     * @return string
606
     */
607 4
    public function getNamespacedName(string $entityName, array $subDirectories): string
608
    {
609 4
        $noEntitiesDirectory = array_slice($subDirectories, 2);
610 4
        $namespacedName      = array_merge($noEntitiesDirectory, [$entityName]);
611
612 4
        return ucfirst(implode('', $namespacedName));
613
    }
614
615
    /**
616
     * @param string $entityFqn
617
     * @param array  $subDirectories
618
     *
619
     * @return string
620
     * @SuppressWarnings(PHPMD.StaticAccess)
621
     */
622 3
    public function getSingularNamespacedName(string $entityFqn, array $subDirectories): string
623
    {
624 3
        $singular = ucfirst(MappingHelper::getSingularForFqn($entityFqn));
625
626 3
        return $this->getNamespacedName($singular, $subDirectories);
627
    }
628
629
    /**
630
     * Get the Namespace root for Entity Relations
631
     *
632
     * @param string $projectRootNamespace
633
     * @param array  $subDirectories
634
     *
635
     * @return string
636
     */
637 3
    public function getOwningRelationsRootFqn(
638
        string $projectRootNamespace,
639
        array $subDirectories
640
    ): string {
641
        $relationsRootFqn = $projectRootNamespace
642 3
                            . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE . '\\';
643 3
        if (count($subDirectories) > 0) {
644 1
            $relationsRootFqn .= implode('\\', $subDirectories) . '\\';
645
        }
646
647 3
        return $this->tidy($relationsRootFqn);
648
    }
649
650
    /**
651
     * Normalise a has type, removing prefixes that are not required
652
     *
653
     * Inverse hasTypes use the standard template without the prefix
654
     * The exclusion ot this are the ManyToMany and OneToOne relations
655
     *
656
     * @param string $ownedHasName
657
     * @param string $hasType
658
     *
659
     * @return string
660
     */
661 2
    public function getBaseHasTypeTraitFqn(
662
        string $ownedHasName,
663
        string $hasType
664
    ): string {
665 2
        $required = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED)
666 1
            ? RelationsGenerator::PREFIX_REQUIRED
667 2
            : '';
668
669 2
        $hasType = str_replace(RelationsGenerator::PREFIX_REQUIRED, '', $hasType);
670
        foreach ([
671 2
                     RelationsGenerator::INTERNAL_TYPE_MANY_TO_MANY,
672 2
                     RelationsGenerator::INTERNAL_TYPE_ONE_TO_ONE,
673
                 ] as $noStrip) {
674 2
            if (\ts\stringContains($hasType, $noStrip)) {
675 2
                return 'Has' . $required . $ownedHasName . $hasType;
676
            }
677
        }
678
679
        foreach ([
680 1
                     RelationsGenerator::INTERNAL_TYPE_ONE_TO_MANY,
681 1
                     RelationsGenerator::INTERNAL_TYPE_MANY_TO_ONE,
682
                 ] as $stripAll) {
683 1
            if (\ts\stringContains($hasType, $stripAll)) {
684 1
                return str_replace(
685
                    [
686 1
                        RelationsGenerator::PREFIX_OWNING,
687 1
                        RelationsGenerator::PREFIX_INVERSE,
688
                    ],
689 1
                    '',
690 1
                    'Has' . $required . $ownedHasName . $hasType
691
                );
692
            }
693
        }
694
695
        return str_replace(
696
            [
697
                RelationsGenerator::PREFIX_INVERSE,
698
            ],
699
            '',
700
            'Has' . $required . $ownedHasName . $hasType
701
        );
702
    }
703
704 2
    public function getFactoryFqnFromEntityFqn(string $entityFqn): string
705
    {
706 2
        return $this->tidy(
707 2
            str_replace(
708 2
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
709 2
                '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE . '\\',
710 2
                $entityFqn
711 2
            ) . 'Factory'
712
        );
713
    }
714
715 2
    public function getDtoFactoryFqnFromEntityFqn(string $entityFqn): string
716
    {
717 2
        return $this->tidy(
718 2
            str_replace(
719 2
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
720 2
                '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE . '\\',
721 2
                $entityFqn
722 2
            ) . 'DtoFactory'
723
        );
724
    }
725
726 1
    public function getRepositoryqnFromEntityFqn(string $entityFqn): string
727
    {
728 1
        return $this->tidy(
729 1
            str_replace(
730 1
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
731 1
                '\\' . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE . '\\',
732 1
                $entityFqn
733 1
            ) . 'Repository'
734
        );
735
    }
736
737
    /**
738
     * @param string $ownedEntityFqn
739
     * @param string $srcOrTestSubFolder
740
     * @param string $projectRootNamespace
741
     *
742
     * @return string
743
     * @throws DoctrineStaticMetaException
744
     */
745 1
    public function getReciprocatedHasName(
746
        string $ownedEntityFqn,
747
        string $srcOrTestSubFolder,
748
        string $projectRootNamespace
749
    ): string {
750 1
        $parsedFqn = $this->parseFullyQualifiedName(
751 1
            $ownedEntityFqn,
752 1
            $srcOrTestSubFolder,
753 1
            $projectRootNamespace
754
        );
755
756 1
        $subDirectories = $parsedFqn[2];
757
758 1
        return $this->getSingularNamespacedName($ownedEntityFqn, $subDirectories);
759
    }
760
761
    /**
762
     * Get the Fully Qualified Namespace for the Relation Interface for a specific Entity and hasType
763
     *
764
     * @param string      $hasType
765
     * @param string      $ownedEntityFqn
766
     * @param string|null $projectRootNamespace
767
     * @param string      $srcFolder
768
     *
769
     * @return string
770
     * @throws DoctrineStaticMetaException
771
     */
772 2
    public function getOwningInterfaceFqn(
773
        string $hasType,
774
        string $ownedEntityFqn,
775
        string $projectRootNamespace = null,
776
        string $srcFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER
777
    ): string {
778
        try {
779 2
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, $projectRootNamespace);
0 ignored issues
show
Bug introduced by
It seems like $projectRootNamespace can also be of type null; however, parameter $projectRootNamespace of EdmondsCommerce\Doctrine...lper::getOwnedHasName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

779
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, /** @scrutinizer ignore-type */ $projectRootNamespace);
Loading history...
780 2
            if (null === $projectRootNamespace) {
781
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
782
            }
783 2
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
784 2
                $ownedEntityFqn,
785 2
                $srcFolder,
786 2
                $projectRootNamespace
787
            );
788 2
            $interfaceSubDirectories = array_slice($ownedSubDirectories, 2);
789 2
            $owningInterfaceFqn      = $this->getOwningRelationsRootFqn(
790 2
                $projectRootNamespace,
791 2
                $interfaceSubDirectories
792
            );
793 2
            $required                = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED)
794 1
                ? 'Required'
795 2
                : '';
796
            $owningInterfaceFqn      .= '\\' .
797 2
                                        $ownedClassName .
798 2
                                        '\\Interfaces\\Has' .
799 2
                                        $required .
800 2
                                        $ownedHasName .
801 2
                                        'Interface';
802
803 2
            return $this->tidy($owningInterfaceFqn);
804
        } catch (Exception $e) {
805
            throw new DoctrineStaticMetaException(
806
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
807
                $e->getCode(),
808
                $e
809
            );
810
        }
811
    }
812
813 1
    public function getEntityInterfaceFromEntityFqn(string $entityFqn): string
814
    {
815 1
        return str_replace(
816 1
            '\\Entities\\',
817 1
            '\\Entity\\Interfaces\\',
818 1
            $entityFqn
819 1
        ) . 'Interface';
820
    }
821
822 1
    public function getEntityFqnFromEntityInterfaceFqn(string $entityInterfaceFqn): string
823
    {
824 1
        return substr(
825 1
            str_replace(
826 1
                '\\Entity\\Interfaces\\',
827 1
                '\\Entities\\',
828 1
                $entityInterfaceFqn
829
            ),
830 1
            0,
831 1
            -strlen('Interface')
832
        );
833
    }
834
835 1
    public function getEntityFqnFromEntityFactoryFqn(string $entityFactoryFqn): string
836
    {
837 1
        return substr(
838 1
            str_replace(
839 1
                '\\Entity\\Factories\\',
840 1
                '\\Entities\\',
841 1
                $entityFactoryFqn
842
            ),
843 1
            0,
844 1
            -strlen('Factory')
845
        );
846
    }
847
848 1
    public function getEntityFqnFromEntityDtoFactoryFqn(string $entityDtoFactoryFqn): string
849
    {
850 1
        return substr(
851 1
            str_replace(
852 1
                '\\Entity\\Factories\\',
853 1
                '\\Entities\\',
854 1
                $entityDtoFactoryFqn
855
            ),
856 1
            0,
857 1
            -strlen('DtoFactory')
858
        );
859
    }
860
861 2
    public function getEntityDtoFqnFromEntityFqn(string $entityFqn): string
862
    {
863 2
        return str_replace(
864 2
            '\\Entities\\',
865 2
            '\\Entity\\DataTransferObjects\\',
866 2
            $entityFqn
867 2
        ) . 'Dto';
868
    }
869
870
    /**
871
     * @param string $entityDtoFqn
872
     *
873
     * @return string
874
     * @deprecated please use the static method on the DTO directly
875
     *
876
     */
877
    public function getEntityFqnFromEntityDtoFqn(string $entityDtoFqn): string
878
    {
879
        return $entityDtoFqn::getEntityFqn();
880
    }
881
882
    public function getEntityFqnFromEntityRepositoryFqn(string $entityRepositoryFqn): string
883
    {
884
        return substr(
885
            str_replace(
886
                '\\Entity\\Repositories\\',
887
                '\\Entities\\',
888
                $entityRepositoryFqn
889
            ),
890
            0,
891
            -strlen('Repository')
892
        );
893
    }
894
895
    public function getEntityFqnFromEntitySaverFqn(string $entitySaverFqn): string
896
    {
897
        return substr(
898
            str_replace(
899
                '\\Entity\\Savers\\',
900
                '\\Entities\\',
901
                $entitySaverFqn
902
            ),
903
            0,
904
            -strlen('Saver')
905
        );
906
    }
907
908 1
    public function getEntitySaverFqnFromEntityFqn(string $entityFqn): string
909
    {
910 1
        return str_replace(
911 1
            '\\Entities\\',
912 1
            '\\Entity\\Savers\\',
913 1
            $entityFqn
914 1
        ) . 'Saver';
915
    }
916
917 1
    public function getEntityFqnFromEntityUpserterFqn(string $entityUpserterFqn): string
918
    {
919 1
        return substr(
920 1
            str_replace(
921 1
                '\\Entity\\Savers\\',
922 1
                '\\Entities\\',
923 1
                $entityUpserterFqn
924
            ),
925 1
            0,
926 1
            -strlen('Upserter')
927
        );
928
    }
929
930 2
    public function getEntityUpserterFqnFromEntityFqn(string $entityFqn): string
931
    {
932 2
        return str_replace(
933 2
            '\\Entities\\',
934 2
            '\\Entity\\Savers\\',
935 2
            $entityFqn
936 2
        ) . 'Upserter';
937
    }
938
939 1
    public function getEntityFqnFromEntityUnitOfWorkHelperFqn(string $entityUnitofWorkHelperFqn): string
940
    {
941 1
        return substr(
942 1
            str_replace(
943 1
                '\\Entity\\Savers\\',
944 1
                '\\Entities\\',
945 1
                $entityUnitofWorkHelperFqn
946
            ),
947 1
            0,
948 1
            -strlen('UnitOfWorkHelper')
949
        );
950
    }
951
952 2
    public function getEntityUnitOfWorkHelperFqnFromEntityFqn(string $entityFqn): string
953
    {
954 2
        return str_replace(
955 2
            '\\Entities\\',
956 2
            '\\Entity\\Savers\\',
957 2
            $entityFqn
958 2
        ) . 'UnitOfWorkHelper';
959
    }
960
961
    public function getEntityFqnFromEntityTestFqn(string $entityTestFqn): string
962
    {
963
        return substr(
964
            $entityTestFqn,
965
            0,
966
            -strlen('Test')
967
        );
968
    }
969
970 1
    public function getEntityTestFqnFromEntityFqn(string $entityFqn): string
971
    {
972 1
        return $entityFqn . 'Test';
973
    }
974
}
975