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 (#199)
by joseph
19:04
created

getHasPluralInterfaceFqnForEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

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

736
            $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, /** @scrutinizer ignore-type */ $projectRootNamespace);
Loading history...
737
            if (null === $projectRootNamespace) {
738
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
739
            }
740
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
741
                $ownedEntityFqn,
742
                $srcFolder,
743
                $projectRootNamespace
744
            );
745
            $interfaceSubDirectories = \array_slice($ownedSubDirectories, 2);
746
            $owningInterfaceFqn      = $this->getOwningRelationsRootFqn(
747
                $projectRootNamespace,
748
                $interfaceSubDirectories
749
            );
750
            $required                = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED)
751
                ? 'Required'
752
                : '';
753
            $owningInterfaceFqn      .= '\\' .
754
                                        $ownedClassName .
755
                                        '\\Interfaces\\Has' .
756
                                        $required .
757
                                        $ownedHasName .
758
                                        'Interface';
759
760
            return $this->tidy($owningInterfaceFqn);
761
        } catch (\Exception $e) {
762
            throw new DoctrineStaticMetaException(
763
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
764
                $e->getCode(),
765
                $e
766
            );
767
        }
768
    }
769
770
    public function getEntityInterfaceFromEntityFqn(string $entityFqn): string
771
    {
772
        return \str_replace(
773
            '\\Entities\\',
774
            '\\Entity\\Interfaces\\',
775
            $entityFqn
776
        ) . 'Interface';
777
    }
778
779 2
    public function getEntityFqnFromEntityInterfaceFqn(string $entityInterfaceFqn): string
780
    {
781 2
        return substr(
782 2
            \str_replace(
783 2
                '\\Entity\\Interfaces\\',
784 2
                '\\Entities\\',
785 2
                $entityInterfaceFqn
786
            ),
787 2
            0,
788 2
            -\strlen('Interface')
789
        );
790
    }
791
792 2
    public function getEntityFqnFromEntityFactoryFqn(string $entityFactoryFqn): string
793
    {
794 2
        return substr(
795 2
            \str_replace(
796 2
                '\\Entity\\Factories\\',
797 2
                '\\Entities\\',
798 2
                $entityFactoryFqn
799
            ),
800 2
            0,
801 2
            -\strlen('Factory')
802
        );
803
    }
804
805 2
    public function getEntityFqnFromEntityDtoFactoryFqn(string $entityDtoFactoryFqn): string
806
    {
807 2
        return substr(
808 2
            \str_replace(
809 2
                '\\Entity\\Factories\\',
810 2
                '\\Entities\\',
811 2
                $entityDtoFactoryFqn
812
            ),
813 2
            0,
814 2
            -\strlen('DtoFactory')
815
        );
816
    }
817
818 2
    public function getEntityDtoFqnFromEntityFqn(string $entityFqn): string
819
    {
820 2
        return \str_replace(
821 2
            '\\Entities\\',
822 2
            '\\Entity\\DataTransferObjects\\',
823 2
            $entityFqn
824 2
        ) . 'Dto';
825
    }
826
827
    /**
828
     * @deprecated please use the static method on the DTO directly
829
     *
830
     * @param string $entityDtoFqn
831
     *
832
     * @return string
833
     */
834
    public function getEntityFqnFromEntityDtoFqn(string $entityDtoFqn): string
835
    {
836
        return $entityDtoFqn::getEntityFqn();
837
    }
838
839
    public function getEntityFqnFromEntityRepositoryFqn(string $entityRepositoryFqn): string
840
    {
841
        return substr(
842
            \str_replace(
843
                '\\Entity\\Repositories\\',
844
                '\\Entities\\',
845
                $entityRepositoryFqn
846
            ),
847
            0,
848
            -\strlen('Repository')
849
        );
850
    }
851
852
    public function getEntityFqnFromEntitySaverFqn(string $entitySaverFqn): string
853
    {
854
        return substr(
855
            \str_replace(
856
                '\\Entity\\Savers\\',
857
                '\\Entities\\',
858
                $entitySaverFqn
859
            ),
860
            0,
861
            -\strlen('Saver')
862
        );
863
    }
864
865
    public function getEntitySaverFqnFromEntityFqn(string $entityFqn): string
866
    {
867
        return \str_replace(
868
            '\\Entities\\',
869
            '\\Entity\\Savers\\',
870
            $entityFqn
871
        ) . 'Saver';
872
    }
873
874 2
    public function getEntityFqnFromEntityUpserterFqn(string $entityUpserterFqn): string
875
    {
876 2
        return substr(
877 2
            \str_replace(
878 2
                '\\Entity\\Savers\\',
879 2
                '\\Entities\\',
880 2
                $entityUpserterFqn
881
            ),
882 2
            0,
883 2
            -\strlen('Upserter')
884
        );
885
    }
886
887 2
    public function getEntityUpserterFqnFromEntityFqn(string $entityFqn): string
888
    {
889 2
        return \str_replace(
890 2
            '\\Entities\\',
891 2
            '\\Entity\\Savers\\',
892 2
            $entityFqn
893 2
        ) . 'Upserter';
894
    }
895
896 2
    public function getEntityFqnFromEntityUnitOfWorkHelperFqn(string $entityUnitofWorkHelperFqn): string
897
    {
898 2
        return substr(
899 2
            \str_replace(
900 2
                '\\Entity\\Savers\\',
901 2
                '\\Entities\\',
902 2
                $entityUnitofWorkHelperFqn
903
            ),
904 2
            0,
905 2
            -\strlen('UnitOfWorkHelper')
906
        );
907
    }
908
909 2
    public function getEntityUnitOfWorkHelperFqnFromEntityFqn(string $entityFqn): string
910
    {
911 2
        return \str_replace(
912 2
            '\\Entities\\',
913 2
            '\\Entity\\Savers\\',
914 2
            $entityFqn
915 2
        ) . 'UnitOfWorkHelper';
916
    }
917
918
    public function getEntityFqnFromEntityTestFqn(string $entityTestFqn): string
919
    {
920
        return \substr(
921
            $entityTestFqn,
922
            0,
923
            -\strlen('Test')
924
        );
925
    }
926
927
    public function getEntityTestFqnFromEntityFqn(string $entityFqn): string
928
    {
929
        return $entityFqn . 'Test';
930
    }
931
}
932