edmondscommerce /
doctrine-static-meta
| 1 | <?php |
||||
| 2 | |||||
| 3 | declare(strict_types=1); |
||||
| 4 | |||||
| 5 | namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration; |
||||
| 6 | |||||
| 7 | use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command\AbstractCommand; |
||||
| 8 | use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\AbstractGenerator; |
||||
| 9 | use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Generator\RelationsGenerator; |
||||
| 10 | use EdmondsCommerce\DoctrineStaticMeta\Config; |
||||
| 11 | use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException; |
||||
| 12 | use EdmondsCommerce\DoctrineStaticMeta\MappingHelper; |
||||
| 13 | use Exception; |
||||
| 14 | use RuntimeException; |
||||
| 15 | use SplFileInfo; |
||||
| 16 | use Symfony\Component\Finder\Finder; |
||||
| 17 | |||||
| 18 | use function array_merge; |
||||
| 19 | use function array_slice; |
||||
| 20 | use function get_class; |
||||
| 21 | use function implode; |
||||
| 22 | use function in_array; |
||||
| 23 | use function str_replace; |
||||
| 24 | use function strlen; |
||||
| 25 | use function strrpos; |
||||
| 26 | use function substr; |
||||
| 27 | use function ucfirst; |
||||
| 28 | |||||
| 29 | /** |
||||
| 30 | * Class NamespaceHelper |
||||
| 31 | * |
||||
| 32 | * Pure functions for working with namespaces and to calculate namespaces |
||||
| 33 | * |
||||
| 34 | * @package EdmondsCommerce\DoctrineStaticMeta\CodeGeneration |
||||
| 35 | * @SuppressWarnings(PHPMD.TooManyPublicMethods) |
||||
| 36 | * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) |
||||
| 37 | * @SuppressWarnings(PHPMD.ExcessivePublicCount) |
||||
| 38 | */ |
||||
| 39 | class NamespaceHelper |
||||
| 40 | { |
||||
| 41 | 2 | public function getAllArchetypeFieldFqns(): array |
|||
| 42 | { |
||||
| 43 | 2 | $archetypeFqns = []; |
|||
| 44 | 2 | $namespaceBase = 'EdmondsCommerce\\DoctrineStaticMeta\\Entity\\Fields\\Traits'; |
|||
| 45 | 2 | $finder = (new Finder())->files() |
|||
| 46 | 2 | ->name('*.php') |
|||
| 47 | 2 | ->in(__DIR__ . '/../Entity/Fields/Traits/'); |
|||
| 48 | 2 | foreach ($finder as $file) { |
|||
| 49 | /** @var SplFileInfo $file */ |
||||
| 50 | 2 | $realpath = $file->getRealPath(); |
|||
| 51 | 2 | if (\ts\stringContains($realpath, '/PrimaryKey/')) { |
|||
| 52 | 2 | continue; |
|||
| 53 | } |
||||
| 54 | 2 | $subPath = substr( |
|||
| 55 | 2 | $realpath, |
|||
| 56 | 2 | strpos($realpath, 'Entity/Fields/Traits/') + strlen('Entity/Fields/Traits/') |
|||
| 57 | ); |
||||
| 58 | 2 | $subPath = substr($subPath, 0, -4); |
|||
| 59 | 2 | $subFqn = str_replace('/', '\\', $subPath); |
|||
| 60 | 2 | $archetypeFqns[] = $namespaceBase . '\\' . $subFqn; |
|||
| 61 | } |
||||
| 62 | |||||
| 63 | 2 | return $archetypeFqns; |
|||
| 64 | } |
||||
| 65 | |||||
| 66 | 2 | public function swapSuffix(string $fqn, string $currentSuffix, string $newSuffix): string |
|||
| 67 | { |
||||
| 68 | 2 | return $this->cropSuffix($fqn, $currentSuffix) . $newSuffix; |
|||
| 69 | } |
||||
| 70 | |||||
| 71 | /** |
||||
| 72 | * Crop a suffix from an FQN if it is there. |
||||
| 73 | * |
||||
| 74 | * If it is not there, do nothing and return the FQN as is |
||||
| 75 | * |
||||
| 76 | * @param string $fqn |
||||
| 77 | * @param string $suffix |
||||
| 78 | * |
||||
| 79 | * @return string |
||||
| 80 | */ |
||||
| 81 | 6 | public function cropSuffix(string $fqn, string $suffix): string |
|||
| 82 | { |
||||
| 83 | 6 | if ($suffix === substr($fqn, -strlen($suffix))) { |
|||
| 84 | 4 | return substr($fqn, 0, -strlen($suffix)); |
|||
| 85 | } |
||||
| 86 | |||||
| 87 | 2 | return $fqn; |
|||
| 88 | } |
||||
| 89 | |||||
| 90 | 2 | public function getEmbeddableObjectFqnFromEmbeddableObjectInterfaceFqn(string $interfaceFqn): string |
|||
| 91 | { |
||||
| 92 | 2 | return str_replace( |
|||
| 93 | 2 | ['\\Interfaces\\', 'Interface'], |
|||
| 94 | 2 | ['\\', ''], |
|||
| 95 | 2 | $interfaceFqn |
|||
| 96 | ); |
||||
| 97 | } |
||||
| 98 | |||||
| 99 | /** |
||||
| 100 | * @param mixed|object $object |
||||
| 101 | * |
||||
| 102 | * @return string |
||||
| 103 | */ |
||||
| 104 | 1 | public function getObjectShortName($object): string |
|||
| 105 | { |
||||
| 106 | 1 | return $this->getClassShortName($this->getObjectFqn($object)); |
|||
| 107 | } |
||||
| 108 | |||||
| 109 | /** |
||||
| 110 | * @param string $className |
||||
| 111 | * |
||||
| 112 | * @return string |
||||
| 113 | */ |
||||
| 114 | 2 | public function getClassShortName(string $className): string |
|||
| 115 | { |
||||
| 116 | 2 | $exp = explode('\\', $className); |
|||
| 117 | |||||
| 118 | 2 | return end($exp); |
|||
| 119 | } |
||||
| 120 | |||||
| 121 | /** |
||||
| 122 | * @param mixed|object $object |
||||
| 123 | * |
||||
| 124 | * @return string |
||||
| 125 | * @see https://gist.github.com/ludofleury/1708784 |
||||
| 126 | */ |
||||
| 127 | 2 | public function getObjectFqn($object): string |
|||
| 128 | { |
||||
| 129 | 2 | return get_class($object); |
|||
| 130 | } |
||||
| 131 | |||||
| 132 | /** |
||||
| 133 | * Get the basename of a namespace |
||||
| 134 | * |
||||
| 135 | * @param string $namespace |
||||
| 136 | * |
||||
| 137 | * @return string |
||||
| 138 | */ |
||||
| 139 | 1 | public function basename(string $namespace): string |
|||
| 140 | { |
||||
| 141 | 1 | $strrpos = strrpos($namespace, '\\'); |
|||
| 142 | 1 | if (false === $strrpos) { |
|||
| 143 | return $namespace; |
||||
| 144 | } |
||||
| 145 | |||||
| 146 | 1 | return $this->tidy(substr($namespace, $strrpos + 1)); |
|||
| 147 | } |
||||
| 148 | |||||
| 149 | /** |
||||
| 150 | * Checks and tidies up a given namespace |
||||
| 151 | * |
||||
| 152 | * @param string $namespace |
||||
| 153 | * |
||||
| 154 | * @return string |
||||
| 155 | * @throws RuntimeException |
||||
| 156 | */ |
||||
| 157 | 24 | public function tidy(string $namespace): string |
|||
| 158 | { |
||||
| 159 | 24 | if (\ts\stringContains($namespace, '/')) { |
|||
| 160 | throw new RuntimeException('Invalid namespace ' . $namespace); |
||||
| 161 | } |
||||
| 162 | #remove repeated separators |
||||
| 163 | 24 | $namespace = preg_replace( |
|||
| 164 | 24 | '#' . '\\\\' . '+#', |
|||
| 165 | 24 | '\\', |
|||
| 166 | 24 | $namespace |
|||
| 167 | ); |
||||
| 168 | |||||
| 169 | 24 | return $namespace; |
|||
| 170 | } |
||||
| 171 | |||||
| 172 | /** |
||||
| 173 | * Get the fully qualified name of the Fixture class for a specified Entity fully qualified name |
||||
| 174 | * |
||||
| 175 | * @param string $entityFqn |
||||
| 176 | * |
||||
| 177 | * @return string |
||||
| 178 | */ |
||||
| 179 | 3 | public function getFixtureFqnFromEntityFqn(string $entityFqn): string |
|||
| 180 | { |
||||
| 181 | 3 | return str_replace( |
|||
| 182 | 3 | '\\Entities', |
|||
| 183 | 3 | '\\Assets\\Entity\\Fixtures', |
|||
| 184 | 3 | $entityFqn |
|||
| 185 | 3 | ) . 'Fixture'; |
|||
| 186 | } |
||||
| 187 | |||||
| 188 | /** |
||||
| 189 | * Get the fully qualified name of the Entity for a specified Entity fully qualified name |
||||
| 190 | * |
||||
| 191 | * @param string $fixtureFqn |
||||
| 192 | * |
||||
| 193 | * @return string |
||||
| 194 | */ |
||||
| 195 | public function getEntityFqnFromFixtureFqn(string $fixtureFqn): string |
||||
| 196 | { |
||||
| 197 | return substr( |
||||
| 198 | str_replace( |
||||
| 199 | '\\Assets\\Entity\\Fixtures', |
||||
| 200 | '\\Entities', |
||||
| 201 | $fixtureFqn |
||||
| 202 | ), |
||||
| 203 | 0, |
||||
| 204 | -strlen('Fixture') |
||||
| 205 | ); |
||||
| 206 | } |
||||
| 207 | |||||
| 208 | /** |
||||
| 209 | * Get the namespace root up to and including a specified directory |
||||
| 210 | * |
||||
| 211 | * @param string $fqn |
||||
| 212 | * @param string $directory |
||||
| 213 | * |
||||
| 214 | * @return null|string |
||||
| 215 | */ |
||||
| 216 | public function getNamespaceRootToDirectoryFromFqn(string $fqn, string $directory): ?string |
||||
| 217 | { |
||||
| 218 | $strPos = strrpos( |
||||
| 219 | $fqn, |
||||
| 220 | $directory |
||||
| 221 | ); |
||||
| 222 | if (false !== $strPos) { |
||||
| 223 | return $this->tidy(substr($fqn, 0, $strPos + strlen($directory))); |
||||
| 224 | } |
||||
| 225 | |||||
| 226 | return null; |
||||
| 227 | } |
||||
| 228 | |||||
| 229 | /** |
||||
| 230 | * Get the sub path for an Entity file, start from the Entities path - normally `/path/to/project/src/Entities` |
||||
| 231 | * |
||||
| 232 | * @param string $entityFqn |
||||
| 233 | * |
||||
| 234 | * @return string |
||||
| 235 | */ |
||||
| 236 | 1 | public function getEntityFileSubPath( |
|||
| 237 | string $entityFqn |
||||
| 238 | ): string { |
||||
| 239 | 1 | return $this->getEntitySubPath($entityFqn) . '.php'; |
|||
| 240 | } |
||||
| 241 | |||||
| 242 | /** |
||||
| 243 | * Get the folder structure for an Entity, start from the Entities path - normally `/path/to/project/src/Entities` |
||||
| 244 | * |
||||
| 245 | * This is not the path to the file, but the sub path of directories for storing entity related items. |
||||
| 246 | * |
||||
| 247 | * @param string $entityFqn |
||||
| 248 | * |
||||
| 249 | * @return string |
||||
| 250 | */ |
||||
| 251 | 2 | public function getEntitySubPath( |
|||
| 252 | string $entityFqn |
||||
| 253 | ): string { |
||||
| 254 | 2 | $entityPath = str_replace( |
|||
| 255 | 2 | '\\', |
|||
| 256 | 2 | '/', |
|||
| 257 | 2 | $this->getEntitySubNamespace($entityFqn) |
|||
| 258 | ); |
||||
| 259 | |||||
| 260 | 2 | return '/' . $entityPath; |
|||
| 261 | } |
||||
| 262 | |||||
| 263 | /** |
||||
| 264 | * Get the Namespace for an Entity, start from the Entities Fully Qualified Name base - normally |
||||
| 265 | * `\My\Project\Entities\` |
||||
| 266 | * |
||||
| 267 | * @param string $entityFqn |
||||
| 268 | * |
||||
| 269 | * @return string |
||||
| 270 | */ |
||||
| 271 | 7 | public function getEntitySubNamespace( |
|||
| 272 | string $entityFqn |
||||
| 273 | ): string { |
||||
| 274 | 7 | return $this->tidy( |
|||
| 275 | 7 | substr( |
|||
| 276 | 7 | $entityFqn, |
|||
| 277 | 7 | strrpos( |
|||
| 278 | 7 | $entityFqn, |
|||
| 279 | 7 | '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\' |
|||
| 280 | ) |
||||
| 281 | 7 | + strlen('\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\') |
|||
| 282 | ) |
||||
| 283 | ); |
||||
| 284 | } |
||||
| 285 | |||||
| 286 | /** |
||||
| 287 | * Get the Fully Qualified Namespace root for Traits for the specified Entity |
||||
| 288 | * |
||||
| 289 | * @param string $entityFqn |
||||
| 290 | * |
||||
| 291 | * @return string |
||||
| 292 | */ |
||||
| 293 | 1 | public function getTraitsNamespaceForEntity( |
|||
| 294 | string $entityFqn |
||||
| 295 | ): string { |
||||
| 296 | 1 | $traitsNamespace = $this->getProjectNamespaceRootFromEntityFqn($entityFqn) |
|||
| 297 | 1 | . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE |
|||
| 298 | 1 | . '\\' . $this->getEntitySubNamespace($entityFqn) |
|||
| 299 | 1 | . '\\Traits'; |
|||
| 300 | |||||
| 301 | 1 | return $traitsNamespace; |
|||
| 302 | } |
||||
| 303 | |||||
| 304 | /** |
||||
| 305 | * Use the fully qualified name of two Entities to calculate the Project Namespace Root |
||||
| 306 | * |
||||
| 307 | * - note: this assumes a single namespace level for entities, eg `Entities` |
||||
| 308 | * |
||||
| 309 | * @param string $entityFqn |
||||
| 310 | * |
||||
| 311 | * @return string |
||||
| 312 | */ |
||||
| 313 | 5 | public function getProjectNamespaceRootFromEntityFqn(string $entityFqn): string |
|||
| 314 | { |
||||
| 315 | 5 | return $this->tidy( |
|||
| 316 | 5 | substr( |
|||
| 317 | 5 | $entityFqn, |
|||
| 318 | 5 | 0, |
|||
| 319 | 5 | strrpos( |
|||
| 320 | 5 | $entityFqn, |
|||
| 321 | 5 | '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\' |
|||
| 322 | ) |
||||
| 323 | ) |
||||
| 324 | ); |
||||
| 325 | } |
||||
| 326 | |||||
| 327 | /** |
||||
| 328 | * Get the Fully Qualified Namespace for the "HasEntities" interface for the specified Entity |
||||
| 329 | * |
||||
| 330 | * @param string $entityFqn |
||||
| 331 | * |
||||
| 332 | * @return string |
||||
| 333 | */ |
||||
| 334 | 1 | public function getHasPluralInterfaceFqnForEntity( |
|||
| 335 | string $entityFqn |
||||
| 336 | ): string { |
||||
| 337 | 1 | $interfaceNamespace = $this->getInterfacesNamespaceForEntity($entityFqn); |
|||
| 338 | |||||
| 339 | 1 | return $interfaceNamespace . '\\Has' . ucfirst($entityFqn::getDoctrineStaticMeta()->getPlural()) . 'Interface'; |
|||
| 340 | } |
||||
| 341 | |||||
| 342 | /** |
||||
| 343 | * Get the Fully Qualified Namespace root for Interfaces for the specified Entity |
||||
| 344 | * |
||||
| 345 | * @param string $entityFqn |
||||
| 346 | * |
||||
| 347 | * @return string |
||||
| 348 | */ |
||||
| 349 | 3 | public function getInterfacesNamespaceForEntity( |
|||
| 350 | string $entityFqn |
||||
| 351 | ): string { |
||||
| 352 | 3 | $interfacesNamespace = $this->getProjectNamespaceRootFromEntityFqn($entityFqn) |
|||
| 353 | 3 | . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE |
|||
| 354 | 3 | . '\\' . $this->getEntitySubNamespace($entityFqn) |
|||
| 355 | 3 | . '\\Interfaces'; |
|||
| 356 | |||||
| 357 | 3 | return $this->tidy($interfacesNamespace); |
|||
| 358 | } |
||||
| 359 | |||||
| 360 | /** |
||||
| 361 | * Get the Fully Qualified Namespace for the "HasEntity" interface for the specified Entity |
||||
| 362 | * |
||||
| 363 | * @param string $entityFqn |
||||
| 364 | * |
||||
| 365 | * @return string |
||||
| 366 | * @throws DoctrineStaticMetaException |
||||
| 367 | */ |
||||
| 368 | 1 | public function getHasSingularInterfaceFqnForEntity( |
|||
| 369 | string $entityFqn |
||||
| 370 | ): string { |
||||
| 371 | try { |
||||
| 372 | 1 | $interfaceNamespace = $this->getInterfacesNamespaceForEntity($entityFqn); |
|||
| 373 | |||||
| 374 | 1 | return $interfaceNamespace . '\\Has' . ucfirst($entityFqn::getDoctrineStaticMeta()->getSingular()) |
|||
| 375 | 1 | . 'Interface'; |
|||
| 376 | } catch (Exception $e) { |
||||
| 377 | throw new DoctrineStaticMetaException( |
||||
| 378 | 'Exception in ' . __METHOD__ . ': ' . $e->getMessage(), |
||||
| 379 | $e->getCode(), |
||||
| 380 | $e |
||||
| 381 | ); |
||||
| 382 | } |
||||
| 383 | } |
||||
| 384 | |||||
| 385 | /** |
||||
| 386 | * Get the Fully Qualified Namespace for the Relation Trait for a specific Entity and hasType |
||||
| 387 | * |
||||
| 388 | * @param string $hasType |
||||
| 389 | * @param string $ownedEntityFqn |
||||
| 390 | * @param string|null $projectRootNamespace |
||||
| 391 | * @param string $srcFolder |
||||
| 392 | * |
||||
| 393 | * @return string |
||||
| 394 | * @throws DoctrineStaticMetaException |
||||
| 395 | */ |
||||
| 396 | 2 | public function getOwningTraitFqn( |
|||
| 397 | string $hasType, |
||||
| 398 | string $ownedEntityFqn, |
||||
| 399 | ?string $projectRootNamespace = null, |
||||
| 400 | string $srcFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER |
||||
| 401 | ): string { |
||||
| 402 | try { |
||||
| 403 | 2 | $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, $projectRootNamespace); |
|||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 404 | 2 | if (null === $projectRootNamespace) { |
|||
| 405 | $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder); |
||||
| 406 | } |
||||
| 407 | 2 | list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName( |
|||
| 408 | 2 | $ownedEntityFqn, |
|||
| 409 | 2 | $srcFolder, |
|||
| 410 | 2 | $projectRootNamespace |
|||
| 411 | ); |
||||
| 412 | 2 | $traitSubDirectories = array_slice($ownedSubDirectories, 2); |
|||
| 413 | 2 | $owningTraitFqn = $this->getOwningRelationsRootFqn( |
|||
| 414 | 2 | $projectRootNamespace, |
|||
| 415 | 2 | $traitSubDirectories |
|||
| 416 | ); |
||||
| 417 | 2 | $required = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED) |
|||
| 418 | 1 | ? RelationsGenerator::PREFIX_REQUIRED |
|||
| 419 | 2 | : ''; |
|||
| 420 | 2 | $owningTraitFqn .= $ownedClassName . '\\Traits\\Has' . $required . $ownedHasName |
|||
| 421 | 2 | . '\\' . $this->getBaseHasTypeTraitFqn($ownedHasName, $hasType); |
|||
| 422 | |||||
| 423 | 2 | return $this->tidy($owningTraitFqn); |
|||
| 424 | } catch (Exception $e) { |
||||
| 425 | throw new DoctrineStaticMetaException( |
||||
| 426 | 'Exception in ' . __METHOD__ . ': ' . $e->getMessage(), |
||||
| 427 | $e->getCode(), |
||||
| 428 | $e |
||||
| 429 | ); |
||||
| 430 | } |
||||
| 431 | } |
||||
| 432 | |||||
| 433 | /** |
||||
| 434 | * Based on the $hasType, we calculate exactly what type of `Has` we have |
||||
| 435 | * |
||||
| 436 | * @param string $hasType |
||||
| 437 | * @param string $ownedEntityFqn |
||||
| 438 | * @param string $srcOrTestSubFolder |
||||
| 439 | * |
||||
| 440 | * @param string $projectRootNamespace |
||||
| 441 | * |
||||
| 442 | * @return string |
||||
| 443 | * @SuppressWarnings(PHPMD.StaticAccess) |
||||
| 444 | * @throws DoctrineStaticMetaException |
||||
| 445 | */ |
||||
| 446 | 4 | public function getOwnedHasName( |
|||
| 447 | string $hasType, |
||||
| 448 | string $ownedEntityFqn, |
||||
| 449 | string $srcOrTestSubFolder, |
||||
| 450 | string $projectRootNamespace |
||||
| 451 | ): string { |
||||
| 452 | 4 | $parsedFqn = $this->parseFullyQualifiedName( |
|||
| 453 | 4 | $ownedEntityFqn, |
|||
| 454 | 4 | $srcOrTestSubFolder, |
|||
| 455 | 4 | $projectRootNamespace |
|||
| 456 | ); |
||||
| 457 | |||||
| 458 | 4 | $subDirectories = $parsedFqn[2]; |
|||
| 459 | |||||
| 460 | if ( |
||||
| 461 | 4 | in_array( |
|||
| 462 | 4 | $hasType, |
|||
| 463 | 4 | RelationsGenerator::HAS_TYPES_PLURAL, |
|||
| 464 | 4 | true |
|||
| 465 | ) |
||||
| 466 | ) { |
||||
| 467 | 4 | return $this->getPluralNamespacedName($ownedEntityFqn, $subDirectories); |
|||
| 468 | } |
||||
| 469 | |||||
| 470 | 2 | return $this->getSingularNamespacedName($ownedEntityFqn, $subDirectories); |
|||
| 471 | } |
||||
| 472 | |||||
| 473 | /** |
||||
| 474 | * From the fully qualified name, parse out: |
||||
| 475 | * - class name, |
||||
| 476 | * - namespace |
||||
| 477 | * - the namespace parts not including the project root namespace |
||||
| 478 | * |
||||
| 479 | * @param string $fqn |
||||
| 480 | * |
||||
| 481 | * @param string $srcOrTestSubFolder eg 'src' or 'test' |
||||
| 482 | * |
||||
| 483 | * @param string|null $projectRootNamespace |
||||
| 484 | * |
||||
| 485 | * @return array [$className,$namespace,$subDirectories] |
||||
| 486 | * @throws DoctrineStaticMetaException |
||||
| 487 | */ |
||||
| 488 | 5 | public function parseFullyQualifiedName( |
|||
| 489 | string $fqn, |
||||
| 490 | string $srcOrTestSubFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER, |
||||
| 491 | string $projectRootNamespace = null |
||||
| 492 | ): array { |
||||
| 493 | try { |
||||
| 494 | 5 | $fqn = $this->root($fqn); |
|||
| 495 | 5 | if (null === $projectRootNamespace) { |
|||
| 496 | $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcOrTestSubFolder); |
||||
| 497 | } |
||||
| 498 | 5 | $projectRootNamespace = $this->root($projectRootNamespace); |
|||
| 499 | 5 | if (false === \ts\stringContains($fqn, $projectRootNamespace)) { |
|||
|
0 ignored issues
–
show
|
|||||
| 500 | throw new DoctrineStaticMetaException( |
||||
| 501 | 'The $fqn [' . $fqn . '] does not contain the project root namespace' |
||||
| 502 | . ' [' . $projectRootNamespace . '] - are you sure it is the correct FQN?' |
||||
| 503 | ); |
||||
| 504 | } |
||||
| 505 | 5 | $fqnParts = explode('\\', $fqn); |
|||
| 506 | 5 | $className = array_pop($fqnParts); |
|||
| 507 | 5 | $namespace = implode('\\', $fqnParts); |
|||
| 508 | 5 | $rootParts = explode('\\', $projectRootNamespace); |
|||
| 509 | 5 | $subDirectories = []; |
|||
| 510 | 5 | foreach ($fqnParts as $k => $fqnPart) { |
|||
| 511 | 5 | if (isset($rootParts[$k]) && $rootParts[$k] === $fqnPart) { |
|||
| 512 | 5 | continue; |
|||
| 513 | } |
||||
| 514 | 5 | $subDirectories[] = $fqnPart; |
|||
| 515 | } |
||||
| 516 | 5 | array_unshift($subDirectories, $srcOrTestSubFolder); |
|||
| 517 | |||||
| 518 | return [ |
||||
| 519 | 5 | $className, |
|||
| 520 | 5 | $this->root($namespace), |
|||
| 521 | 5 | $subDirectories, |
|||
| 522 | ]; |
||||
| 523 | } catch (Exception $e) { |
||||
| 524 | throw new DoctrineStaticMetaException( |
||||
| 525 | 'Exception in ' . __METHOD__ . ': ' . $e->getMessage(), |
||||
| 526 | $e->getCode(), |
||||
| 527 | $e |
||||
| 528 | ); |
||||
| 529 | } |
||||
| 530 | } |
||||
| 531 | |||||
| 532 | /** |
||||
| 533 | * Generate a tidy root namespace without a leading \ |
||||
| 534 | * |
||||
| 535 | * @param string $namespace |
||||
| 536 | * |
||||
| 537 | * @return string |
||||
| 538 | */ |
||||
| 539 | 7 | public function root(string $namespace): string |
|||
| 540 | { |
||||
| 541 | 7 | return $this->tidy(ltrim($namespace, '\\')); |
|||
| 542 | } |
||||
| 543 | |||||
| 544 | /** |
||||
| 545 | * Read src autoloader from composer json |
||||
| 546 | * |
||||
| 547 | * @param string $dirForNamespace |
||||
| 548 | * |
||||
| 549 | * @return string |
||||
| 550 | * @throws DoctrineStaticMetaException |
||||
| 551 | * @SuppressWarnings(PHPMD.StaticAccess) |
||||
| 552 | */ |
||||
| 553 | 16 | public function getProjectRootNamespaceFromComposerJson( |
|||
| 554 | string $dirForNamespace = 'src' |
||||
| 555 | ): string { |
||||
| 556 | try { |
||||
| 557 | 16 | $dirForNamespace = trim($dirForNamespace, '/'); |
|||
| 558 | 16 | $jsonPath = Config::getProjectRootDirectory() . '/composer.json'; |
|||
| 559 | 16 | $json = json_decode(\ts\file_get_contents($jsonPath), true); |
|||
| 560 | 16 | if (JSON_ERROR_NONE !== json_last_error()) { |
|||
| 561 | throw new RuntimeException( |
||||
| 562 | 'Error decoding json from path ' . $jsonPath . ' , ' . json_last_error_msg() |
||||
| 563 | ); |
||||
| 564 | } |
||||
| 565 | /** |
||||
| 566 | * @var string[][][][] $json |
||||
| 567 | */ |
||||
| 568 | 16 | if (isset($json['autoload']['psr-4'])) { |
|||
| 569 | 16 | foreach ($json['autoload']['psr-4'] as $namespace => $dirs) { |
|||
| 570 | 16 | if (!is_array($dirs)) { |
|||
| 571 | $dirs = [$dirs]; |
||||
| 572 | } |
||||
| 573 | 16 | foreach ($dirs as $dir) { |
|||
| 574 | 16 | $dir = trim($dir, '/'); |
|||
| 575 | 16 | if ($dir === $dirForNamespace) { |
|||
| 576 | 16 | return $this->tidy(rtrim($namespace, '\\')); |
|||
| 577 | } |
||||
| 578 | } |
||||
| 579 | } |
||||
| 580 | } |
||||
| 581 | } catch (Exception $e) { |
||||
| 582 | throw new DoctrineStaticMetaException( |
||||
| 583 | 'Exception in ' . __METHOD__ . ': ' . $e->getMessage(), |
||||
| 584 | $e->getCode(), |
||||
| 585 | $e |
||||
| 586 | ); |
||||
| 587 | } |
||||
| 588 | throw new DoctrineStaticMetaException('Failed to find psr-4 namespace root'); |
||||
| 589 | } |
||||
| 590 | |||||
| 591 | /** |
||||
| 592 | * @param string $entityFqn |
||||
| 593 | * @param array $subDirectories |
||||
| 594 | * |
||||
| 595 | * @return string |
||||
| 596 | * @SuppressWarnings(PHPMD.StaticAccess) |
||||
| 597 | */ |
||||
| 598 | 4 | public function getPluralNamespacedName(string $entityFqn, array $subDirectories): string |
|||
| 599 | { |
||||
| 600 | 4 | $plural = ucfirst(MappingHelper::getPluralForFqn($entityFqn)); |
|||
| 601 | |||||
| 602 | 4 | return $this->getNamespacedName($plural, $subDirectories); |
|||
| 603 | } |
||||
| 604 | |||||
| 605 | /** |
||||
| 606 | * @param string $entityName |
||||
| 607 | * @param array $subDirectories |
||||
| 608 | * |
||||
| 609 | * @return string |
||||
| 610 | */ |
||||
| 611 | 4 | public function getNamespacedName(string $entityName, array $subDirectories): string |
|||
| 612 | { |
||||
| 613 | 4 | $noEntitiesDirectory = array_slice($subDirectories, 2); |
|||
| 614 | 4 | $namespacedName = array_merge($noEntitiesDirectory, [$entityName]); |
|||
| 615 | |||||
| 616 | 4 | return ucfirst(implode('', $namespacedName)); |
|||
| 617 | } |
||||
| 618 | |||||
| 619 | /** |
||||
| 620 | * @param string $entityFqn |
||||
| 621 | * @param array $subDirectories |
||||
| 622 | * |
||||
| 623 | * @return string |
||||
| 624 | * @SuppressWarnings(PHPMD.StaticAccess) |
||||
| 625 | */ |
||||
| 626 | 3 | public function getSingularNamespacedName(string $entityFqn, array $subDirectories): string |
|||
| 627 | { |
||||
| 628 | 3 | $singular = ucfirst(MappingHelper::getSingularForFqn($entityFqn)); |
|||
| 629 | |||||
| 630 | 3 | return $this->getNamespacedName($singular, $subDirectories); |
|||
| 631 | } |
||||
| 632 | |||||
| 633 | /** |
||||
| 634 | * Get the Namespace root for Entity Relations |
||||
| 635 | * |
||||
| 636 | * @param string $projectRootNamespace |
||||
| 637 | * @param array $subDirectories |
||||
| 638 | * |
||||
| 639 | * @return string |
||||
| 640 | */ |
||||
| 641 | 3 | public function getOwningRelationsRootFqn( |
|||
| 642 | string $projectRootNamespace, |
||||
| 643 | array $subDirectories |
||||
| 644 | ): string { |
||||
| 645 | $relationsRootFqn = $projectRootNamespace |
||||
| 646 | 3 | . AbstractGenerator::ENTITY_RELATIONS_NAMESPACE . '\\'; |
|||
| 647 | 3 | if (count($subDirectories) > 0) { |
|||
| 648 | 1 | $relationsRootFqn .= implode('\\', $subDirectories) . '\\'; |
|||
| 649 | } |
||||
| 650 | |||||
| 651 | 3 | return $this->tidy($relationsRootFqn); |
|||
| 652 | } |
||||
| 653 | |||||
| 654 | /** |
||||
| 655 | * Normalise a has type, removing prefixes that are not required |
||||
| 656 | * |
||||
| 657 | * Inverse hasTypes use the standard template without the prefix |
||||
| 658 | * The exclusion ot this are the ManyToMany and OneToOne relations |
||||
| 659 | * |
||||
| 660 | * @param string $ownedHasName |
||||
| 661 | * @param string $hasType |
||||
| 662 | * |
||||
| 663 | * @return string |
||||
| 664 | */ |
||||
| 665 | 2 | public function getBaseHasTypeTraitFqn( |
|||
| 666 | string $ownedHasName, |
||||
| 667 | string $hasType |
||||
| 668 | ): string { |
||||
| 669 | 2 | $required = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED) |
|||
| 670 | 1 | ? RelationsGenerator::PREFIX_REQUIRED |
|||
| 671 | 2 | : ''; |
|||
| 672 | |||||
| 673 | 2 | $hasType = str_replace(RelationsGenerator::PREFIX_REQUIRED, '', $hasType); |
|||
| 674 | foreach ( |
||||
| 675 | [ |
||||
| 676 | 2 | RelationsGenerator::INTERNAL_TYPE_MANY_TO_MANY, |
|||
| 677 | 2 | RelationsGenerator::INTERNAL_TYPE_ONE_TO_ONE, |
|||
| 678 | ] as $noStrip |
||||
| 679 | ) { |
||||
| 680 | 2 | if (\ts\stringContains($hasType, $noStrip)) { |
|||
| 681 | 2 | return 'Has' . $required . $ownedHasName . $hasType; |
|||
| 682 | } |
||||
| 683 | } |
||||
| 684 | |||||
| 685 | foreach ( |
||||
| 686 | [ |
||||
| 687 | 1 | RelationsGenerator::INTERNAL_TYPE_ONE_TO_MANY, |
|||
| 688 | 1 | RelationsGenerator::INTERNAL_TYPE_MANY_TO_ONE, |
|||
| 689 | ] as $stripAll |
||||
| 690 | ) { |
||||
| 691 | 1 | if (\ts\stringContains($hasType, $stripAll)) { |
|||
| 692 | 1 | return str_replace( |
|||
| 693 | [ |
||||
| 694 | 1 | RelationsGenerator::PREFIX_OWNING, |
|||
| 695 | 1 | RelationsGenerator::PREFIX_INVERSE, |
|||
| 696 | ], |
||||
| 697 | 1 | '', |
|||
| 698 | 1 | 'Has' . $required . $ownedHasName . $hasType |
|||
| 699 | ); |
||||
| 700 | } |
||||
| 701 | } |
||||
| 702 | |||||
| 703 | return str_replace( |
||||
| 704 | [ |
||||
| 705 | RelationsGenerator::PREFIX_INVERSE, |
||||
| 706 | ], |
||||
| 707 | '', |
||||
| 708 | 'Has' . $required . $ownedHasName . $hasType |
||||
| 709 | ); |
||||
| 710 | } |
||||
| 711 | |||||
| 712 | 3 | public function getFactoryFqnFromEntityFqn(string $entityFqn): string |
|||
| 713 | { |
||||
| 714 | 3 | return $this->tidy( |
|||
| 715 | 3 | str_replace( |
|||
| 716 | 3 | '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\', |
|||
| 717 | 3 | '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE . '\\', |
|||
| 718 | 3 | $entityFqn |
|||
| 719 | 3 | ) . 'Factory' |
|||
| 720 | ); |
||||
| 721 | } |
||||
| 722 | |||||
| 723 | 3 | public function getDtoFactoryFqnFromEntityFqn(string $entityFqn): string |
|||
| 724 | { |
||||
| 725 | 3 | return $this->tidy( |
|||
| 726 | 3 | str_replace( |
|||
| 727 | 3 | '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\', |
|||
| 728 | 3 | '\\' . AbstractGenerator::ENTITY_FACTORIES_NAMESPACE . '\\', |
|||
| 729 | 3 | $entityFqn |
|||
| 730 | 3 | ) . 'DtoFactory' |
|||
| 731 | ); |
||||
| 732 | } |
||||
| 733 | |||||
| 734 | 1 | public function getRepositoryqnFromEntityFqn(string $entityFqn): string |
|||
| 735 | { |
||||
| 736 | 1 | return $this->tidy( |
|||
| 737 | 1 | str_replace( |
|||
| 738 | 1 | '\\' . AbstractGenerator::ENTITIES_FOLDER_NAME . '\\', |
|||
| 739 | 1 | '\\' . AbstractGenerator::ENTITY_REPOSITORIES_NAMESPACE . '\\', |
|||
| 740 | 1 | $entityFqn |
|||
| 741 | 1 | ) . 'Repository' |
|||
| 742 | ); |
||||
| 743 | } |
||||
| 744 | |||||
| 745 | /** |
||||
| 746 | * @param string $ownedEntityFqn |
||||
| 747 | * @param string $srcOrTestSubFolder |
||||
| 748 | * @param string $projectRootNamespace |
||||
| 749 | * |
||||
| 750 | * @return string |
||||
| 751 | * @throws DoctrineStaticMetaException |
||||
| 752 | */ |
||||
| 753 | 1 | public function getReciprocatedHasName( |
|||
| 754 | string $ownedEntityFqn, |
||||
| 755 | string $srcOrTestSubFolder, |
||||
| 756 | string $projectRootNamespace |
||||
| 757 | ): string { |
||||
| 758 | 1 | $parsedFqn = $this->parseFullyQualifiedName( |
|||
| 759 | 1 | $ownedEntityFqn, |
|||
| 760 | 1 | $srcOrTestSubFolder, |
|||
| 761 | 1 | $projectRootNamespace |
|||
| 762 | ); |
||||
| 763 | |||||
| 764 | 1 | $subDirectories = $parsedFqn[2]; |
|||
| 765 | |||||
| 766 | 1 | return $this->getSingularNamespacedName($ownedEntityFqn, $subDirectories); |
|||
| 767 | } |
||||
| 768 | |||||
| 769 | /** |
||||
| 770 | * Get the Fully Qualified Namespace for the Relation Interface for a specific Entity and hasType |
||||
| 771 | * |
||||
| 772 | * @param string $hasType |
||||
| 773 | * @param string $ownedEntityFqn |
||||
| 774 | * @param string|null $projectRootNamespace |
||||
| 775 | * @param string $srcFolder |
||||
| 776 | * |
||||
| 777 | * @return string |
||||
| 778 | * @throws DoctrineStaticMetaException |
||||
| 779 | */ |
||||
| 780 | 2 | public function getOwningInterfaceFqn( |
|||
| 781 | string $hasType, |
||||
| 782 | string $ownedEntityFqn, |
||||
| 783 | string $projectRootNamespace = null, |
||||
| 784 | string $srcFolder = AbstractCommand::DEFAULT_SRC_SUBFOLDER |
||||
| 785 | ): string { |
||||
| 786 | try { |
||||
| 787 | 2 | $ownedHasName = $this->getOwnedHasName($hasType, $ownedEntityFqn, $srcFolder, $projectRootNamespace); |
|||
|
0 ignored issues
–
show
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
Loading history...
|
|||||
| 788 | 2 | if (null === $projectRootNamespace) { |
|||
| 789 | $projectRootNamespace = $this->getProjectRootNamespaceFromComposerJson($srcFolder); |
||||
| 790 | } |
||||
| 791 | 2 | list($ownedClassName, , $ownedSubDirectories) = $this->parseFullyQualifiedName( |
|||
| 792 | 2 | $ownedEntityFqn, |
|||
| 793 | 2 | $srcFolder, |
|||
| 794 | 2 | $projectRootNamespace |
|||
| 795 | ); |
||||
| 796 | 2 | $interfaceSubDirectories = array_slice($ownedSubDirectories, 2); |
|||
| 797 | 2 | $owningInterfaceFqn = $this->getOwningRelationsRootFqn( |
|||
| 798 | 2 | $projectRootNamespace, |
|||
| 799 | 2 | $interfaceSubDirectories |
|||
| 800 | ); |
||||
| 801 | 2 | $required = \ts\stringContains($hasType, RelationsGenerator::PREFIX_REQUIRED) |
|||
| 802 | 1 | ? 'Required' |
|||
| 803 | 2 | : ''; |
|||
| 804 | $owningInterfaceFqn .= '\\' . |
||||
| 805 | 2 | $ownedClassName . |
|||
| 806 | 2 | '\\Interfaces\\Has' . |
|||
| 807 | 2 | $required . |
|||
| 808 | 2 | $ownedHasName . |
|||
| 809 | 2 | 'Interface'; |
|||
| 810 | |||||
| 811 | 2 | return $this->tidy($owningInterfaceFqn); |
|||
| 812 | } catch (Exception $e) { |
||||
| 813 | throw new DoctrineStaticMetaException( |
||||
| 814 | 'Exception in ' . __METHOD__ . ': ' . $e->getMessage(), |
||||
| 815 | $e->getCode(), |
||||
| 816 | $e |
||||
| 817 | ); |
||||
| 818 | } |
||||
| 819 | } |
||||
| 820 | |||||
| 821 | 1 | public function getEntityInterfaceFromEntityFqn(string $entityFqn): string |
|||
| 822 | { |
||||
| 823 | 1 | return str_replace( |
|||
| 824 | 1 | '\\Entities\\', |
|||
| 825 | 1 | '\\Entity\\Interfaces\\', |
|||
| 826 | 1 | $entityFqn |
|||
| 827 | 1 | ) . 'Interface'; |
|||
| 828 | } |
||||
| 829 | |||||
| 830 | 2 | public function getEntityFqnFromEntityInterfaceFqn(string $entityInterfaceFqn): string |
|||
| 831 | { |
||||
| 832 | 2 | return substr( |
|||
| 833 | 2 | str_replace( |
|||
| 834 | 2 | '\\Entity\\Interfaces\\', |
|||
| 835 | 2 | '\\Entities\\', |
|||
| 836 | 2 | $entityInterfaceFqn |
|||
| 837 | ), |
||||
| 838 | 2 | 0, |
|||
| 839 | 2 | -strlen('Interface') |
|||
| 840 | ); |
||||
| 841 | } |
||||
| 842 | |||||
| 843 | 2 | public function getEntityFqnFromEntityFactoryFqn(string $entityFactoryFqn): string |
|||
| 844 | { |
||||
| 845 | 2 | return substr( |
|||
| 846 | 2 | str_replace( |
|||
| 847 | 2 | '\\Entity\\Factories\\', |
|||
| 848 | 2 | '\\Entities\\', |
|||
| 849 | 2 | $entityFactoryFqn |
|||
| 850 | ), |
||||
| 851 | 2 | 0, |
|||
| 852 | 2 | -strlen('Factory') |
|||
| 853 | ); |
||||
| 854 | } |
||||
| 855 | |||||
| 856 | 2 | public function getEntityFqnFromEntityDtoFactoryFqn(string $entityDtoFactoryFqn): string |
|||
| 857 | { |
||||
| 858 | 2 | return substr( |
|||
| 859 | 2 | str_replace( |
|||
| 860 | 2 | '\\Entity\\Factories\\', |
|||
| 861 | 2 | '\\Entities\\', |
|||
| 862 | 2 | $entityDtoFactoryFqn |
|||
| 863 | ), |
||||
| 864 | 2 | 0, |
|||
| 865 | 2 | -strlen('DtoFactory') |
|||
| 866 | ); |
||||
| 867 | } |
||||
| 868 | |||||
| 869 | 3 | public function getEntityDtoFqnFromEntityFqn(string $entityFqn): string |
|||
| 870 | { |
||||
| 871 | 3 | return str_replace( |
|||
| 872 | 3 | '\\Entities\\', |
|||
| 873 | 3 | '\\Entity\\DataTransferObjects\\', |
|||
| 874 | 3 | $entityFqn |
|||
| 875 | 3 | ) . 'Dto'; |
|||
| 876 | } |
||||
| 877 | |||||
| 878 | /** |
||||
| 879 | * @param string $entityDtoFqn |
||||
| 880 | * |
||||
| 881 | * @return string |
||||
| 882 | * @deprecated please use the static method on the DTO directly |
||||
| 883 | * |
||||
| 884 | */ |
||||
| 885 | public function getEntityFqnFromEntityDtoFqn(string $entityDtoFqn): string |
||||
| 886 | { |
||||
| 887 | return $entityDtoFqn::getEntityFqn(); |
||||
| 888 | } |
||||
| 889 | |||||
| 890 | public function getEntityFqnFromEntityRepositoryFqn(string $entityRepositoryFqn): string |
||||
| 891 | { |
||||
| 892 | return substr( |
||||
| 893 | str_replace( |
||||
| 894 | '\\Entity\\Repositories\\', |
||||
| 895 | '\\Entities\\', |
||||
| 896 | $entityRepositoryFqn |
||||
| 897 | ), |
||||
| 898 | 0, |
||||
| 899 | -strlen('Repository') |
||||
| 900 | ); |
||||
| 901 | } |
||||
| 902 | |||||
| 903 | public function getEntityFqnFromEntitySaverFqn(string $entitySaverFqn): string |
||||
| 904 | { |
||||
| 905 | return substr( |
||||
| 906 | str_replace( |
||||
| 907 | '\\Entity\\Savers\\', |
||||
| 908 | '\\Entities\\', |
||||
| 909 | $entitySaverFqn |
||||
| 910 | ), |
||||
| 911 | 0, |
||||
| 912 | -strlen('Saver') |
||||
| 913 | ); |
||||
| 914 | } |
||||
| 915 | |||||
| 916 | 1 | public function getEntitySaverFqnFromEntityFqn(string $entityFqn): string |
|||
| 917 | { |
||||
| 918 | 1 | return str_replace( |
|||
| 919 | 1 | '\\Entities\\', |
|||
| 920 | 1 | '\\Entity\\Savers\\', |
|||
| 921 | 1 | $entityFqn |
|||
| 922 | 1 | ) . 'Saver'; |
|||
| 923 | } |
||||
| 924 | |||||
| 925 | 2 | public function getEntityFqnFromEntityUpserterFqn(string $entityUpserterFqn): string |
|||
| 926 | { |
||||
| 927 | 2 | return substr( |
|||
| 928 | 2 | str_replace( |
|||
| 929 | 2 | '\\Entity\\Savers\\', |
|||
| 930 | 2 | '\\Entities\\', |
|||
| 931 | 2 | $entityUpserterFqn |
|||
| 932 | ), |
||||
| 933 | 2 | 0, |
|||
| 934 | 2 | -strlen('Upserter') |
|||
| 935 | ); |
||||
| 936 | } |
||||
| 937 | |||||
| 938 | 3 | public function getEntityUpserterFqnFromEntityFqn(string $entityFqn): string |
|||
| 939 | { |
||||
| 940 | 3 | return str_replace( |
|||
| 941 | 3 | '\\Entities\\', |
|||
| 942 | 3 | '\\Entity\\Savers\\', |
|||
| 943 | 3 | $entityFqn |
|||
| 944 | 3 | ) . 'Upserter'; |
|||
| 945 | } |
||||
| 946 | |||||
| 947 | 2 | public function getEntityFqnFromEntityUnitOfWorkHelperFqn(string $entityUnitofWorkHelperFqn): string |
|||
| 948 | { |
||||
| 949 | 2 | return substr( |
|||
| 950 | 2 | str_replace( |
|||
| 951 | 2 | '\\Entity\\Savers\\', |
|||
| 952 | 2 | '\\Entities\\', |
|||
| 953 | 2 | $entityUnitofWorkHelperFqn |
|||
| 954 | ), |
||||
| 955 | 2 | 0, |
|||
| 956 | 2 | -strlen('UnitOfWorkHelper') |
|||
| 957 | ); |
||||
| 958 | } |
||||
| 959 | |||||
| 960 | 3 | public function getEntityUnitOfWorkHelperFqnFromEntityFqn(string $entityFqn): string |
|||
| 961 | { |
||||
| 962 | 3 | return str_replace( |
|||
| 963 | 3 | '\\Entities\\', |
|||
| 964 | 3 | '\\Entity\\Savers\\', |
|||
| 965 | 3 | $entityFqn |
|||
| 966 | 3 | ) . 'UnitOfWorkHelper'; |
|||
| 967 | } |
||||
| 968 | |||||
| 969 | public function getEntityFqnFromEntityTestFqn(string $entityTestFqn): string |
||||
| 970 | { |
||||
| 971 | return substr( |
||||
| 972 | $entityTestFqn, |
||||
| 973 | 0, |
||||
| 974 | -strlen('Test') |
||||
| 975 | ); |
||||
| 976 | } |
||||
| 977 | |||||
| 978 | 1 | public function getEntityTestFqnFromEntityFqn(string $entityFqn): string |
|||
| 979 | { |
||||
| 980 | 1 | return $entityFqn . 'Test'; |
|||
| 981 | } |
||||
| 982 | } |
||||
| 983 |