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 (#224)
by joseph
22:25
created

getEntityFqnFromEntityDtoFactoryFqn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 10
ccs 8
cts 8
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
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
    public function getObjectShortName($object): string
105
    {
106
        return $this->getClassShortName($this->getObjectFqn($object));
107
    }
108
109
    /**
110
     * @param string $className
111
     *
112
     * @return string
113
     */
114
    public function getClassShortName(string $className): string
115
    {
116
        $exp = explode('\\', $className);
117
118
        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
    public function getObjectFqn($object): string
128
    {
129
        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
    public function basename(string $namespace): string
140
    {
141
        $strrpos = strrpos($namespace, '\\');
142
        if (false === $strrpos) {
143
            return $namespace;
144
        }
145
146
        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 8
    public function tidy(string $namespace): string
158
    {
159 8
        if (\ts\stringContains($namespace, '/')) {
160
            throw new RuntimeException('Invalid namespace ' . $namespace);
161
        }
162
        #remove repeated separators
163 8
        $namespace = preg_replace(
164 8
            '#' . '\\\\' . '+#',
165 8
            '\\',
166 8
            $namespace
167
        );
168
169 8
        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 2
    public function getFixtureFqnFromEntityFqn(string $entityFqn): string
180
    {
181 2
        return str_replace(
182 2
            '\\Entities',
183 2
            '\\Assets\\Entity\\Fixtures',
184 2
            $entityFqn
185 2
        ) . '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
    public function getEntityFileSubPath(
237
        string $entityFqn
238
    ): string {
239
        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
    public function getEntitySubPath(
252
        string $entityFqn
253
    ): string {
254
        $entityPath = str_replace(
255
            '\\',
256
            '/',
257
            $this->getEntitySubNamespace($entityFqn)
258
        );
259
260
        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
    public function getEntitySubNamespace(
272
        string $entityFqn
273
    ): string {
274
        return $this->tidy(
275
            substr(
276
                $entityFqn,
277
                strrpos(
278
                    $entityFqn,
279
                    '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\'
280
                )
281
                + 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
    public function getTraitsNamespaceForEntity(
294
        string $entityFqn
295
    ): string {
296
        $traitsNamespace = $this->getProjectNamespaceRootFromEntityFqn($entityFqn)
297
                           . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE
298
                           . '\\' . $this->getEntitySubNamespace($entityFqn)
299
                           . '\\Traits';
300
301
        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
    public function getProjectNamespaceRootFromEntityFqn(string $entityFqn): string
314
    {
315
        return $this->tidy(
316
            substr(
317
                $entityFqn,
318
                0,
319
                strrpos(
320
                    $entityFqn,
321
                    '\\' . 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
    public function getHasPluralInterfaceFqnForEntity(
335
        string $entityFqn
336
    ): string {
337
        $interfaceNamespace = $this->getInterfacesNamespaceForEntity($entityFqn);
338
339
        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
    public function getInterfacesNamespaceForEntity(
350
        string $entityFqn
351
    ): string {
352
        $interfacesNamespace = $this->getProjectNamespaceRootFromEntityFqn($entityFqn)
353
                               . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE
354
                               . '\\' . $this->getEntitySubNamespace($entityFqn)
355
                               . '\\Interfaces';
356
357
        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
    public function getHasSingularInterfaceFqnForEntity(
369
        string $entityFqn
370
    ): string {
371
        try {
372
            $interfaceNamespace = $this->getInterfacesNamespaceForEntity($entityFqn);
373
374
            return $interfaceNamespace . '\\Has' . ucfirst($entityFqn::getDoctrineStaticMeta()->getSingular())
375
                   . '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
    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
            $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
            if (null === $projectRootNamespace) {
405
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
406
            }
407
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
408
                $ownedEntityFqn,
409
                $srcFolder,
410
                $projectRootNamespace
411
            );
412
            $traitSubDirectories = array_slice($ownedSubDirectories, 2);
413
            $owningTraitFqn      = $this->getOwningRelationsRootFqn(
414
                $projectRootNamespace,
415
                $traitSubDirectories
416
            );
417
            $required            = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED)
418
                ? RelationsGenerator::PREFIX_REQUIRED
419
                : '';
420
            $owningTraitFqn      .= $ownedClassName . '\\Traits\\Has' . $required . $ownedHasName
421
                                    . '\\' . $this->getBaseHasTypeTraitFqn($ownedHasName, $hasType);
422
423
            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
    public function getOwnedHasName(
447
        string $hasType,
448
        string $ownedEntityFqn,
449
        string $srcOrTestSubFolder,
450
        string $projectRootNamespace
451
    ): string {
452
        $parsedFqn = $this->parseFullyQualifiedName(
453
            $ownedEntityFqn,
454
            $srcOrTestSubFolder,
455
            $projectRootNamespace
456
        );
457
458
        $subDirectories = $parsedFqn[2];
459
460
        if (
461
            in_array(
462
                $hasType,
463
                RelationsGenerator::HAS_TYPES_PLURAL,
464
                true
465
            )
466
        ) {
467
            return $this->getPluralNamespacedName($ownedEntityFqn, $subDirectories);
468
        }
469
470
        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
    public function parseFullyQualifiedName(
489
        string $fqn,
490
        string $srcOrTestSubFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER,
491
        string $projectRootNamespace = null
492
    ): array {
493
        try {
494
            $fqn = $this->root($fqn);
495
            if (null === $projectRootNamespace) {
496
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcOrTestSubFolder);
497
            }
498
            $projectRootNamespace = $this->root($projectRootNamespace);
499
            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
            $fqnParts       = explode('\\', $fqn);
506
            $className      = array_pop($fqnParts);
507
            $namespace      = implode('\\', $fqnParts);
508
            $rootParts      = explode('\\', $projectRootNamespace);
509
            $subDirectories = [];
510
            foreach ($fqnParts as $k => $fqnPart) {
511
                if (isset($rootParts[$k]) && $rootParts[$k] === $fqnPart) {
512
                    continue;
513
                }
514
                $subDirectories[] = $fqnPart;
515
            }
516
            array_unshift($subDirectories, $srcOrTestSubFolder);
517
518
            return [
519
                $className,
520
                $this->root($namespace),
521
                $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 2
    public function root(string $namespace): string
540
    {
541 2
        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
    public function getProjectRootNamespaceFromComposerJson(
554
        string $dirForNamespace = 'src'
555
    ): string {
556
        try {
557
            $dirForNamespace = trim($dirForNamespace, '/');
558
            $jsonPath        = Config::getProjectRootDirectory() . '/composer.json';
559
            $json            = json_decode(\ts\file_get_contents($jsonPath), true);
560
            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
            if (isset($json['autoload']['psr-4'])) {
569
                foreach ($json['autoload']['psr-4'] as $namespace => $dirs) {
570
                    if (!is_array($dirs)) {
571
                        $dirs = [$dirs];
572
                    }
573
                    foreach ($dirs as $dir) {
574
                        $dir = trim($dir, '/');
575
                        if ($dir === $dirForNamespace) {
576
                            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
    public function getPluralNamespacedName(string $entityFqn, array $subDirectories): string
599
    {
600
        $plural = ucfirst(MappingHelper::getPluralForFqn($entityFqn));
601
602
        return $this->getNamespacedName($plural, $subDirectories);
603
    }
604
605
    /**
606
     * @param string $entityName
607
     * @param array  $subDirectories
608
     *
609
     * @return string
610
     */
611
    public function getNamespacedName(string $entityName, array $subDirectories): string
612
    {
613
        $noEntitiesDirectory = array_slice($subDirectories, 2);
614
        $namespacedName      = array_merge($noEntitiesDirectory, [$entityName]);
615
616
        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
    public function getSingularNamespacedName(string $entityFqn, array $subDirectories): string
627
    {
628
        $singular = ucfirst(MappingHelper::getSingularForFqn($entityFqn));
629
630
        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
    public function getOwningRelationsRootFqn(
642
        string $projectRootNamespace,
643
        array $subDirectories
644
    ): string {
645
        $relationsRootFqn = $projectRootNamespace
646
                            . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE . '\\';
647
        if (count($subDirectories) > 0) {
648
            $relationsRootFqn .= implode('\\', $subDirectories) . '\\';
649
        }
650
651
        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
    public function getBaseHasTypeTraitFqn(
666
        string $ownedHasName,
667
        string $hasType
668
    ): string {
669
        $required = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED)
670
            ? RelationsGenerator::PREFIX_REQUIRED
671
            : '';
672
673
        $hasType = str_replace(RelationsGenerator::PREFIX_REQUIRED, '', $hasType);
674
        foreach (
675
            [
676
                     RelationsGenerator::INTERNAL_TYPE_MANY_TO_MANY,
677
                     RelationsGenerator::INTERNAL_TYPE_ONE_TO_ONE,
678
                 ] as $noStrip
679
        ) {
680
            if (\ts\stringContains($hasType, $noStrip)) {
681
                return 'Has' . $required . $ownedHasName . $hasType;
682
            }
683
        }
684
685
        foreach (
686
            [
687
                     RelationsGenerator::INTERNAL_TYPE_ONE_TO_MANY,
688
                     RelationsGenerator::INTERNAL_TYPE_MANY_TO_ONE,
689
                 ] as $stripAll
690
        ) {
691
            if (\ts\stringContains($hasType, $stripAll)) {
692
                return str_replace(
693
                    [
694
                        RelationsGenerator::PREFIX_OWNING,
695
                        RelationsGenerator::PREFIX_INVERSE,
696
                    ],
697
                    '',
698
                    '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 2
    public function getFactoryFqnFromEntityFqn(string $entityFqn): string
713
    {
714 2
        return $this->tidy(
715 2
            str_replace(
716 2
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
717 2
                '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE . '\\',
718 2
                $entityFqn
719 2
            ) . 'Factory'
720
        );
721
    }
722
723 2
    public function getDtoFactoryFqnFromEntityFqn(string $entityFqn): string
724
    {
725 2
        return $this->tidy(
726 2
            str_replace(
727 2
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
728 2
                '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE . '\\',
729 2
                $entityFqn
730 2
            ) . 'DtoFactory'
731
        );
732
    }
733
734
    public function getRepositoryqnFromEntityFqn(string $entityFqn): string
735
    {
736
        return $this->tidy(
737
            str_replace(
738
                '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\',
739
                '\\' . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE . '\\',
740
                $entityFqn
741
            ) . '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
    public function getReciprocatedHasName(
754
        string $ownedEntityFqn,
755
        string $srcOrTestSubFolder,
756
        string $projectRootNamespace
757
    ): string {
758
        $parsedFqn = $this->parseFullyQualifiedName(
759
            $ownedEntityFqn,
760
            $srcOrTestSubFolder,
761
            $projectRootNamespace
762
        );
763
764
        $subDirectories = $parsedFqn[2];
765
766
        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
    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
            $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
            if (null === $projectRootNamespace) {
789
                $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder);
790
            }
791
            list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName(
792
                $ownedEntityFqn,
793
                $srcFolder,
794
                $projectRootNamespace
795
            );
796
            $interfaceSubDirectories = array_slice($ownedSubDirectories, 2);
797
            $owningInterfaceFqn      = $this->getOwningRelationsRootFqn(
798
                $projectRootNamespace,
799
                $interfaceSubDirectories
800
            );
801
            $required                = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED)
802
                ? 'Required'
803
                : '';
804
            $owningInterfaceFqn      .= '\\' .
805
                                        $ownedClassName .
806
                                        '\\Interfaces\\Has' .
807
                                        $required .
808
                                        $ownedHasName .
809
                                        'Interface';
810
811
            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
    public function getEntityInterfaceFromEntityFqn(string $entityFqn): string
822
    {
823
        return str_replace(
824
            '\\Entities\\',
825
            '\\Entity\\Interfaces\\',
826
            $entityFqn
827
        ) . '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 2
    public function getEntityDtoFqnFromEntityFqn(string $entityFqn): string
870
    {
871 2
        return str_replace(
872 2
            '\\Entities\\',
873 2
            '\\Entity\\DataTransferObjects\\',
874 2
            $entityFqn
875 2
        ) . '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
    public function getEntitySaverFqnFromEntityFqn(string $entityFqn): string
917
    {
918
        return str_replace(
919
            '\\Entities\\',
920
            '\\Entity\\Savers\\',
921
            $entityFqn
922
        ) . '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 2
    public function getEntityUpserterFqnFromEntityFqn(string $entityFqn): string
939
    {
940 2
        return str_replace(
941 2
            '\\Entities\\',
942 2
            '\\Entity\\Savers\\',
943 2
            $entityFqn
944 2
        ) . '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 2
    public function getEntityUnitOfWorkHelperFqnFromEntityFqn(string $entityFqn): string
961
    {
962 2
        return str_replace(
963 2
            '\\Entities\\',
964 2
            '\\Entity\\Savers\\',
965 2
            $entityFqn
966 2
        ) . '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
    public function getEntityTestFqnFromEntityFqn(string $entityFqn): string
979
    {
980
        return $entityFqn . 'Test';
981
    }
982
}
983