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.

NamespaceHelper::getEntityInterfaceFromEntityFqn()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

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

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

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