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.
Completed
Pull Request — master (#93)
by joseph
14:47
created

getFakerProviderFqnFromFieldTraitReflection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

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

352
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, /** @scrutinizer ignore-type */ $projectRootNamespace);
Loading history...
353 24
            if (null === $projectRootNamespace) {
354
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
355
            }
356 24
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
357 24
                $ownedEntityFqn,
358 24
                $srcFolder,
359 24
                $projectRootNamespace
360
            );
361 24
            $traitSubDirectories = \array_slice($ownedSubDirectories, 2);
362 24
            $owningTraitFqn      = $this->getOwningRelationsRootFqn(
363 24
                $projectRootNamespace,
364 24
                $traitSubDirectories
365
            );
366 24
            $owningTraitFqn      .= $ownedClassName . '\\Traits\\Has' . $ownedHasName
367 24
                                    . '\\Has' . $ownedHasName . $this->stripPrefixFromHasType($hasType);
368
369 24
            return $this->tidy($owningTraitFqn);
370
        } catch (\Exception $e) {
371
            throw new DoctrineStaticMetaException(
372
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
373
                $e->getCode(),
374
                $e
375
            );
376
        }
377
    }
378
379
    /**
380
     * Based on the $hasType, we calculate exactly what type of `Has` we have
381
     *
382
     * @param string $hasType
383
     * @param string $ownedEntityFqn
384
     * @param string $srcOrTestSubFolder
385
     *
386
     * @param string $projectRootNamespace
387
     *
388
     * @return string
389
     * @SuppressWarnings(PHPMD.StaticAccess)
390
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
391
     */
392 24
    public function getOwnedHasName(
393
        string $hasType,
394
        string $ownedEntityFqn,
395
        string $srcOrTestSubFolder,
396
        string $projectRootNamespace
397
    ): string {
398 24
        $parsedFqn = $this->parseFullyQualifiedName(
399 24
            $ownedEntityFqn,
400 24
            $srcOrTestSubFolder,
401 24
            $projectRootNamespace
402
        );
403
404 24
        $subDirectories = $parsedFqn[2];
405
406 24
        if (\in_array(
407 24
            $hasType,
408 24
            RelationsGenerator::HAS_TYPES_PLURAL,
409 24
            true
410
        )) {
411 23
            return $this->getPluralNamespacedName($ownedEntityFqn, $subDirectories);
412
        }
413
414 8
        return $this->getSingularNamespacedName($ownedEntityFqn, $subDirectories);
415
    }
416
417
    /**
418
     * From the fully qualified name, parse out:
419
     *  - class name,
420
     *  - namespace
421
     *  - the namespace parts not including the project root namespace
422
     *
423
     * @param string      $fqn
424
     *
425
     * @param string      $srcOrTestSubFolder eg 'src' or 'test'
426
     *
427
     * @param string|null $projectRootNamespace
428
     *
429
     * @return array [$className,$namespace,$subDirectories]
430
     * @throws DoctrineStaticMetaException
431
     */
432 140
    public function parseFullyQualifiedName(
433
        string $fqn,
434
        string $srcOrTestSubFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER,
435
        string $projectRootNamespace = null
436
    ): array {
437
        try {
438 140
            $fqn = $this->root($fqn);
439 140
            if (null === $projectRootNamespace) {
440
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcOrTestSubFolder);
441
            }
442 140
            $projectRootNamespace = $this->root($projectRootNamespace);
443 140
            if (false === \ts\stringContains($fqn, $projectRootNamespace)) {
444
                throw new DoctrineStaticMetaException(
445
                    'The $fqn [' . $fqn . '] does not contain the project root namespace'
446
                    . ' [' . $projectRootNamespace . '] - are you sure it is the correct FQN?'
447
                );
448
            }
449 140
            $fqnParts       = explode('\\', $fqn);
450 140
            $className      = array_pop($fqnParts);
451 140
            $namespace      = implode('\\', $fqnParts);
452 140
            $rootParts      = explode('\\', $projectRootNamespace);
453 140
            $subDirectories = [];
454 140
            foreach ($fqnParts as $k => $fqnPart) {
455 140
                if (isset($rootParts[$k]) && $rootParts[$k] === $fqnPart) {
456 140
                    continue;
457
                }
458 140
                $subDirectories[] = $fqnPart;
459
            }
460 140
            array_unshift($subDirectories, $srcOrTestSubFolder);
461
462
            return [
463 140
                $className,
464 140
                $this->root($namespace),
465 140
                $subDirectories,
466
            ];
467
        } catch (\Exception $e) {
468
            throw new DoctrineStaticMetaException(
469
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
470
                $e->getCode(),
471
                $e
472
            );
473
        }
474
    }
475
476
    /**
477
     * Generate a tidy root namespace without a leading \
478
     *
479
     * @param string $namespace
480
     *
481
     * @return string
482
     */
483 140
    public function root(string $namespace): string
484
    {
485 140
        return $this->tidy(ltrim($namespace, '\\'));
486
    }
487
488
    /**
489
     * Read src autoloader from composer json
490
     *
491
     * @param string $dirForNamespace
492
     *
493
     * @return string
494
     * @throws DoctrineStaticMetaException
495
     * @SuppressWarnings(PHPMD.StaticAccess)
496
     */
497 141
    public function getProjectRootNamespaceFromComposerJson(
498
        string $dirForNamespace = 'src'
499
    ): string {
500
        try {
501 141
            $dirForNamespace = trim($dirForNamespace, '/');
502 141
            $json            = json_decode(
503 141
                \ts\file_get_contents(Config::getProjectRootDirectory() . '/composer.json'),
504 141
                true
505
            );
506
            /**
507
             * @var string[][][][] $json
508
             */
509 141
            if (isset($json['autoload']['psr-4'])) {
510 141
                foreach ($json['autoload']['psr-4'] as $namespace => $dirs) {
511 141
                    foreach ($dirs as $dir) {
512 141
                        $dir = trim($dir, '/');
513 141
                        if ($dir === $dirForNamespace) {
514 141
                            return $this->tidy(rtrim($namespace, '\\'));
515
                        }
516
                    }
517
                }
518
            }
519
        } catch (\Exception $e) {
520
            throw new DoctrineStaticMetaException(
521
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
522
                $e->getCode(),
523
                $e
524
            );
525
        }
526
        throw new DoctrineStaticMetaException('Failed to find psr-4 namespace root');
527
    }
528
529
    /**
530
     * @param string $entityFqn
531
     * @param array  $subDirectories
532
     *
533
     * @return string
534
     * @SuppressWarnings(PHPMD.StaticAccess)
535
     */
536 28
    public function getPluralNamespacedName(string $entityFqn, array $subDirectories): string
537
    {
538 28
        $plural = \ucfirst(MappingHelper::getPluralForFqn($entityFqn));
539
540 28
        return $this->getNamespacedName($plural, $subDirectories);
541
    }
542
543
    /**
544
     * @param string $entityName
545
     * @param array  $subDirectories
546
     *
547
     * @return string
548
     */
549 28
    public function getNamespacedName(string $entityName, array $subDirectories): string
550
    {
551 28
        $noEntitiesDirectory = \array_slice($subDirectories, 2);
552 28
        $namespacedName      = \array_merge($noEntitiesDirectory, [$entityName]);
553
554 28
        return \ucfirst(\implode('', $namespacedName));
555
    }
556
557
    /**
558
     * @param string $entityFqn
559
     * @param array  $subDirectories
560
     *
561
     * @return string
562
     * @SuppressWarnings(PHPMD.StaticAccess)
563
     */
564 28
    public function getSingularNamespacedName(string $entityFqn, array $subDirectories): string
565
    {
566 28
        $singular = \ucfirst(MappingHelper::getSingularForFqn($entityFqn));
567
568 28
        return $this->getNamespacedName($singular, $subDirectories);
569
    }
570
571
    /**
572
     * Get the Namespace root for Entity Relations
573
     *
574
     * @param string $projectRootNamespace
575
     * @param array  $subDirectories
576
     *
577
     * @return string
578
     */
579 24
    public function getOwningRelationsRootFqn(
580
        string $projectRootNamespace,
581
        array $subDirectories
582
    ): string {
583
        $relationsRootFqn = $projectRootNamespace
584 24
                            . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE . '\\';
585 24
        if (count($subDirectories) > 0) {
586 24
            $relationsRootFqn .= implode('\\', $subDirectories) . '\\';
587
        }
588
589 24
        return $this->tidy($relationsRootFqn);
590
    }
591
592
    /**
593
     * Normalise a has type, removing prefixes that are not required
594
     *
595
     * Inverse hasTypes use the standard template without the prefix
596
     * The exclusion ot this are the ManyToMany and OneToOne relations
597
     *
598
     * @param string $hasType
599
     *
600
     * @return string
601
     */
602 24
    public function stripPrefixFromHasType(
603
        string $hasType
604
    ): string {
605
        foreach ([
606 24
                     RelationsGenerator::INTERNAL_TYPE_MANY_TO_MANY,
607
                     RelationsGenerator::INTERNAL_TYPE_ONE_TO_ONE,
608
                 ] as $noStrip) {
609 24
            if (\ts\stringContains($hasType, $noStrip)) {
610 24
                return $hasType;
611
            }
612
        }
613
614
        foreach ([
615 6
                     RelationsGenerator::INTERNAL_TYPE_ONE_TO_MANY,
616
                     RelationsGenerator::INTERNAL_TYPE_MANY_TO_ONE,
617
                 ] as $stripAll) {
618 6
            if (\ts\stringContains($hasType, $stripAll)) {
619 6
                return str_replace(
620
                    [
621 6
                        RelationsGenerator::PREFIX_OWNING,
622
                        RelationsGenerator::PREFIX_INVERSE,
623
                    ],
624 6
                    '',
625 6
                    $hasType
626
                );
627
            }
628
        }
629
630
        return str_replace(
631
            [
632
                RelationsGenerator::PREFIX_INVERSE,
633
            ],
634
            '',
635
            $hasType
636
        );
637
    }
638
639
    /**
640
     * @param string $ownedEntityFqn
641
     * @param string $srcOrTestSubFolder
642
     * @param string $projectRootNamespace
643
     *
644
     * @return string
645
     * @throws \EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException
646
     */
647 24
    public function getReciprocatedHasName(
648
        string $ownedEntityFqn,
649
        string $srcOrTestSubFolder,
650
        string $projectRootNamespace
651
    ): string {
652 24
        $parsedFqn = $this->parseFullyQualifiedName(
653 24
            $ownedEntityFqn,
654 24
            $srcOrTestSubFolder,
655 24
            $projectRootNamespace
656
        );
657
658 24
        $subDirectories = $parsedFqn[2];
659
660 24
        return $this->getSingularNamespacedName($ownedEntityFqn, $subDirectories);
661
    }
662
663
    /**
664
     * Get the Fully Qualified Namespace for the Relation Interface for a specific Entity and hasType
665
     *
666
     * @param string      $hasType
667
     * @param string      $ownedEntityFqn
668
     * @param string|null $projectRootNamespace
669
     * @param string      $srcFolder
670
     *
671
     * @return string
672
     * @throws DoctrineStaticMetaException
673
     */
674 24
    public function getOwningInterfaceFqn(
675
        string $hasType,
676
        string $ownedEntityFqn,
677
        string $projectRootNamespace = null,
678
        string $srcFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER
679
    ): string {
680
        try {
681 24
            $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

681
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, /** @scrutinizer ignore-type */ $projectRootNamespace);
Loading history...
682 24
            if (null === $projectRootNamespace) {
683
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
684
            }
685 24
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
686 24
                $ownedEntityFqn,
687 24
                $srcFolder,
688 24
                $projectRootNamespace
689
            );
690 24
            $interfaceSubDirectories = \array_slice($ownedSubDirectories, 2);
691 24
            $owningInterfaceFqn      = $this->getOwningRelationsRootFqn(
692 24
                $projectRootNamespace,
693 24
                $interfaceSubDirectories
694
            );
695 24
            $owningInterfaceFqn      .= '\\' . $ownedClassName . '\\Interfaces\\Has' . $ownedHasName . 'Interface';
696
697 24
            return $this->tidy($owningInterfaceFqn);
698
        } catch (\Exception $e) {
699
            throw new DoctrineStaticMetaException(
700
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
701
                $e->getCode(),
702
                $e
703
            );
704
        }
705
    }
706
707 97
    public function getEntityInterfaceFromEntityFqn(string $entityFqn): string
708
    {
709 97
        return \str_replace(
710 97
                   '\\Entities\\',
711 97
                   '\\Entity\\Interfaces\\',
712 97
                   $entityFqn
713 97
               ) . 'Interface';
714
    }
715
}
716