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
Push — master ( c22d50...0bd9a0 )
by joseph
18s queued 11s
created

NamespaceHelper::getEntityInterfaceFromEntityFqn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

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

701
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, /** @scrutinizer ignore-type */ $projectRootNamespace);
Loading history...
702
            if (null === $projectRootNamespace) {
703
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
704
            }
705
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
706
                $ownedEntityFqn,
707
                $srcFolder,
708
                $projectRootNamespace
709
            );
710
            $interfaceSubDirectories = \array_slice($ownedSubDirectories, 2);
711
            $owningInterfaceFqn      = $this->getOwningRelationsRootFqn(
712
                $projectRootNamespace,
713
                $interfaceSubDirectories
714
            );
715
            $owningInterfaceFqn      .= '\\' . $ownedClassName . '\\Interfaces\\Has' . $ownedHasName . 'Interface';
716
717
            return $this->tidy($owningInterfaceFqn);
718
        } catch (\Exception $e) {
719
            throw new DoctrineStaticMetaException(
720
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
721
                $e->getCode(),
722
                $e
723
            );
724
        }
725
    }
726
727
    public function getEntityInterfaceFromEntityFqn(string $entityFqn): string
728
    {
729
        return \str_replace(
730
            '\\Entities\\',
731
            '\\Entity\\Interfaces\\',
732
            $entityFqn
733
        ) . 'Interface';
734
    }
735
}
736