From 8a94dd3932459cda452ac7b3de90a2a95d19ef3e Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Mon, 19 Apr 2021 02:15:08 +0000 Subject: [PATCH 01/35] Added DataAttribute generation --- config/reliese.php | 31 ++- .../DataAttributeGenerateCommand.php | 136 +++++++++++++ .../DataAttributeGeneratorConfiguration.php | 74 +++++++ ...nsportCollectionGeneratorConfiguration.php | 74 +++++++ ...TransportObjectGeneratorConfiguration.php} | 6 +- .../ModelDataMapGeneratorConfiguration.php | 2 +- .../ModelGeneratorConfiguration.php | 2 +- src/Configuration/RelieseConfiguration.php | 28 ++- .../RelieseConfigurationFactory.php | 34 ++-- .../DataAttribute/DataAttributeGenerator.php | 172 ++++++++++++++++ .../DataMap/ModelDataMapGenerator.php | 7 +- .../DataTransportCollectionGenerator.php | 13 ++ .../DataTransport/DataTransportGenerator.php | 16 +- src/MetaCode/Definition/ClassDefinition.php | 183 +++++++++++------- src/MetaCode/Definition/TraitDefinition.php | 35 ++++ src/MetaCode/Format/ClassFormatter.php | 12 +- src/RelieseServiceProvider.php | 2 + 17 files changed, 719 insertions(+), 108 deletions(-) create mode 100644 src/Command/DataAttribute/DataAttributeGenerateCommand.php create mode 100644 src/Configuration/DataAttributeGeneratorConfiguration.php create mode 100644 src/Configuration/DataTransportCollectionGeneratorConfiguration.php rename src/Configuration/{DataTransportGeneratorConfiguration.php => DataTransportObjectGeneratorConfiguration.php} (88%) create mode 100644 src/Generator/DataAttribute/DataAttributeGenerator.php create mode 100644 src/Generator/DataTransport/DataTransportCollectionGenerator.php create mode 100644 src/MetaCode/Definition/TraitDefinition.php diff --git a/config/reliese.php b/config/reliese.php index b80e76e7..41608481 100644 --- a/config/reliese.php +++ b/config/reliese.php @@ -1,6 +1,9 @@ [ + 'Path' => app_path().'/DataAttribute/PrimaryDatabase', + 'Namespace' => 'App\DataAttribute\Objects', + 'ClassPrefix' => 'With', + 'ClassSuffix' => 'Trait', + 'ParentClassPrefix' => 'Abstract', + ], + // endregion Data Attribute Generator Config // region Data Transport Generator Config - 'DataTransportGeneratorConfiguration' => [ - 'Path' => app_path().'/DataTransportObjects', - 'Namespace' => 'App\DataTransportObjects', + DataTransportObjectGeneratorConfiguration::class => [ + 'Path' => app_path().'/DataTransport/Objects', + 'Namespace' => 'App\DataTransport\Objects', 'ClassSuffix' => 'Dto', 'ParentClassPrefix' => 'Abstract', ], // endregion Data Transport Generator Config + // region Data Transport Collection Generator Config + DataTransportCollectionGeneratorConfiguration::class => [ + 'Path' => app_path().'/DataTransport/Collections', + 'Namespace' => 'App\DataTransport\Collections', + 'ClassSuffix' => 'Dto', + 'ParentClassPrefix' => 'Abstract', + ], + // endregion Data Transport Collection Generator Config // region Data Map Generator Config - 'ModelDataMapGeneratorConfiguration' => [ + ModelDataMapGeneratorConfiguration::class => [ 'Path' => app_path().'/DataMaps/PrimaryDatabase', 'Namespace' => 'App\DataMaps\PrimaryDatabase', 'ClassSuffix' => 'Map', diff --git a/src/Command/DataAttribute/DataAttributeGenerateCommand.php b/src/Command/DataAttribute/DataAttributeGenerateCommand.php new file mode 100644 index 00000000..07a4c9c3 --- /dev/null +++ b/src/Command/DataAttribute/DataAttributeGenerateCommand.php @@ -0,0 +1,136 @@ +signature .= self::$configurationProfileOptionDescription; + parent::__construct(); + + $this->models = $models; + $this->config = $config; + } + + /** + * Execute the console command. + * + * @param AnalyserFactory $analyserFactory + * @param RelieseConfigurationFactory $relieseConfigurationFactory + */ + public function handle( + AnalyserFactory $analyserFactory, + RelieseConfigurationFactory $relieseConfigurationFactory, + ) { + $relieseConfiguration = $relieseConfigurationFactory->getRelieseConfiguration($this->getConfigurationProfileName()); + $connection = $this->getConnection(); + $schema = $this->getSchema($connection); + $table = $this->getTable(); + + /* + * TODO: allow command line options to modify state of the $relieseConfiguration graph + */ + + /* + * Create the correct analyser for the configuration profile + */ + $databaseAnalyser = $analyserFactory->databaseAnalyser( + $relieseConfiguration->getDatabaseBlueprintConfiguration(), + $relieseConfiguration->getDatabaseAnalyserConfiguration() + ); + + /* + * Allow the $databaseAnalyser to create the Database Blueprint + */ + $databaseBlueprint = $databaseAnalyser->analyseDatabase($relieseConfiguration->getDatabaseBlueprintConfiguration()); + + /* + * Generate class files + */ + $dataAttributeGenerator = new DataAttributeGenerator( + $relieseConfiguration->getDataAttributeGeneratorConfiguration() + ); + + $schemaBlueprint = $databaseBlueprint->getSchemaBlueprint($schema); + + /* + * Display the data that would be used to perform code generation + */ + foreach ($schemaBlueprint->getTableBlueprints() as $tableBlueprint) { + $dataAttributeGenerator->fromColumnBlueprint($tableBlueprint); + } + } + + /** + * @return string + */ + protected function getConnection() + { + return $this->option('connection') ?: $this->config->get('database.default'); + } + + /** + * @param $connection + * + * @return string + */ + protected function getSchema($connection) + { + return $this->option('schema') ?: $this->config->get("database.connections.$connection.database"); + } + + /** + * @return string + */ + protected function getTable() + { + return $this->option('table'); + } +} diff --git a/src/Configuration/DataAttributeGeneratorConfiguration.php b/src/Configuration/DataAttributeGeneratorConfiguration.php new file mode 100644 index 00000000..7c16c8f1 --- /dev/null +++ b/src/Configuration/DataAttributeGeneratorConfiguration.php @@ -0,0 +1,74 @@ +path = $configuration['Path']; + $this->namespace = $configuration['Namespace']; + $this->traitPrefix = $configuration['TraitPrefix'] ?? ""; + $this->traitSuffix = $configuration['TraitSuffix'] ?? ""; + } + + /** + * @return mixed + */ + public function getTraitPrefix(): mixed + { + return $this->traitPrefix; + } + + /** + * @return mixed + */ + public function getTraitSuffix(): mixed + { + return $this->traitSuffix; + } + + /** + * @return string + */ + public function getNamespace(): string + { + return $this->namespace; + } + + /** + * @return string + */ + public function getPath(): string + { + return $this->path; + } +} diff --git a/src/Configuration/DataTransportCollectionGeneratorConfiguration.php b/src/Configuration/DataTransportCollectionGeneratorConfiguration.php new file mode 100644 index 00000000..adb0c792 --- /dev/null +++ b/src/Configuration/DataTransportCollectionGeneratorConfiguration.php @@ -0,0 +1,74 @@ +path = $configuration['Path']; + $this->namespace = $configuration['Namespace']; + $this->classSuffix = $configuration['ClassSuffix']; + $this->parentClassPrefix = $configuration['ParentClassPrefix']; + } + + /** + * @return mixed + */ + public function getClassSuffix(): mixed + { + return $this->classSuffix; + } + + /** + * @return string + */ + public function getNamespace(): string + { + return $this->namespace; + } + + /** + * @return mixed + */ + public function getParentClassPrefix(): mixed + { + return $this->parentClassPrefix; + } + + /** + * @return string + */ + public function getPath(): string + { + return $this->path; + } +} diff --git a/src/Configuration/DataTransportGeneratorConfiguration.php b/src/Configuration/DataTransportObjectGeneratorConfiguration.php similarity index 88% rename from src/Configuration/DataTransportGeneratorConfiguration.php rename to src/Configuration/DataTransportObjectGeneratorConfiguration.php index 8cd64d98..cbc2e2cf 100644 --- a/src/Configuration/DataTransportGeneratorConfiguration.php +++ b/src/Configuration/DataTransportObjectGeneratorConfiguration.php @@ -3,9 +3,9 @@ namespace Reliese\Configuration; /** - * Class DataTransportGeneratorConfiguration + * Class DataTransportObjectGeneratorConfiguration */ -class DataTransportGeneratorConfiguration +class DataTransportObjectGeneratorConfiguration { /** * @var string @@ -28,7 +28,7 @@ class DataTransportGeneratorConfiguration private string $path; /** - * DataTransportGeneratorConfiguration constructor. + * DataTransportObjectGeneratorConfiguration constructor. * * @param array $configuration */ diff --git a/src/Configuration/ModelDataMapGeneratorConfiguration.php b/src/Configuration/ModelDataMapGeneratorConfiguration.php index fa425366..8047a9dd 100644 --- a/src/Configuration/ModelDataMapGeneratorConfiguration.php +++ b/src/Configuration/ModelDataMapGeneratorConfiguration.php @@ -28,7 +28,7 @@ class ModelDataMapGeneratorConfiguration private string $path; /** - * DataTransportGeneratorConfiguration constructor. + * DataTransportObjectGeneratorConfiguration constructor. * * @param array $configuration */ diff --git a/src/Configuration/ModelGeneratorConfiguration.php b/src/Configuration/ModelGeneratorConfiguration.php index 20b2987c..304d2cfe 100644 --- a/src/Configuration/ModelGeneratorConfiguration.php +++ b/src/Configuration/ModelGeneratorConfiguration.php @@ -28,7 +28,7 @@ class ModelGeneratorConfiguration private string $path; /** - * DataTransportGeneratorConfiguration constructor. + * DataTransportObjectGeneratorConfiguration constructor. * * @param array $configuration */ diff --git a/src/Configuration/RelieseConfiguration.php b/src/Configuration/RelieseConfiguration.php index 669af714..6a908fe9 100644 --- a/src/Configuration/RelieseConfiguration.php +++ b/src/Configuration/RelieseConfiguration.php @@ -13,9 +13,9 @@ class RelieseConfiguration protected ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration; /** - * @var DataTransportGeneratorConfiguration + * @var DataTransportObjectGeneratorConfiguration */ - protected DataTransportGeneratorConfiguration $dataTransportGeneratorConfiguration; + protected DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration; /** * @var DatabaseAnalyserConfiguration @@ -37,20 +37,27 @@ class RelieseConfiguration */ private string $configurationProfileName; + /** + * @var DataAttributeGeneratorConfiguration + */ + private DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration; + /** * RelieseConfiguration constructor. * * @param string $configurationProfileName * @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration - * @param DataTransportGeneratorConfiguration $dataTransportGeneratorConfiguration + * @param DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration * @param DatabaseAnalyserConfiguration $databaseAnalyserConfiguration + * @param DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration * @param DatabaseBlueprintConfiguration $databaseBlueprintConfiguration * @param ModelGeneratorConfiguration $modelGeneratorConfiguration */ public function __construct(string $configurationProfileName, ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration, - DataTransportGeneratorConfiguration $dataTransportGeneratorConfiguration, + DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration, DatabaseAnalyserConfiguration $databaseAnalyserConfiguration, + DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration, DatabaseBlueprintConfiguration $databaseBlueprintConfiguration, ModelGeneratorConfiguration $modelGeneratorConfiguration,) { @@ -60,6 +67,7 @@ public function __construct(string $configurationProfileName, $this->databaseAnalyserConfiguration = $databaseAnalyserConfiguration; $this->databaseBlueprintConfiguration = $databaseBlueprintConfiguration; $this->modelGeneratorConfiguration = $modelGeneratorConfiguration; + $this->dataAttributeGeneratorConfiguration = $dataAttributeGeneratorConfiguration; } /** @@ -70,6 +78,14 @@ public function getConfigurationProfileName(): string return $this->configurationProfileName; } + /** + * @return DataAttributeGeneratorConfiguration + */ + public function getDataAttributeGeneratorConfiguration(): DataAttributeGeneratorConfiguration + { + return $this->dataAttributeGeneratorConfiguration; + } + /** * @return ModelDataMapGeneratorConfiguration */ @@ -79,9 +95,9 @@ public function getModelDataMapGeneratorConfiguration(): ModelDataMapGeneratorCo } /** - * @return DataTransportGeneratorConfiguration + * @return DataTransportObjectGeneratorConfiguration */ - public function getDataTransportGeneratorConfiguration(): DataTransportGeneratorConfiguration + public function getDataTransportGeneratorConfiguration(): DataTransportObjectGeneratorConfiguration { return $this->dataTransportGeneratorConfiguration; } diff --git a/src/Configuration/RelieseConfigurationFactory.php b/src/Configuration/RelieseConfigurationFactory.php index e43ac2cf..523e2994 100644 --- a/src/Configuration/RelieseConfigurationFactory.php +++ b/src/Configuration/RelieseConfigurationFactory.php @@ -47,29 +47,41 @@ public function getRelieseConfiguration(string $configurationProfileName): Relie $configurationProfile = $this->relieseConfigurationProfiles[$configurationProfileName]; return new RelieseConfiguration($configurationProfileName, - $this->getDataMapGeneratorConfiguration($configurationProfile), - $this->getDataTransportGeneratorConfiguration($configurationProfile), + $this->getModelDataMapGeneratorConfiguration($configurationProfile), + $this->getDataTransportObjectGeneratorConfiguration($configurationProfile), $this->getDatabaseAnalyserConfiguration($configurationProfile), + $this->getDataAttributeGeneratorConfiguration($configurationProfile), $this->getDatabaseBlueprintConfiguration($configurationProfile), - $this->getModelGeneratorConfiguration($configurationProfile)); + $this->getModelGeneratorConfiguration($configurationProfile) + ); } - protected function getDataMapGeneratorConfiguration(array $configurationProfile): ModelDataMapGeneratorConfiguration + protected function getModelDataMapGeneratorConfiguration(array $configurationProfile): ModelDataMapGeneratorConfiguration { - if (!\array_key_exists('ModelDataMapGeneratorConfiguration', $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"ModelDataMapGeneratorConfiguration\""); + if (!\array_key_exists(ModelDataMapGeneratorConfiguration::class, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"ModelDataMapGeneratorConfiguration::class\""); } - return new ModelDataMapGeneratorConfiguration($configurationProfile['ModelDataMapGeneratorConfiguration']); + return new ModelDataMapGeneratorConfiguration($configurationProfile[ModelDataMapGeneratorConfiguration::class]); } - protected function getDataTransportGeneratorConfiguration(array $configurationProfile): DataTransportGeneratorConfiguration + protected function getDataAttributeGeneratorConfiguration(array $configurationProfile): DataAttributeGeneratorConfiguration { - if (!\array_key_exists('DataTransportGeneratorConfiguration', $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"DataTransportGeneratorConfiguration\""); + if (!\array_key_exists(DataAttributeGeneratorConfiguration::class, $configurationProfile)) { + dd(\array_keys($configurationProfile)); + throw new InvalidArgumentException("Unable to locate configuration block for \"DataAttributeGeneratorConfiguration::class\""); } - return new DataTransportGeneratorConfiguration($configurationProfile['DataTransportGeneratorConfiguration']); + return new DataAttributeGeneratorConfiguration($configurationProfile[DataAttributeGeneratorConfiguration::class]); + } + + protected function getDataTransportObjectGeneratorConfiguration(array $configurationProfile): DataTransportObjectGeneratorConfiguration + { + if (!\array_key_exists(DataTransportObjectGeneratorConfiguration::class, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"DataTransportObjectGeneratorConfiguration::class\""); + } + + return new DataTransportObjectGeneratorConfiguration($configurationProfile[DataTransportObjectGeneratorConfiguration::class]); } protected function getDatabaseAnalyserConfiguration(array $configurationProfile): DatabaseAnalyserConfiguration diff --git a/src/Generator/DataAttribute/DataAttributeGenerator.php b/src/Generator/DataAttribute/DataAttributeGenerator.php new file mode 100644 index 00000000..e09f6ebb --- /dev/null +++ b/src/Generator/DataAttribute/DataAttributeGenerator.php @@ -0,0 +1,172 @@ +dataAttributeGeneratorConfiguration = $dataAttributeGeneratorConfiguration; + /* + * TODO: inject a MySql / Postgress or other DataType mapping as needed + */ + $this->dataTypeMap = new MySqlDataTypeMap(); + } + + /** + * @param TableBlueprint $tableBlueprint + */ + public function fromColumnBlueprint(TableBlueprint $tableBlueprint) + { + foreach ($tableBlueprint->getColumnBlueprints() as $columnBlueprint) { + + if ($this->isExcluded($tableBlueprint, $columnBlueprint)) { + Log::warning("Skipping column: " . $tableBlueprint->getName() . '.' . $columnBlueprint->getColumnName()); + continue; + } + + $traitName = $this->getTraitName($tableBlueprint, $columnBlueprint); + + $namespace = $this->getTraitNamespace($tableBlueprint, $columnBlueprint); + + $traitDefinition = new TraitDefinition($traitName, $namespace); + + $traitDefinition + ->addClassComment( + sprintf("Generated from table column %s.%s", $tableBlueprint->getName(), $columnBlueprint->getColumnName()) + ) + ->addClassComment( + "This file is only generated if it does not already exist. To regenerate, remove this file." + ) + ; + + $propertyName = ClassNameTool::columnNameToPropertyName($columnBlueprint->getColumnName()); + + $phpTypeEnum = $this->dataTypeMap->getPhpTypeEnumFromDatabaseType( + $columnBlueprint->getDataType(), + $columnBlueprint->getMaximumCharacters(), + $columnBlueprint->getNumericPrecision(), + $columnBlueprint->getNumericScale(), + $columnBlueprint->getIsNullable() + ); + + $traitDefinition->addProperty( + (new ClassPropertyDefinition($propertyName, $phpTypeEnum)) + ->withSetter() + ->withGetter() + ); + + /* + * Write the Class Files + */ + $this->writeTraitFile($traitDefinition); + } + } + + /** + * @param TableBlueprint $tableBlueprint + * @param ColumnBlueprint $columnBlueprint + * + * @return string + */ + public function getFullyQualifiedTraitName(TableBlueprint $tableBlueprint, ColumnBlueprint $columnBlueprint): string + { + return $this->getTraitNamespace($tableBlueprint, $columnBlueprint).'\\'.$this->getTraitName($tableBlueprint, $columnBlueprint); + } + + public function getTraitNamespace(TableBlueprint $tableBlueprint, ColumnBlueprint $columnBlueprint): string + { + $tableClassName = ClassNameTool::snakeCaseToClassName(null, $tableBlueprint->getName(), null); + return $this->dataAttributeGeneratorConfiguration->getNamespace().'\\'.$tableClassName; + } + + public function getTraitName( + TableBlueprint $tableBlueprint, + ColumnBlueprint $columnBlueprint + ): string { + return ClassNameTool::snakeCaseToClassName( + $this->dataAttributeGeneratorConfiguration->getTraitPrefix(), + $columnBlueprint->getColumnName(), + $this->dataAttributeGeneratorConfiguration->getTraitSuffix(), + ); + } + + /** + * @param TableBlueprint $tableBlueprint + * @param ColumnBlueprint $columnBlueprint + * + * @return bool + */ + private function isExcluded(TableBlueprint $tableBlueprint, ColumnBlueprint $columnBlueprint) + { + if ('id' === $columnBlueprint->getColumnName()) { + return true; + } + return false; + } + + /** + * @param TraitDefinition $traitDefinition + */ + private function writeTraitFile( + TraitDefinition $traitDefinition + ): void + { + $classFormatter = new ClassFormatter(); + + $traitPhpCode = $classFormatter->format($traitDefinition); +// echo "\n---Trait---\n$traitPhpCode\n\n"; + + $traitDirectory = $this->dataAttributeGeneratorConfiguration->getPath(); +// echo "\n---Trait Path---\n$traitDirectory\n\n"; + + if (!is_dir($traitDirectory)) { + \mkdir($traitDirectory, 0755, true); + } + + $traitFilePath = $traitDirectory . DIRECTORY_SEPARATOR . $traitDefinition->getName() . '.php'; +// echo "\n---Trait File---\n$traitFilePath\n\n"; + if (!\file_exists($traitFilePath)) { + \file_put_contents($traitFilePath, $traitPhpCode); + } else { + Log::warning("File already exists, skipped: $traitFilePath"); + } + } +} diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index 8fcfce07..1053130d 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -5,15 +5,12 @@ use Illuminate\Support\Str; use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\TableBlueprint; -use Reliese\Configuration\DataTransportGeneratorConfiguration; use Reliese\Configuration\ModelDataMapGeneratorConfiguration; -use Reliese\Configuration\ModelGeneratorConfiguration; use Reliese\Generator\DataTransport\DataTransportGenerator; use Reliese\Generator\Model\ModelGenerator; use Reliese\Generator\MySqlDataTypeMap; use Reliese\MetaCode\Definition\ClassDefinition; use Reliese\MetaCode\Definition\ClassMethodDefinition; -use Reliese\MetaCode\Definition\ClassPropertyDefinition; use Reliese\MetaCode\Definition\FunctionParameterDefinition; use Reliese\MetaCode\Definition\RawStatementDefinition; use Reliese\MetaCode\Enum\PhpTypeEnum; @@ -255,10 +252,10 @@ private function writeClassFiles( $classFolder = $this->modelDataMapGeneratorConfiguration->getPath(); $abstractClassFolder = $classFolder . DIRECTORY_SEPARATOR . 'Generated'; if (!is_dir($classFolder)) { - \mkdir($classFolder, 0777, true); + \mkdir($classFolder, 0755, true); } if (!is_dir($abstractClassFolder)) { - \mkdir($abstractClassFolder, 0777, true); + \mkdir($abstractClassFolder, 0755, true); } $classFilePath = $classFolder . DIRECTORY_SEPARATOR . $classDefinition->getName() . '.php'; diff --git a/src/Generator/DataTransport/DataTransportCollectionGenerator.php b/src/Generator/DataTransport/DataTransportCollectionGenerator.php new file mode 100644 index 00000000..c1aaa533 --- /dev/null +++ b/src/Generator/DataTransport/DataTransportCollectionGenerator.php @@ -0,0 +1,13 @@ +dataTransportGeneratorConfiguration = $dataTransportGeneratorConfiguration; /* @@ -148,10 +146,10 @@ private function writeClassFiles( $dtoClassFolder = $this->dataTransportGeneratorConfiguration->getPath(); $abstractDtoClassFolder = $dtoClassFolder . DIRECTORY_SEPARATOR . 'Generated'; if (!is_dir($dtoClassFolder)) { - \mkdir($dtoClassFolder, 0777, true); + \mkdir($dtoClassFolder, 0755, true); } if (!is_dir($abstractDtoClassFolder)) { - \mkdir($abstractDtoClassFolder, 0777, true); + \mkdir($abstractDtoClassFolder, 0755, true); } $dtoFilePath = $dtoClassFolder . DIRECTORY_SEPARATOR . $classDefinition->getName() . '.php'; diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php index a99f12a4..543360e9 100644 --- a/src/MetaCode/Definition/ClassDefinition.php +++ b/src/MetaCode/Definition/ClassDefinition.php @@ -7,6 +7,26 @@ */ class ClassDefinition implements ImportableInterface { + /** + * @var string[] + */ + private array $classComments = []; + + /** + * @var ClassConstantDefinition[] + */ + private array $constants = []; + + /** + * @var ImportableInterface[] + */ + private array $imports = []; + + /** + * @var ClassMethodDefinition[] + */ + private array $methods = []; + private string $name; /** @@ -20,9 +40,9 @@ class ClassDefinition implements ImportableInterface private ?string $parentClassName = null; /** - * @var ImportableInterface[] + * @var ClassPropertyDefinition[] */ - private array $imports = []; + private array $properties = []; /** * @var ClassTraitDefinition[] @@ -30,75 +50,115 @@ class ClassDefinition implements ImportableInterface private array $traits = []; /** - * @var ClassConstantDefinition[] + * ClassDefinition constructor. + * + * @param string $name + * @param string $namespace */ - private array $constants = []; + public function __construct(string $name, + string $namespace) + { + $this->name = $name; + $this->namespace = trim($namespace, '\\'); + } /** - * @var ClassPropertyDefinition[] + * @param string $comment + * + * @return $this */ - private array $properties = []; + public function addClassComment(string $comment): static + { + $this->classComments[] = $comment; + return $this; + } /** - * @var ClassMethodDefinition[] + * @param ClassConstantDefinition $constant + * + * @return $this */ - private array $methods = []; + public function addConstant(ClassConstantDefinition $constant): static + { + $this->constants[$constant->getName()] = $constant; + return $this; + } - public function __construct( - string $name, - string $namespace - ) { - $this->name = $name; - $this->namespace = trim($namespace, '\\'); + /** + * @param ImportableInterface $import + * + * @return $this + */ + public function addImport(ImportableInterface $import): static + { + // We'll assume this class is already imported to shorten references to itself + if (strcmp($import->getFullyQualifiedImportableName(), $this->getFullyQualifiedImportableName()) === 0) { + return $this; + } + + $this->imports[$import->getImportableName()] = $import; + return $this; } + /** + * @param ClassMethodDefinition $classMethodDefinition + */ public function addMethodDefinition(ClassMethodDefinition $classMethodDefinition) { $this->methods[$classMethodDefinition->getFunctionName()] = $classMethodDefinition; } - public function setParentClass(string $fullyQualifiedClassName): ClassDefinition + /** + * @param ClassPropertyDefinition $classPropertyDefinition + * + * @return $this + */ + public function addProperty(ClassPropertyDefinition $classPropertyDefinition): ClassDefinition { - $this->parentClassName = $fullyQualifiedClassName; + $this->properties[$classPropertyDefinition->getVariableName()] = $classPropertyDefinition; return $this; } - public function hasParentClass(): bool + public function addTrait(ClassTraitDefinition $trait): static { - return !is_null($this->parentClassName); + $this->traits[$trait->getName()] = $trait; + return $this; } - public function getParentClassName() : string + public function getClassComments(): array { - return $this->parentClassName; + return $this->classComments; } - public function getName(): string + /** + * @return ClassConstantDefinition[] + */ + public function getConstants(): array { - return $this->name; + return $this->constants; } - public function getFullyQualifiedName(): string + public function getFullyQualifiedImportableName(): string { - return '\\'.$this->getNamespace().'\\'.$this->getName(); + return trim($this->getFullyQualifiedName(), '\\'); } - public function getNamespace(): string + public function getFullyQualifiedName(): string { - return $this->namespace; + return '\\' . $this->getNamespace() . '\\' . $this->getName(); } - public function addProperty(ClassPropertyDefinition $classPropertyDefinition): ClassDefinition { - $this->properties[$classPropertyDefinition->getVariableName()] = $classPropertyDefinition; - return $this; + public function getImportableName(): string + { + return $this->getName(); } /** - * @return ClassPropertyDefinition[] + * @return ImportableInterface[] */ - public function getProperties(): array + public function getImports(): array { - return $this->properties; + return $this->imports; } /** @@ -109,24 +169,35 @@ public function getMethods(): array return $this->methods; } - public function addConstant(ClassConstantDefinition $constant): static + public function getName(): string { - $this->constants[$constant->getName()] = $constant; - return $this; + return $this->name; + } + + public function getNamespace(): string + { + return $this->namespace; + } + + public function getParentClassName(): string + { + return $this->parentClassName; } /** - * @return ClassConstantDefinition[] + * @return ClassPropertyDefinition[] */ - public function getConstants(): array + public function getProperties(): array { - return $this->constants; + return $this->properties; } - public function addTrait(ClassTraitDefinition $trait): static + /** + * @return string + */ + public function getStructureType(): string { - $this->traits[$trait->getName()] = $trait; - return $this; + return 'class'; } /** @@ -137,14 +208,14 @@ public function getTraits(): array return $this->traits; } - public function addImport(ImportableInterface $import): static + public function hasParentClass(): bool { - // We'll assume this class is already imported to shorten references to itself - if (strcmp($import->getFullyQualifiedImportableName(), $this->getFullyQualifiedImportableName()) === 0) { - return $this; - } + return !is_null($this->parentClassName); + } - $this->imports[$import->getImportableName()] = $import; + public function setParentClass(string $fullyQualifiedClassName): ClassDefinition + { + $this->parentClassName = $fullyQualifiedClassName; return $this; } @@ -164,22 +235,4 @@ public function willCollideImport(ImportableInterface $import): bool return array_key_exists($import->getImportableName(), $this->imports); } - - /** - * @return ImportableInterface[] - */ - public function getImports(): array - { - return $this->imports; - } - - public function getFullyQualifiedImportableName(): string - { - return trim($this->getFullyQualifiedName(), '\\'); - } - - public function getImportableName(): string - { - return $this->getName(); - } } diff --git a/src/MetaCode/Definition/TraitDefinition.php b/src/MetaCode/Definition/TraitDefinition.php new file mode 100644 index 00000000..45e7f4b9 --- /dev/null +++ b/src/MetaCode/Definition/TraitDefinition.php @@ -0,0 +1,35 @@ +getName() . "\n"; + $lines[] = ' * ' . Str::studly($classDefinition->getStructureType()) . ' ' . $classDefinition->getName() . "\n"; $lines[] = " * \n"; $lines[] = " * Created by Reliese\n"; + foreach ($classDefinition->getClassComments() as $line) { + $lines[] = " * \n * ".$line."\n"; + } $lines[] = " */\n"; - $lines[] = 'class ' . $classDefinition->getName(); + $lines[] = Str::lower($classDefinition->getStructureType()) . ' ' . $classDefinition->getName(); if (!empty($parent)) { $lines[] = ' extends ' . $parent; diff --git a/src/RelieseServiceProvider.php b/src/RelieseServiceProvider.php index ce81eb9a..8e5f33c8 100644 --- a/src/RelieseServiceProvider.php +++ b/src/RelieseServiceProvider.php @@ -9,6 +9,7 @@ use Reliese\Coders\Model\Config; use Reliese\Coders\Model\Factory as ModelFactory; use Reliese\Command\Blueprint\ShowBlueprintCommand; +use Reliese\Command\DataAttribute\DataAttributeGenerateCommand; use Reliese\Command\DataMap\ModelDataMapGenerateCommand; use Reliese\Command\DataTransport\DataTransportGenerateCommand; use Reliese\Command\Model\ModelGenerateCommand; @@ -50,6 +51,7 @@ public function boot() ShowBlueprintCommand::class, ModelDataMapGenerateCommand::class, DataTransportGenerateCommand::class, + DataAttributeGenerateCommand::class ]); } } From 8637f8af46d03d2270d6ef26b1b3a7b3ed8e674a Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Mon, 19 Apr 2021 02:59:38 +0000 Subject: [PATCH 02/35] update to re-use data attributes --- .../DataMap/ModelDataMapGenerateCommand.php | 6 ++- .../DataTransportGenerateCommand.php | 4 +- .../DataAttribute/DataAttributeGenerator.php | 23 ++--------- .../DataTransport/DataTransportGenerator.php | 41 ++++++++++++++++--- .../Model/Eloquent/EloquentModelGenerator.php | 13 ------ 5 files changed, 46 insertions(+), 41 deletions(-) delete mode 100644 src/Generator/Model/Eloquent/EloquentModelGenerator.php diff --git a/src/Command/DataMap/ModelDataMapGenerateCommand.php b/src/Command/DataMap/ModelDataMapGenerateCommand.php index 22b0d033..2592e713 100644 --- a/src/Command/DataMap/ModelDataMapGenerateCommand.php +++ b/src/Command/DataMap/ModelDataMapGenerateCommand.php @@ -9,6 +9,7 @@ use Reliese\Coders\Model\Factory; use Reliese\Command\ConfigurationProfileOptionTrait; use Reliese\Configuration\RelieseConfigurationFactory; +use Reliese\Generator\DataAttribute\DataAttributeGenerator; use Reliese\Generator\DataMap\ModelDataMapGenerator; use Reliese\Generator\DataTransport\DataTransportGenerator; use Reliese\Generator\Model\ModelGenerator; @@ -104,7 +105,10 @@ public function handle( $modelDataMapGenerator = new ModelDataMapGenerator( $relieseConfiguration->getModelDataMapGeneratorConfiguration(), new ModelGenerator($relieseConfiguration->getModelGeneratorConfiguration()), - new DataTransportGenerator($relieseConfiguration->getDataTransportGeneratorConfiguration()), + new DataTransportGenerator( + $relieseConfiguration->getDataTransportGeneratorConfiguration(), + new DataAttributeGenerator($relieseConfiguration->getDataAttributeGeneratorConfiguration()) + ), ); if (!empty($table)) { diff --git a/src/Command/DataTransport/DataTransportGenerateCommand.php b/src/Command/DataTransport/DataTransportGenerateCommand.php index 88180754..af3a598f 100644 --- a/src/Command/DataTransport/DataTransportGenerateCommand.php +++ b/src/Command/DataTransport/DataTransportGenerateCommand.php @@ -9,6 +9,7 @@ use Reliese\Coders\Model\Factory; use Reliese\Command\ConfigurationProfileOptionTrait; use Reliese\Configuration\RelieseConfigurationFactory; +use Reliese\Generator\DataAttribute\DataAttributeGenerator; use Reliese\Generator\DataTransport\DataTransportGenerator; /** * Class DataTransportGenerateCommand @@ -95,7 +96,8 @@ public function handle( * Generate class files */ $dataTransportGenerator = new DataTransportGenerator( - $relieseConfiguration->getDataTransportGeneratorConfiguration() + $relieseConfiguration->getDataTransportGeneratorConfiguration(), + new DataAttributeGenerator($relieseConfiguration->getDataAttributeGeneratorConfiguration()) ); $schemaBlueprint = $databaseBlueprint->getSchemaBlueprint($schema); diff --git a/src/Generator/DataAttribute/DataAttributeGenerator.php b/src/Generator/DataAttribute/DataAttributeGenerator.php index e09f6ebb..f48a6beb 100644 --- a/src/Generator/DataAttribute/DataAttributeGenerator.php +++ b/src/Generator/DataAttribute/DataAttributeGenerator.php @@ -57,11 +57,6 @@ public function fromColumnBlueprint(TableBlueprint $tableBlueprint) { foreach ($tableBlueprint->getColumnBlueprints() as $columnBlueprint) { - if ($this->isExcluded($tableBlueprint, $columnBlueprint)) { - Log::warning("Skipping column: " . $tableBlueprint->getName() . '.' . $columnBlueprint->getColumnName()); - continue; - } - $traitName = $this->getTraitName($tableBlueprint, $columnBlueprint); $namespace = $this->getTraitNamespace($tableBlueprint, $columnBlueprint); @@ -128,20 +123,6 @@ public function getTraitName( ); } - /** - * @param TableBlueprint $tableBlueprint - * @param ColumnBlueprint $columnBlueprint - * - * @return bool - */ - private function isExcluded(TableBlueprint $tableBlueprint, ColumnBlueprint $columnBlueprint) - { - if ('id' === $columnBlueprint->getColumnName()) { - return true; - } - return false; - } - /** * @param TraitDefinition $traitDefinition */ @@ -155,7 +136,9 @@ private function writeTraitFile( // echo "\n---Trait---\n$traitPhpCode\n\n"; $traitDirectory = $this->dataAttributeGeneratorConfiguration->getPath(); -// echo "\n---Trait Path---\n$traitDirectory\n\n"; + $namespaceParts = \explode('\\', $traitDefinition->getNamespace()); + $traitDirectory .= '/'.\array_pop($namespaceParts); + echo "\n---Trait Path---\n$traitDirectory\n\n"; if (!is_dir($traitDirectory)) { \mkdir($traitDirectory, 0755, true); diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 6b235d13..4e2d1c66 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -5,9 +5,11 @@ use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\DataTransportObjectGeneratorConfiguration; +use Reliese\Generator\DataAttribute\DataAttributeGenerator; use Reliese\Generator\MySqlDataTypeMap; use Reliese\MetaCode\Definition\ClassDefinition; use Reliese\MetaCode\Definition\ClassPropertyDefinition; +use Reliese\MetaCode\Definition\ClassTraitDefinition; use Reliese\MetaCode\Format\ClassFormatter; use Reliese\MetaCode\Tool\ClassNameTool; use const DIRECTORY_SEPARATOR; @@ -17,6 +19,11 @@ */ class DataTransportGenerator { + /** + * @var DataAttributeGenerator + */ + private DataAttributeGenerator $dataAttributeGenerator; + /** * @var DataTransportObjectGeneratorConfiguration */ @@ -36,15 +43,18 @@ class DataTransportGenerator * DataTransportGenerator constructor. * * @param DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration + * @param DataAttributeGenerator $dataAttributeGenerator */ public function __construct( - DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration + DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration, + DataAttributeGenerator $dataAttributeGenerator ) { $this->dataTransportGeneratorConfiguration = $dataTransportGeneratorConfiguration; /* * TODO: inject a MySql / Postgress or other DataType mapping as needed */ $this->dataTypeMap = new MySqlDataTypeMap(); + $this->dataAttributeGenerator = $dataAttributeGenerator; } /** @@ -79,12 +89,31 @@ public function fromTableBlueprint( $columnBlueprint->getIsNullable() ); - $columnClassProperty = (new ClassPropertyDefinition($propertyName, $phpTypeEnum)) - ->withSetter() - ->withGetter() - ; + $traitFullyQualifiedName = $this->dataAttributeGenerator->getFullyQualifiedTraitName($tableBlueprint, + $columnBlueprint + ); - $dtoAbstractClassDefinition->addProperty($columnClassProperty); + echo "looking for: $traitFullyQualifiedName\n"; + + if (\class_exists($traitFullyQualifiedName)) { + /* + * If a DataAttribute trait has been defined for this table and column, then use it here + */ + $classTraitDefinition = new ClassTraitDefinition( + $this->dataAttributeGenerator->getTraitName($tableBlueprint, $columnBlueprint), + $this->dataAttributeGenerator->getTraitNamespace($tableBlueprint, $columnBlueprint)) + ; + $dtoAbstractClassDefinition->addTrait($classTraitDefinition); + } else { + /* + * Use a property defined directly on the class + */ + $columnClassProperty = (new ClassPropertyDefinition($propertyName, $phpTypeEnum))->withSetter() + ->withGetter() + ; + + $dtoAbstractClassDefinition->addProperty($columnClassProperty); + } } /* diff --git a/src/Generator/Model/Eloquent/EloquentModelGenerator.php b/src/Generator/Model/Eloquent/EloquentModelGenerator.php deleted file mode 100644 index c93c6651..00000000 --- a/src/Generator/Model/Eloquent/EloquentModelGenerator.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Mon, 19 Apr 2021 03:16:45 +0000 Subject: [PATCH 03/35] Added command to generate empty data access objects. will add method definitions soon --- config/reliese.php | 20 ++- .../DataAccess/DataAccessGenerateCommand.php | 136 ++++++++++++++++ .../DataAccessGeneratorConfiguration.php | 88 ++++++++++ src/Configuration/RelieseConfiguration.php | 13 ++ .../RelieseConfigurationFactory.php | 85 ++++++++-- .../DataAccess/DataAccessGenerator.php | 154 ++++++++++++++++++ src/RelieseServiceProvider.php | 4 +- 7 files changed, 478 insertions(+), 22 deletions(-) create mode 100644 src/Command/DataAccess/DataAccessGenerateCommand.php create mode 100644 src/Configuration/DataAccessGeneratorConfiguration.php create mode 100644 src/Generator/DataAccess/DataAccessGenerator.php diff --git a/config/reliese.php b/config/reliese.php index 41608481..18aa1886 100644 --- a/config/reliese.php +++ b/config/reliese.php @@ -1,5 +1,6 @@ [ 'IncludeByDefault' => true, 'Except' => [ - // except everything in schema + // except everything in schemas named... ['schemas' => ['information_schema', 'performance_schema', 'mysql']], // except audit.log_.* tables - ['schemas' => ['audit'], 'tables' => ['/^log_.*$/']], + //['schemas' => ['audit'], 'tables' => ['/^log_.*$/']], // except any table that ends in migrations or matches 'phinx' on all schemas ['schemas' => [$all], 'tables' => ['/^.*migrations$/', 'phinx']], // except soft delete columns on all tables for all schemas - ['schemas' => [$all], 'tables' => [$all], 'columns' => ['deleted_on']] + //['schemas' => [$all], 'tables' => [$all], 'columns' => ['deleted_on']] ], ], /* @@ -529,6 +530,16 @@ ], // endregion Model Generator Config + // region Data Access Generator Config + DataAccessGeneratorConfiguration::class => [ + 'Path' => app_path().'/DataAccess/PrimaryDatabase', + 'Namespace' => 'app\DataAccess\PrimaryDatabase', + //'ClassPrefix' => '', + 'ClassSuffix' => 'DataAccess', + 'ParentClassPrefix' => 'Abstract', + ], + // endregion Data Access Generator Config + // region Data Attribute Generator Config DataAttributeGeneratorConfiguration::class => [ 'Path' => app_path().'/DataAttribute/PrimaryDatabase', @@ -538,6 +549,7 @@ 'ParentClassPrefix' => 'Abstract', ], // endregion Data Attribute Generator Config + // region Data Transport Generator Config DataTransportObjectGeneratorConfiguration::class => [ 'Path' => app_path().'/DataTransport/Objects', @@ -546,6 +558,7 @@ 'ParentClassPrefix' => 'Abstract', ], // endregion Data Transport Generator Config + // region Data Transport Collection Generator Config DataTransportCollectionGeneratorConfiguration::class => [ 'Path' => app_path().'/DataTransport/Collections', @@ -554,6 +567,7 @@ 'ParentClassPrefix' => 'Abstract', ], // endregion Data Transport Collection Generator Config + // region Data Map Generator Config ModelDataMapGeneratorConfiguration::class => [ 'Path' => app_path().'/DataMaps/PrimaryDatabase', diff --git a/src/Command/DataAccess/DataAccessGenerateCommand.php b/src/Command/DataAccess/DataAccessGenerateCommand.php new file mode 100644 index 00000000..6e3ccf58 --- /dev/null +++ b/src/Command/DataAccess/DataAccessGenerateCommand.php @@ -0,0 +1,136 @@ +signature .= self::$configurationProfileOptionDescription; + parent::__construct(); + + $this->models = $models; + $this->config = $config; + } + + /** + * Execute the console command. + * + * @param AnalyserFactory $analyserFactory + * @param RelieseConfigurationFactory $relieseConfigurationFactory + */ + public function handle( + AnalyserFactory $analyserFactory, + RelieseConfigurationFactory $relieseConfigurationFactory, + ) { + $relieseConfiguration = $relieseConfigurationFactory->getRelieseConfiguration($this->getConfigurationProfileName()); + $connection = $this->getConnection(); + $schema = $this->getSchema($connection); + $table = $this->getTable(); + + /* + * TODO: allow command line options to modify state of the $relieseConfiguration graph + */ + + /* + * Create the correct analyser for the configuration profile + */ + $databaseAnalyser = $analyserFactory->databaseAnalyser( + $relieseConfiguration->getDatabaseBlueprintConfiguration(), + $relieseConfiguration->getDatabaseAnalyserConfiguration() + ); + + /* + * Allow the $databaseAnalyser to create the Database Blueprint + */ + $databaseBlueprint = $databaseAnalyser->analyseDatabase($relieseConfiguration->getDatabaseBlueprintConfiguration()); + + /* + * Generate class files + */ + $dataAccessGenerator = new DataAccessGenerator( + $relieseConfiguration->getDataAccessGeneratorConfiguration() + ); + + $schemaBlueprint = $databaseBlueprint->getSchemaBlueprint($schema); + + /* + * Display the data that would be used to perform code generation + */ + foreach ($schemaBlueprint->getTableBlueprints() as $tableBlueprint) { + $dataAccessGenerator->fromTableBlueprint($tableBlueprint); + } + } + + /** + * @return string + */ + protected function getConnection() + { + return $this->option('connection') ?: $this->config->get('database.default'); + } + + /** + * @param $connection + * + * @return string + */ + protected function getSchema($connection) + { + return $this->option('schema') ?: $this->config->get("database.connections.$connection.database"); + } + + /** + * @return string + */ + protected function getTable() + { + return $this->option('table'); + } +} diff --git a/src/Configuration/DataAccessGeneratorConfiguration.php b/src/Configuration/DataAccessGeneratorConfiguration.php new file mode 100644 index 00000000..b511ba20 --- /dev/null +++ b/src/Configuration/DataAccessGeneratorConfiguration.php @@ -0,0 +1,88 @@ +path = $configuration['Path']; + $this->namespace = $configuration['Namespace']; + $this->classPrefix = $configuration['ClassPrefix'] ?? ''; + $this->classSuffix = $configuration['ClassSuffix'] ?? ''; + $this->parentClassPrefix = $configuration['ParentClassPrefix'] ?? ''; + } + + /** + * @return mixed|string + */ + public function getClassPrefix(): mixed + { + return $this->classPrefix; + } + + /** + * @return mixed + */ + public function getClassSuffix(): mixed + { + return $this->classSuffix; + } + + /** + * @return string + */ + public function getNamespace(): string + { + return $this->namespace; + } + + /** + * @return mixed + */ + public function getParentClassPrefix(): mixed + { + return $this->parentClassPrefix; + } + + /** + * @return string + */ + public function getPath(): string + { + return $this->path; + } +} diff --git a/src/Configuration/RelieseConfiguration.php b/src/Configuration/RelieseConfiguration.php index 6a908fe9..e673f465 100644 --- a/src/Configuration/RelieseConfiguration.php +++ b/src/Configuration/RelieseConfiguration.php @@ -37,6 +37,11 @@ class RelieseConfiguration */ private string $configurationProfileName; + /** + * @var DataAccessGeneratorConfiguration + */ + private DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration; + /** * @var DataAttributeGeneratorConfiguration */ @@ -47,6 +52,7 @@ class RelieseConfiguration * * @param string $configurationProfileName * @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration + * @param DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration * @param DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration * @param DatabaseAnalyserConfiguration $databaseAnalyserConfiguration * @param DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration @@ -55,6 +61,7 @@ class RelieseConfiguration */ public function __construct(string $configurationProfileName, ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration, + DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration, DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration, DatabaseAnalyserConfiguration $databaseAnalyserConfiguration, DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration, @@ -63,6 +70,7 @@ public function __construct(string $configurationProfileName, { $this->configurationProfileName = $configurationProfileName; $this->modelDataMapGeneratorConfiguration = $modelDataMapGeneratorConfiguration; + $this->dataAccessGeneratorConfiguration = $dataAccessGeneratorConfiguration; $this->dataTransportGeneratorConfiguration = $dataTransportGeneratorConfiguration; $this->databaseAnalyserConfiguration = $databaseAnalyserConfiguration; $this->databaseBlueprintConfiguration = $databaseBlueprintConfiguration; @@ -78,6 +86,11 @@ public function getConfigurationProfileName(): string return $this->configurationProfileName; } + public function getDataAccessGeneratorConfiguration() + { + return $this->dataAccessGeneratorConfiguration; + } + /** * @return DataAttributeGeneratorConfiguration */ diff --git a/src/Configuration/RelieseConfigurationFactory.php b/src/Configuration/RelieseConfigurationFactory.php index 523e2994..adf1b017 100644 --- a/src/Configuration/RelieseConfigurationFactory.php +++ b/src/Configuration/RelieseConfigurationFactory.php @@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Log; use InvalidArgumentException; use Reliese\PackagePaths; +use function array_key_exists; /** * Class ConfigurationFactory @@ -36,11 +37,16 @@ public function __construct(string $appDirectoryPath, $this->relieseConfigurationProfiles = $relieseConfigurationProfiles ?? include(PackagePaths::getExampleConfigFilePath()); } + /** + * @param string $configurationProfileName + * + * @return RelieseConfiguration + */ public function getRelieseConfiguration(string $configurationProfileName): RelieseConfiguration { Log::info("Creating RelieseConfiguration for Configuration Profile \"$configurationProfileName\""); - if (!\array_key_exists($configurationProfileName, $this->relieseConfigurationProfiles)) { + if (!array_key_exists($configurationProfileName, $this->relieseConfigurationProfiles)) { throw new InvalidArgumentException("Unable to locate a configuration profile named $configurationProfileName in {$this->relieseConfigurationFilePath}"); } @@ -48,66 +54,109 @@ public function getRelieseConfiguration(string $configurationProfileName): Relie return new RelieseConfiguration($configurationProfileName, $this->getModelDataMapGeneratorConfiguration($configurationProfile), + $this->getDataAccessGeneratorConfiguration($configurationProfile), $this->getDataTransportObjectGeneratorConfiguration($configurationProfile), $this->getDatabaseAnalyserConfiguration($configurationProfile), $this->getDataAttributeGeneratorConfiguration($configurationProfile), $this->getDatabaseBlueprintConfiguration($configurationProfile), - $this->getModelGeneratorConfiguration($configurationProfile) - ); - } - - protected function getModelDataMapGeneratorConfiguration(array $configurationProfile): ModelDataMapGeneratorConfiguration - { - if (!\array_key_exists(ModelDataMapGeneratorConfiguration::class, $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"ModelDataMapGeneratorConfiguration::class\""); - } - - return new ModelDataMapGeneratorConfiguration($configurationProfile[ModelDataMapGeneratorConfiguration::class]); + $this->getModelGeneratorConfiguration($configurationProfile)); } + /** + * @param array $configurationProfile + * + * @return DataAttributeGeneratorConfiguration + */ protected function getDataAttributeGeneratorConfiguration(array $configurationProfile): DataAttributeGeneratorConfiguration { - if (!\array_key_exists(DataAttributeGeneratorConfiguration::class, $configurationProfile)) { - dd(\array_keys($configurationProfile)); + if (!array_key_exists(DataAttributeGeneratorConfiguration::class, $configurationProfile)) { throw new InvalidArgumentException("Unable to locate configuration block for \"DataAttributeGeneratorConfiguration::class\""); } return new DataAttributeGeneratorConfiguration($configurationProfile[DataAttributeGeneratorConfiguration::class]); } + /** + * @param array $configurationProfile + * + * @return DataTransportObjectGeneratorConfiguration + */ protected function getDataTransportObjectGeneratorConfiguration(array $configurationProfile): DataTransportObjectGeneratorConfiguration { - if (!\array_key_exists(DataTransportObjectGeneratorConfiguration::class, $configurationProfile)) { + if (!array_key_exists(DataTransportObjectGeneratorConfiguration::class, $configurationProfile)) { throw new InvalidArgumentException("Unable to locate configuration block for \"DataTransportObjectGeneratorConfiguration::class\""); } return new DataTransportObjectGeneratorConfiguration($configurationProfile[DataTransportObjectGeneratorConfiguration::class]); } + /** + * @param array $configurationProfile + * + * @return DatabaseAnalyserConfiguration + */ protected function getDatabaseAnalyserConfiguration(array $configurationProfile): DatabaseAnalyserConfiguration { - if (!\array_key_exists('DatabaseAnalyserConfiguration', $configurationProfile)) { + if (!array_key_exists('DatabaseAnalyserConfiguration', $configurationProfile)) { throw new InvalidArgumentException("Unable to locate configuration block for \"DatabaseAnalyserConfiguration\""); } return new DatabaseAnalyserConfiguration($configurationProfile['DatabaseAnalyserConfiguration']); } + /** + * @param array $configurationProfile + * + * @return DatabaseBlueprintConfiguration + */ protected function getDatabaseBlueprintConfiguration(array $configurationProfile): DatabaseBlueprintConfiguration { - if (!\array_key_exists('DatabaseBlueprintConfiguration', $configurationProfile)) { + if (!array_key_exists('DatabaseBlueprintConfiguration', $configurationProfile)) { throw new InvalidArgumentException("Unable to locate configuration block for \"DatabaseBlueprintConfiguration\""); } return new DatabaseBlueprintConfiguration($configurationProfile['DatabaseBlueprintConfiguration']); } + /** + * @param array $configurationProfile + * + * @return ModelDataMapGeneratorConfiguration + */ + protected function getModelDataMapGeneratorConfiguration(array $configurationProfile): ModelDataMapGeneratorConfiguration + { + if (!array_key_exists(ModelDataMapGeneratorConfiguration::class, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"ModelDataMapGeneratorConfiguration::class\""); + } + + return new ModelDataMapGeneratorConfiguration($configurationProfile[ModelDataMapGeneratorConfiguration::class]); + } + + /** + * @param array $configurationProfile + * + * @return ModelGeneratorConfiguration + */ protected function getModelGeneratorConfiguration(array $configurationProfile): ModelGeneratorConfiguration { - if (!\array_key_exists('ModelGeneratorConfiguration', $configurationProfile)) { + if (!array_key_exists('ModelGeneratorConfiguration', $configurationProfile)) { throw new InvalidArgumentException("Unable to locate configuration block for \"ModelGeneratorConfiguration\""); } return new ModelGeneratorConfiguration($configurationProfile['ModelGeneratorConfiguration']); } + + /** + * @param mixed $configurationProfile + * + * @return DataAccessGeneratorConfiguration + */ + private function getDataAccessGeneratorConfiguration(mixed $configurationProfile): DataAccessGeneratorConfiguration + { + if (!array_key_exists(DataAccessGeneratorConfiguration::class, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"DataAccessGeneratorConfiguration\""); + } + + return new DataAccessGeneratorConfiguration($configurationProfile[DataAccessGeneratorConfiguration::class]); + } } diff --git a/src/Generator/DataAccess/DataAccessGenerator.php b/src/Generator/DataAccess/DataAccessGenerator.php new file mode 100644 index 00000000..36cbccad --- /dev/null +++ b/src/Generator/DataAccess/DataAccessGenerator.php @@ -0,0 +1,154 @@ +dataAccessGeneratorConfiguration = $dataAccessGeneratorConfiguration; + /* + * TODO: inject a MySql / Postgress or other DataType mapping as needed + */ + $this->dataTypeMap = new MySqlDataTypeMap(); + } + + /** + * @param TableBlueprint $tableBlueprint + */ + public function fromTableBlueprint( + TableBlueprint $tableBlueprint + ) { + + $className = $this->getClassName($tableBlueprint); + + $abstractClassName = $this->getAbstractClassName($tableBlueprint); + + $namespace = $this->getClassNamespace($tableBlueprint); + + $abstractNamespace = $this->getAbstractClassNamespace($tableBlueprint); + + $dtoAbstractClassDefinition = new ClassDefinition($abstractClassName, $abstractNamespace); + + $dtoClassDefinition = new ClassDefinition($className, $namespace); + $dtoClassDefinition->setParentClass($dtoAbstractClassDefinition->getFullyQualifiedName()); + + /* + * TODO: Add generic methods like "get by id" + */ + + /* + * Write the Class Files + */ + $this->writeClassFiles($dtoClassDefinition, $dtoAbstractClassDefinition); + } + + /** + * @param TableBlueprint $tableBlueprint + * + * @return string + */ + public function getFullyQualifiedClassName(TableBlueprint $tableBlueprint): string + { + return $this->getClassNamespace($tableBlueprint).'\\'.$this->getClassName($tableBlueprint); + } + + public function getClassNamespace(TableBlueprint $tableBlueprint): string + { + return $this->dataAccessGeneratorConfiguration->getNamespace(); + } + + public function getClassName(TableBlueprint $tableBlueprint): string + { + return ClassNameTool::snakeCaseToClassName( + $this->dataAccessGeneratorConfiguration->getClassPrefix(), + $tableBlueprint->getName(), + $this->dataAccessGeneratorConfiguration->getClassSuffix() + ); + } + + private function getAbstractClassName(TableBlueprint $tableBlueprint): string + { + return $this->dataAccessGeneratorConfiguration->getParentClassPrefix() + . $this->getClassName($tableBlueprint); + } + + private function getAbstractClassNamespace(TableBlueprint $tableBlueprint): string + { + return $this->getClassNamespace($tableBlueprint) .'\\Generated'; + } + + /** + * @param ClassDefinition $classDefinition + * @param ClassDefinition $abstractClassDefinition + */ + private function writeClassFiles( + ClassDefinition $classDefinition, + ClassDefinition $abstractClassDefinition, + ): void + { + $classFormatter = new ClassFormatter(); + + $dtoClassPhpCode = $classFormatter->format($classDefinition); + $abstractDtoPhpCode = $classFormatter->format($abstractClassDefinition); + // echo "\n---Class---\n$dtoClassPhpCode\n\n\n---Base Class---\n$abstractDtoPhpCode\n\n"; + + $dtoClassFolder = $this->dataAccessGeneratorConfiguration->getPath(); + $abstractDtoClassFolder = $dtoClassFolder . DIRECTORY_SEPARATOR . 'Generated'; + if (!is_dir($dtoClassFolder)) { + \mkdir($dtoClassFolder, 0755, true); + } + if (!is_dir($abstractDtoClassFolder)) { + \mkdir($abstractDtoClassFolder, 0755, true); + } + + $dtoFilePath = $dtoClassFolder . DIRECTORY_SEPARATOR . $classDefinition->getName() . '.php'; + $abstractDtoFilePath = $abstractDtoClassFolder . DIRECTORY_SEPARATOR . $abstractClassDefinition->getName() . '.php'; + + if (!\file_exists($dtoFilePath)) { + \file_put_contents($dtoFilePath, $dtoClassPhpCode); + } + \file_put_contents($abstractDtoFilePath, $abstractDtoPhpCode); + } +} diff --git a/src/RelieseServiceProvider.php b/src/RelieseServiceProvider.php index 8e5f33c8..d6c9b600 100644 --- a/src/RelieseServiceProvider.php +++ b/src/RelieseServiceProvider.php @@ -9,6 +9,7 @@ use Reliese\Coders\Model\Config; use Reliese\Coders\Model\Factory as ModelFactory; use Reliese\Command\Blueprint\ShowBlueprintCommand; +use Reliese\Command\DataAccess\DataAccessGenerateCommand; use Reliese\Command\DataAttribute\DataAttributeGenerateCommand; use Reliese\Command\DataMap\ModelDataMapGenerateCommand; use Reliese\Command\DataTransport\DataTransportGenerateCommand; @@ -51,7 +52,8 @@ public function boot() ShowBlueprintCommand::class, ModelDataMapGenerateCommand::class, DataTransportGenerateCommand::class, - DataAttributeGenerateCommand::class + DataAttributeGenerateCommand::class, + DataAccessGenerateCommand::class, ]); } } From 50b00363196350fdd378f6c968c8caba3b82673a Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Mon, 19 Apr 2021 04:01:42 -0400 Subject: [PATCH 04/35] fixes for configuration and made all dto class members nullable so that a DTO can be used w/o setting all of the fields --- config/reliese.php | 9 +++-- ...nsportCollectionGeneratorConfiguration.php | 4 +-- ...aTransportObjectGeneratorConfiguration.php | 4 +-- .../ModelDataMapGeneratorConfiguration.php | 4 +-- .../ModelGeneratorConfiguration.php | 4 +-- .../RelieseConfigurationFactory.php | 35 +++++++++++-------- .../DataTransport/DataTransportGenerator.php | 4 ++- src/MetaCode/Enum/PhpTypeEnum.php | 28 +++++++-------- src/MetaCode/Format/ClassFormatter.php | 1 + 9 files changed, 52 insertions(+), 41 deletions(-) diff --git a/config/reliese.php b/config/reliese.php index 18aa1886..f2e76f20 100644 --- a/config/reliese.php +++ b/config/reliese.php @@ -2,9 +2,12 @@ use Reliese\Analyser\Doctrine\MySqlDoctrineDatabaseAnalyser; use Reliese\Configuration\DataAccessGeneratorConfiguration; use Reliese\Configuration\DataAttributeGeneratorConfiguration; +use Reliese\Configuration\DatabaseAnalyserConfiguration; +use Reliese\Configuration\DatabaseBlueprintConfiguration; use Reliese\Configuration\DataTransportObjectGeneratorConfiguration; use Reliese\Configuration\ModelDataMapGeneratorConfiguration; use Reliese\Configuration\DataTransportCollectionGeneratorConfiguration; +use Reliese\Configuration\ModelGeneratorConfiguration; /* |-------------------------------------------------------------------------- @@ -32,7 +35,7 @@ | section defines which database connection will be analysed. | */ - 'DatabaseAnalyserConfiguration' => [ + DatabaseAnalyserConfiguration::class => [ /* |-------------------------------------------------------------------------- | Database Connection Name @@ -48,7 +51,7 @@ // region Blueprint Configuration - 'DatabaseBlueprintConfiguration' => [ + DatabaseBlueprintConfiguration::class => [ /* |-------------------------------------------------------------------------- | Database Blueprint Filters @@ -111,7 +114,7 @@ // endregion Blueprint Configuration // region Model Generator Config - 'ModelGeneratorConfiguration' => [ + ModelGeneratorConfiguration::class => [ /* |-------------------------------------------------------------------------- diff --git a/src/Configuration/DataTransportCollectionGeneratorConfiguration.php b/src/Configuration/DataTransportCollectionGeneratorConfiguration.php index adb0c792..663212e7 100644 --- a/src/Configuration/DataTransportCollectionGeneratorConfiguration.php +++ b/src/Configuration/DataTransportCollectionGeneratorConfiguration.php @@ -36,8 +36,8 @@ public function __construct(array $configuration) { $this->path = $configuration['Path']; $this->namespace = $configuration['Namespace']; - $this->classSuffix = $configuration['ClassSuffix']; - $this->parentClassPrefix = $configuration['ParentClassPrefix']; + $this->classSuffix = $configuration['ClassSuffix'] ?? ''; + $this->parentClassPrefix = $configuration['ParentClassPrefix'] ?? ''; } /** diff --git a/src/Configuration/DataTransportObjectGeneratorConfiguration.php b/src/Configuration/DataTransportObjectGeneratorConfiguration.php index cbc2e2cf..b2b7db05 100644 --- a/src/Configuration/DataTransportObjectGeneratorConfiguration.php +++ b/src/Configuration/DataTransportObjectGeneratorConfiguration.php @@ -36,8 +36,8 @@ public function __construct(array $configuration) { $this->path = $configuration['Path']; $this->namespace = $configuration['Namespace']; - $this->classSuffix = $configuration['ClassSuffix']; - $this->parentClassPrefix = $configuration['ParentClassPrefix']; + $this->classSuffix = $configuration['ClassSuffix'] ?? ''; + $this->parentClassPrefix = $configuration['ParentClassPrefix'] ?? ''; } /** diff --git a/src/Configuration/ModelDataMapGeneratorConfiguration.php b/src/Configuration/ModelDataMapGeneratorConfiguration.php index 8047a9dd..8ca7c9c9 100644 --- a/src/Configuration/ModelDataMapGeneratorConfiguration.php +++ b/src/Configuration/ModelDataMapGeneratorConfiguration.php @@ -37,8 +37,8 @@ public function __construct(array $configuration) $this->path = $configuration['Path']; $this->namespace = $configuration['Namespace']; - $this->classSuffix = $configuration['ClassSuffix']; - $this->parentClassPrefix = $configuration['ParentClassPrefix']; + $this->classSuffix = $configuration['ClassSuffix'] ?? ''; + $this->parentClassPrefix = $configuration['ParentClassPrefix'] ?? ''; } /** diff --git a/src/Configuration/ModelGeneratorConfiguration.php b/src/Configuration/ModelGeneratorConfiguration.php index 304d2cfe..e3506cdf 100644 --- a/src/Configuration/ModelGeneratorConfiguration.php +++ b/src/Configuration/ModelGeneratorConfiguration.php @@ -36,8 +36,8 @@ public function __construct(array $configuration) { $this->path = $configuration['Path']; $this->namespace = $configuration['Namespace']; - $this->classSuffix = $configuration['ClassSuffix']; - $this->parentClassPrefix = $configuration['ParentClassPrefix']; + $this->classSuffix = $configuration['ClassSuffix'] ?? ''; + $this->parentClassPrefix = $configuration['ParentClassPrefix'] ?? ''; } /** diff --git a/src/Configuration/RelieseConfigurationFactory.php b/src/Configuration/RelieseConfigurationFactory.php index adf1b017..a0b4045f 100644 --- a/src/Configuration/RelieseConfigurationFactory.php +++ b/src/Configuration/RelieseConfigurationFactory.php @@ -97,11 +97,12 @@ protected function getDataTransportObjectGeneratorConfiguration(array $configura */ protected function getDatabaseAnalyserConfiguration(array $configurationProfile): DatabaseAnalyserConfiguration { - if (!array_key_exists('DatabaseAnalyserConfiguration', $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"DatabaseAnalyserConfiguration\""); + $key = DatabaseAnalyserConfiguration::class; + if (!array_key_exists($key, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"$key\""); } - return new DatabaseAnalyserConfiguration($configurationProfile['DatabaseAnalyserConfiguration']); + return new DatabaseAnalyserConfiguration($configurationProfile[$key]); } /** @@ -111,11 +112,12 @@ protected function getDatabaseAnalyserConfiguration(array $configurationProfile) */ protected function getDatabaseBlueprintConfiguration(array $configurationProfile): DatabaseBlueprintConfiguration { - if (!array_key_exists('DatabaseBlueprintConfiguration', $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"DatabaseBlueprintConfiguration\""); + $key = DatabaseBlueprintConfiguration::class; + if (!array_key_exists($key, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"$key\""); } - return new DatabaseBlueprintConfiguration($configurationProfile['DatabaseBlueprintConfiguration']); + return new DatabaseBlueprintConfiguration($configurationProfile[$key]); } /** @@ -125,11 +127,12 @@ protected function getDatabaseBlueprintConfiguration(array $configurationProfile */ protected function getModelDataMapGeneratorConfiguration(array $configurationProfile): ModelDataMapGeneratorConfiguration { - if (!array_key_exists(ModelDataMapGeneratorConfiguration::class, $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"ModelDataMapGeneratorConfiguration::class\""); + $key = ModelDataMapGeneratorConfiguration::class; + if (!array_key_exists($key, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"$key\""); } - return new ModelDataMapGeneratorConfiguration($configurationProfile[ModelDataMapGeneratorConfiguration::class]); + return new ModelDataMapGeneratorConfiguration($configurationProfile[$key]); } /** @@ -139,11 +142,12 @@ protected function getModelDataMapGeneratorConfiguration(array $configurationPro */ protected function getModelGeneratorConfiguration(array $configurationProfile): ModelGeneratorConfiguration { - if (!array_key_exists('ModelGeneratorConfiguration', $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"ModelGeneratorConfiguration\""); + $key = ModelGeneratorConfiguration::class; + if (!array_key_exists($key, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"$key\""); } - return new ModelGeneratorConfiguration($configurationProfile['ModelGeneratorConfiguration']); + return new ModelGeneratorConfiguration($configurationProfile[$key]); } /** @@ -153,10 +157,11 @@ protected function getModelGeneratorConfiguration(array $configurationProfile): */ private function getDataAccessGeneratorConfiguration(mixed $configurationProfile): DataAccessGeneratorConfiguration { - if (!array_key_exists(DataAccessGeneratorConfiguration::class, $configurationProfile)) { - throw new InvalidArgumentException("Unable to locate configuration block for \"DataAccessGeneratorConfiguration\""); + $key = DataAccessGeneratorConfiguration::class; + if (!array_key_exists($key, $configurationProfile)) { + throw new InvalidArgumentException("Unable to locate configuration block for \"$key\""); } - return new DataAccessGeneratorConfiguration($configurationProfile[DataAccessGeneratorConfiguration::class]); + return new DataAccessGeneratorConfiguration($configurationProfile[$key]); } } diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 4e2d1c66..c54ddcf3 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -86,7 +86,9 @@ public function fromTableBlueprint( $columnBlueprint->getMaximumCharacters(), $columnBlueprint->getNumericPrecision(), $columnBlueprint->getNumericScale(), - $columnBlueprint->getIsNullable() + // This value must always be true in order to allow for partial DTOs. + // Otherwise and error is raised when attempting to read a property that has not been assigned a value + true //$columnBlueprint->getIsNullable() ); $traitFullyQualifiedName = $this->dataAttributeGenerator->getFullyQualifiedTraitName($tableBlueprint, diff --git a/src/MetaCode/Enum/PhpTypeEnum.php b/src/MetaCode/Enum/PhpTypeEnum.php index 5b9826d3..465c8262 100644 --- a/src/MetaCode/Enum/PhpTypeEnum.php +++ b/src/MetaCode/Enum/PhpTypeEnum.php @@ -73,7 +73,7 @@ class PhpTypeEnum */ private bool $isNullable = false; - private function __construct($phpTypeId, $isNullable = false) + private function __construct($phpTypeId, $isNullable) { $this->phpTypeId = $phpTypeId; $this->isNullable = $isNullable; @@ -195,7 +195,7 @@ public static function stringType(): PhpTypeEnum if (static::$stringTypeInstance) { return static::$stringTypeInstance; } - return static::$stringTypeInstance = new static(static::STRING_TYPE_ID); + return static::$stringTypeInstance = new static(static::STRING_TYPE_ID, false); } public static function nullableStringType(): PhpTypeEnum @@ -211,7 +211,7 @@ public static function intType(): PhpTypeEnum if (static::$intTypeInstance) { return static::$intTypeInstance; } - return static::$intTypeInstance = new static(static::INT_TYPE_ID); + return static::$intTypeInstance = new static(static::INT_TYPE_ID, false); } public static function nullableIntType(): PhpTypeEnum @@ -219,7 +219,7 @@ public static function nullableIntType(): PhpTypeEnum if (static::$nullableIntTypeInstance) { return static::$nullableIntTypeInstance; } - return static::$nullableIntTypeInstance = new static(static::NULLABLE_INT_TYPE_ID); + return static::$nullableIntTypeInstance = new static(static::NULLABLE_INT_TYPE_ID, true); } public static function floatType(): PhpTypeEnum @@ -227,7 +227,7 @@ public static function floatType(): PhpTypeEnum if (static::$floatTypeInstance) { return static::$floatTypeInstance; } - return static::$floatTypeInstance = new static(static::FLOAT_TYPE_ID); + return static::$floatTypeInstance = new static(static::FLOAT_TYPE_ID, false); } public static function nullableFloatType(): PhpTypeEnum @@ -235,7 +235,7 @@ public static function nullableFloatType(): PhpTypeEnum if (static::$nullableFloatTypeInstance) { return static::$nullableFloatTypeInstance; } - return static::$nullableFloatTypeInstance = new static(static::NULLABLE_FLOAT_TYPE_ID); + return static::$nullableFloatTypeInstance = new static(static::NULLABLE_FLOAT_TYPE_ID, true); } public static function boolType(): PhpTypeEnum @@ -243,7 +243,7 @@ public static function boolType(): PhpTypeEnum if (static::$boolTypeInstance) { return static::$boolTypeInstance; } - return static::$boolTypeInstance = new static(static::BOOL_TYPE_ID); + return static::$boolTypeInstance = new static(static::BOOL_TYPE_ID, false); } public static function nullableBoolType(): PhpTypeEnum @@ -251,7 +251,7 @@ public static function nullableBoolType(): PhpTypeEnum if (static::$nullableBoolTypeInstance) { return static::$nullableBoolTypeInstance; } - return static::$nullableBoolTypeInstance = new static(static::NULLABLE_BOOL_TYPE_ID); + return static::$nullableBoolTypeInstance = new static(static::NULLABLE_BOOL_TYPE_ID, true); } public static function arrayType(string $containedTypeName): PhpTypeEnum @@ -259,7 +259,7 @@ public static function arrayType(string $containedTypeName): PhpTypeEnum if (\array_key_exists($containedTypeName, static::$arrayTypeInstances)) { return static::$arrayTypeInstances[$containedTypeName]; } - return static::$arrayTypeInstances[$containedTypeName] = (new static(static::ARRAY_TYPE_ID)) + return static::$arrayTypeInstances[$containedTypeName] = (new static(static::ARRAY_TYPE_ID, false)) ->setContainedTypeName($containedTypeName); } @@ -268,7 +268,7 @@ public static function nullableArrayType(string $containedTypeName): PhpTypeEnum if (\array_key_exists($containedTypeName, static::$nullableArrayTypeInstances)) { return static::$nullableArrayTypeInstances[$containedTypeName]; } - return static::$nullableArrayTypeInstances[$containedTypeName] = (new static(static::NULLABLE_ARRAY_TYPE_ID)) + return static::$nullableArrayTypeInstances[$containedTypeName] = (new static(static::NULLABLE_ARRAY_TYPE_ID, true)) ->setContainedTypeName($containedTypeName); } @@ -278,7 +278,7 @@ public static function objectOfType(string $fullyQualifiedClassNameOfObjectType) return static::$objectTypeInstance[$fullyQualifiedClassNameOfObjectType]; } return static::$objectTypeInstance[$fullyQualifiedClassNameOfObjectType] - = (new static(static::OBJECT_TYPE_ID))->setObjectClassType($fullyQualifiedClassNameOfObjectType); + = (new static(static::OBJECT_TYPE_ID, false))->setObjectClassType($fullyQualifiedClassNameOfObjectType); } public static function nullableObjectOfType(string $fullyQualifiedClassNameOfObjectType): PhpTypeEnum @@ -287,7 +287,7 @@ public static function nullableObjectOfType(string $fullyQualifiedClassNameOfObj return static::$nullableObjectTypeInstance[$fullyQualifiedClassNameOfObjectType]; } return static::$nullableObjectTypeInstance[$fullyQualifiedClassNameOfObjectType] - = (new static(static::NULLABLE_OBJECT_TYPE_ID))->setObjectClassType($fullyQualifiedClassNameOfObjectType); + = (new static(static::NULLABLE_OBJECT_TYPE_ID, true))->setObjectClassType($fullyQualifiedClassNameOfObjectType); } public static function staticTypeEnum(): PhpTypeEnum @@ -295,7 +295,7 @@ public static function staticTypeEnum(): PhpTypeEnum if (static::$staticTypeInstance) { return static::$staticTypeInstance; } - return static::$staticTypeInstance = new static(static::STATIC_TYPE_ID); + return static::$staticTypeInstance = new static(static::STATIC_TYPE_ID, false); } public static function nullableStaticTypeEnum(): PhpTypeEnum @@ -303,7 +303,7 @@ public static function nullableStaticTypeEnum(): PhpTypeEnum if (static::$nullableStaticTypeInstance) { return static::$nullableStaticTypeInstance; } - return static::$nullableStaticTypeInstance = new static(static::NULLABLE_STATIC_TYPE_ID); + return static::$nullableStaticTypeInstance = new static(static::NULLABLE_STATIC_TYPE_ID, true); } public function toDeclarationType() : string diff --git a/src/MetaCode/Format/ClassFormatter.php b/src/MetaCode/Format/ClassFormatter.php index 126de70a..72b1be64 100644 --- a/src/MetaCode/Format/ClassFormatter.php +++ b/src/MetaCode/Format/ClassFormatter.php @@ -205,6 +205,7 @@ private function formatProperty(ClassDefinition $classDefinition, ClassPropertyD . $this->shortenTypeHint($classDefinition, $property->getPhpTypeEnum()) . ' $' . $property->getVariableName() + . ($property->getPhpTypeEnum()->isNullable() ? ' = null' : '') . ';'; } From a43e2efae54cd0cb68bc7548b1dd3050b5ae6ab4 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Sun, 9 May 2021 19:51:57 -0400 Subject: [PATCH 05/35] .gitignore changes --- .gitignore | 106 ++++++++++++++++++++++++++++++++++- .idea/encodings.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/php-test-framework.xml | 14 +++++ .idea/php.xml | 91 ++++++++++++++++++++++++++++++ .idea/phpunit.xml | 10 ++++ .idea/reliese-laravel.iml | 12 ++++ .idea/vcs.xml | 6 ++ 8 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 .idea/encodings.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/php-test-framework.xml create mode 100644 .idea/php.xml create mode 100644 .idea/phpunit.xml create mode 100644 .idea/reliese-laravel.iml create mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore index 55ff9b07..a9109417 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,104 @@ -.idea /vendor -composer.lock -.phpunit.result.cache \ No newline at end of file +.phpunit.result.cache +.idea/**/markdown-navigator* +# Ingore .env files +.env +.env.behat + +# Created by https://www.toptal.com/developers/gitignore/api/osx,linux,windows,jetbrains+all +# Edit at https://www.toptal.com/developers/gitignore?templates=osx,linux,windows,jetbrains+all + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/osx,linux,windows,jetbrains+all diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..97626ba4 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..19e5bd3b --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/php-test-framework.xml b/.idea/php-test-framework.xml new file mode 100644 index 00000000..5aa0e33f --- /dev/null +++ b/.idea/php-test-framework.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 00000000..8fc91883 --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/phpunit.xml b/.idea/phpunit.xml new file mode 100644 index 00000000..4f8104cf --- /dev/null +++ b/.idea/phpunit.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/reliese-laravel.iml b/.idea/reliese-laravel.iml new file mode 100644 index 00000000..6e4b1f34 --- /dev/null +++ b/.idea/reliese-laravel.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..94a25f7f --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 9ad42f8eef6265d4eda8fd730c96121ab222a742 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Mon, 10 May 2021 21:55:47 -0400 Subject: [PATCH 06/35] Added DTO Property generation to allow DTOs to reference other DTOs --- src/Blueprint/ForeignKeyBlueprint.php | 24 ++++++ ...aTransportObjectGeneratorConfiguration.php | 8 +- .../DataTransport/DataTransportGenerator.php | 84 ++++++++++++++++++- .../Definition/ClassPropertyDefinition.php | 31 ++++++- src/MetaCode/Tool/ClassNameTool.php | 5 ++ 5 files changed, 141 insertions(+), 11 deletions(-) diff --git a/src/Blueprint/ForeignKeyBlueprint.php b/src/Blueprint/ForeignKeyBlueprint.php index 1cc23303..be42906f 100644 --- a/src/Blueprint/ForeignKeyBlueprint.php +++ b/src/Blueprint/ForeignKeyBlueprint.php @@ -101,4 +101,28 @@ public function getReferencedTableBlueprint() : ColumnOwnerInterface { return $this->referencedTable; } + + /** + * @return ColumnBlueprint[] + */ + public function getReferencedColumns() : array + { + return $this->referencedColumns; + } + + public function getFkColumnPairs():array + { + $columns = []; + $i = -1; + foreach ($this->referencingColumns as $referencingColumn) { + $i++; + $columns[$i][0] = $referencingColumn; + } + $i = -1; + foreach ($this->referencedColumns as $referencedColumn) { + $i++; + $columns[$i][1] = $referencedColumn; + } + return $columns; + } } diff --git a/src/Configuration/DataTransportObjectGeneratorConfiguration.php b/src/Configuration/DataTransportObjectGeneratorConfiguration.php index 0a165f14..e4883ce2 100644 --- a/src/Configuration/DataTransportObjectGeneratorConfiguration.php +++ b/src/Configuration/DataTransportObjectGeneratorConfiguration.php @@ -54,10 +54,10 @@ public function __construct(array $configuration) if (\array_key_exists('ObservableProperties', $configuration)) { $observableConfig = $configuration['ObservableProperties']; if (\array_key_exists('BeforeChange', $observableConfig)) { - $this->useBeforeChangeObservableProperties = $observableConfig['BeforeChange']; + $this->useBeforeChangeObservableProperties = true === $observableConfig['BeforeChange']; } if (\array_key_exists('AfterChange', $observableConfig)) { - $this->useBeforeChangeObservableProperties = $observableConfig['AfterChange']; + $this->useAfterChangeObservableProperties = true === $observableConfig['AfterChange']; } } } @@ -97,7 +97,7 @@ public function getPath(): string /** * @return bool */ - public function useAfterChangeObservableProperties(): bool + public function getUseAfterChangeObservableProperties(): bool { return $this->useAfterChangeObservableProperties; } @@ -105,7 +105,7 @@ public function useAfterChangeObservableProperties(): bool /** * @return bool */ - public function useBeforeChangeObservableProperties(): bool + public function getUseBeforeChangeObservableProperties(): bool { return $this->useBeforeChangeObservableProperties; } diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 96e67b6d..12b8405a 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -2,7 +2,9 @@ namespace Reliese\Generator\DataTransport; +use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\DatabaseBlueprint; +use Reliese\Blueprint\ForeignKeyBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\DataTransportObjectGeneratorConfiguration; use Reliese\Generator\DataAttribute\DataAttributeGenerator; @@ -10,6 +12,8 @@ use Reliese\MetaCode\Definition\ClassDefinition; use Reliese\MetaCode\Definition\ClassPropertyDefinition; use Reliese\MetaCode\Definition\ClassTraitDefinition; +use Reliese\MetaCode\Definition\RawStatementDefinition; +use Reliese\MetaCode\Enum\PhpTypeEnum; use Reliese\MetaCode\Format\ClassFormatter; use Reliese\MetaCode\Tool\ClassNameTool; use function file_exists; @@ -77,7 +81,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) $dtoAbstractClassDefinition = new ClassDefinition($abstractClassName, $abstractNamespace); - if ($this->dataTransportGeneratorConfiguration->useBeforeChangeObservableProperties()) { + if ($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) { $dtoAbstractClassDefinition->addInterface( \PhpLibs\Observable\BeforeValueChangeObservableInterface::class ); @@ -86,7 +90,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) ); } - if ($this->dataTransportGeneratorConfiguration->useAfterChangeObservableProperties()) { + if ($this->dataTransportGeneratorConfiguration->getUseAfterChangeObservableProperties()) { $dtoAbstractClassDefinition->addInterface( \PhpLibs\Observable\AfterValueChangeObservableInterface::class ); @@ -116,8 +120,12 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) * Use a property defined directly on the class */ $columnClassProperty = (new ClassPropertyDefinition($propertyName, $phpTypeEnum)) - ->setIsBeforeChangeObservable($this->dataTransportGeneratorConfiguration->useBeforeChangeObservableProperties()) - ->setIsAfterChangeObservable($this->dataTransportGeneratorConfiguration->useBeforeChangeObservableProperties()) + ->setIsBeforeChangeObservable( + $this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties() + ) + ->setIsAfterChangeObservable( + $this->dataTransportGeneratorConfiguration->getUseAfterChangeObservableProperties() + ) ->withSetter() ->withGetter() ; @@ -125,6 +133,74 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) $dtoAbstractClassDefinition->addProperty($columnClassProperty); } + /** + * Examine FKs + * @var ForeignKeyBlueprint $foreignKeyBlueprint + */ + foreach ($tableBlueprint->getForeignKeyBlueprintsGroupedByReferencedTable() as + $referencedTableName => $foreignKeyBlueprints + ) { + $comments = "Fk to: ".$referencedTableName; + $dtoAbstractClassDefinition->addClassComment($comments); + + $commonColumns = []; + $fkDtoProperty = null; + $dtoVariableName = null; + + $referencedTableBlueprint = null; + foreach ($foreignKeyBlueprints as $foreignKeyName => $foreignKeyBlueprint) { + + $referencedTableBlueprint ??= $foreignKeyBlueprint->getReferencedTableBlueprint(); + + $fkDtoClassName = $this->getClassName($referencedTableBlueprint); + + $dtoVariableName = ClassNameTool::dtoClassNameToVariableName($fkDtoClassName); +// + if (\is_null($fkDtoProperty)) { + $fkDtoProperty = ( + new ClassPropertyDefinition( + $dtoVariableName, + PhpTypeEnum::objectOfType( + $this->getFullyQualifiedClassName($referencedTableBlueprint) + ) + ) + ) + ->setIsBeforeChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) + ->setIsAfterChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) + ->withSetter() + ->withGetter() + ; + } + + foreach ($foreignKeyBlueprint->getFkColumnPairs() as $columns) { + /** + * @var ColumnBlueprint $referencingColumn + * @var ColumnBlueprint $referencedColumn + */ + [$referencingColumn, $referencedColumn] = $columns; + + $commonColumns[$referencingColumn->getColumnName().' = '.$referencedColumn->getColumnName()] = + [$referencingColumn, $referencedColumn]; + } + } + + foreach ($commonColumns as $columnPairs) { + [$referencingColumn, $referencedColumn] = $columnPairs; + + $fkDtoProperty->addAdditionalSetterOperation( + new RawStatementDefinition( + \sprintf( + "\$this->%s(\$%s->%s());\n", + ClassNameTool::columnNameToSetterName($referencingColumn->getColumnName()), + $dtoVariableName, + ClassNameTool::columnNameToGetterName($referencedColumn->getColumnName()), + ) + ) + ); + } + $dtoAbstractClassDefinition->addProperty($fkDtoProperty); + } + /* * Write the Class Files */ diff --git a/src/MetaCode/Definition/ClassPropertyDefinition.php b/src/MetaCode/Definition/ClassPropertyDefinition.php index 79bc2d39..9f27aaae 100644 --- a/src/MetaCode/Definition/ClassPropertyDefinition.php +++ b/src/MetaCode/Definition/ClassPropertyDefinition.php @@ -22,6 +22,11 @@ class ClassPropertyDefinition */ private ?VisibilityEnum $getterVisibilityEnum = null; + /** + * @var StatementDefinitionInterface[] + */ + private array $additionalSetterOperations = []; + /** * @var InstanceEnum|null */ @@ -145,17 +150,27 @@ public function getSetterMethodDefinition(ClassDefinition $containingClass): Cla $this->getSetterInstanceEnum(), ); - if ($this->getIsBeforeChangeObservable() && $containingClass->hasTrait('BeforeValueChangeObservableTrait')) { - $setter->appendBodyStatement(new RawStatementDefinition(\sprintf("\$this->raiseBeforeValueChange('%s', \$this->%s, \$\%s);\n", + if ($this->getIsBeforeChangeObservable() ) { + $setter->appendBodyStatement( + new RawStatementDefinition( + \sprintf( + "\$this->raiseBeforeValueChange('%s', \$this->%s, \$%s);\n", $this->getVariableName(), $this->getVariableName(), - $param->getParameterName(),))); + $param->getParameterName(), + ) + ) + ); } $setter->appendBodyStatement(new RawStatementDefinition(\sprintf("\$this->%s = $%s;\n", $this->getVariableName(), $param->getParameterName()))); + foreach ($this->additionalSetterOperations as $additionalSetterOperation) { + $setter->appendBodyStatement($additionalSetterOperation); + } + if ($this->getIsAfterChangeObservable() && $containingClass->hasTrait('AfterValueChangeObservableTrait')) { $setter->appendBodyStatement(new RawStatementDefinition(\sprintf("\$this->raiseAfterValueChange('%s', \$this->%s);\n", $this->getVariableName(), @@ -289,4 +304,14 @@ public function setValue(mixed $value): static return $this; } + /** + * @param StatementDefinitionInterface $statementDefinition + * + * @return $this + */ + public function addAdditionalSetterOperation(StatementDefinitionInterface $statementDefinition): static + { + $this->additionalSetterOperations[] = $statementDefinition; + return $this; + } } diff --git a/src/MetaCode/Tool/ClassNameTool.php b/src/MetaCode/Tool/ClassNameTool.php index 97ff33d2..a10c518d 100644 --- a/src/MetaCode/Tool/ClassNameTool.php +++ b/src/MetaCode/Tool/ClassNameTool.php @@ -71,4 +71,9 @@ public static function columnNameToSetterName(string $columnName): string { return 'set'.str::studly($columnName); } + + public static function dtoClassNameToVariableName(string $dtoClassName) + { + return \strtolower($dtoClassName[0]).\substr($dtoClassName, 1); + } } From 415431917cc6d9da00b6f209d54b832edcb5f382 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 11 May 2021 03:41:00 -0400 Subject: [PATCH 07/35] removed DTO debug comments --- src/Generator/DataTransport/DataTransportGenerator.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 12b8405a..c04d22e5 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -140,9 +140,6 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) foreach ($tableBlueprint->getForeignKeyBlueprintsGroupedByReferencedTable() as $referencedTableName => $foreignKeyBlueprints ) { - $comments = "Fk to: ".$referencedTableName; - $dtoAbstractClassDefinition->addClassComment($comments); - $commonColumns = []; $fkDtoProperty = null; $dtoVariableName = null; From ae59d0e97ffb12373ba993217ff5224af392843a Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 11 May 2021 04:52:32 -0400 Subject: [PATCH 08/35] Made DTO properties default to a nullable --- src/Generator/DataTransport/DataTransportGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index c04d22e5..a4edbe40 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -157,7 +157,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) $fkDtoProperty = ( new ClassPropertyDefinition( $dtoVariableName, - PhpTypeEnum::objectOfType( + PhpTypeEnum::nullableObjectOfType( $this->getFullyQualifiedClassName($referencedTableBlueprint) ) ) From 4bae836a85701d5266575bda088bd7fe026d8d76 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 11 May 2021 04:56:51 -0400 Subject: [PATCH 09/35] restored composer.json extra section --- composer.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/composer.json b/composer.json index 81731254..3f1ac535 100644 --- a/composer.json +++ b/composer.json @@ -48,5 +48,12 @@ }, "scripts": { "test": "phpunit --testdox" + }, + "extra": { + "laravel": { + "providers": [ + "Reliese\\RelieseServiceProvider" + ] + } } } From ab863db54889d7ab3e72046e5f3c3938e7fe219f Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 03:12:28 -0400 Subject: [PATCH 10/35] data map accessor generation --- composer.json | 7 - config/reliese.php | 2 + .../ModelDataMapGeneratorConfiguration.php | 29 ++- .../DataMap/ModelDataMapGenerator.php | 174 ++++++++++++++++++ .../DataTransport/DataTransportGenerator.php | 143 +++++++------- .../Definition/ClassPropertyDefinition.php | 49 ++++- .../Definition/ClassTraitDefinition.php | 8 +- .../Definition/RawStatementDefinition.php | 7 +- .../Definition/StatementBlockDefinition.php | 60 ++++++ .../StatementDefinitionCollection.php | 38 ++++ .../StatementDefinitionInterface.php | 4 +- src/MetaCode/Enum/PhpTypeEnum.php | 5 + src/MetaCode/Format/ClassFormatter.php | 26 +-- .../Format/IndentationProviderInterface.php | 21 +++ src/MetaCode/Tool/ClassNameTool.php | 29 +++ 15 files changed, 499 insertions(+), 103 deletions(-) create mode 100644 src/MetaCode/Definition/StatementBlockDefinition.php create mode 100644 src/MetaCode/Definition/StatementDefinitionCollection.php create mode 100644 src/MetaCode/Format/IndentationProviderInterface.php diff --git a/composer.json b/composer.json index 3f1ac535..81731254 100644 --- a/composer.json +++ b/composer.json @@ -48,12 +48,5 @@ }, "scripts": { "test": "phpunit --testdox" - }, - "extra": { - "laravel": { - "providers": [ - "Reliese\\RelieseServiceProvider" - ] - } } } diff --git a/config/reliese.php b/config/reliese.php index 1606c336..bc040a3b 100644 --- a/config/reliese.php +++ b/config/reliese.php @@ -579,6 +579,8 @@ 'Namespace' => 'App\DataMaps\PrimaryDatabase', 'ClassSuffix' => 'Map', 'ParentClassPrefix' => 'Abstract', + 'AccessorTraitNamespace' => 'app\DataMapAccessors\PrimaryDatabase', + 'AccessorTraitPath' => app_path().'/DataMapAccessors/PrimaryDatabase', ], // endregion Data Map Generator Config ] diff --git a/src/Configuration/ModelDataMapGeneratorConfiguration.php b/src/Configuration/ModelDataMapGeneratorConfiguration.php index 8ca7c9c9..c56b6f61 100644 --- a/src/Configuration/ModelDataMapGeneratorConfiguration.php +++ b/src/Configuration/ModelDataMapGeneratorConfiguration.php @@ -7,6 +7,16 @@ */ class ModelDataMapGeneratorConfiguration { + /** + * @var mixed|string + */ + private $accessorTraitNamespace; + + /** + * @var mixed|string + */ + private $accessorTraitPath; + /** * @var mixed */ @@ -34,11 +44,12 @@ class ModelDataMapGeneratorConfiguration */ public function __construct(array $configuration) { - $this->path = $configuration['Path']; $this->namespace = $configuration['Namespace']; $this->classSuffix = $configuration['ClassSuffix'] ?? ''; $this->parentClassPrefix = $configuration['ParentClassPrefix'] ?? ''; + $this->accessorTraitNamespace = $configuration['AccessorTraitNamespace'] ?? ''; + $this->accessorTraitPath = $configuration['AccessorTraitPath'] ?? ''; } /** @@ -72,4 +83,20 @@ public function getPath(): string { return $this->path; } + + /** + * @return ?string + */ + public function getAccessorTraitNamespace(): ?string + { + return $this->accessorTraitNamespace; + } + + /** + * @return mixed|string + */ + public function getAccessorTraitPath(): mixed + { + return $this->accessorTraitPath; + } } diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index 8f8d7758..cde5fc01 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -2,7 +2,10 @@ namespace Reliese\Generator\DataMap; +use app\DataTransport\Objects\PrimaryDatabase\OrganizationDto; +use app\Services\Identity\AccountService; use Illuminate\Support\Str; +use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\ModelDataMapGeneratorConfiguration; @@ -11,11 +14,19 @@ use Reliese\Generator\MySqlDataTypeMap; use Reliese\MetaCode\Definition\ClassDefinition; use Reliese\MetaCode\Definition\ClassMethodDefinition; +use Reliese\MetaCode\Definition\ClassPropertyDefinition; +use Reliese\MetaCode\Definition\ClassTraitDefinition; use Reliese\MetaCode\Definition\FunctionParameterDefinition; use Reliese\MetaCode\Definition\RawStatementDefinition; +use Reliese\MetaCode\Definition\StatementBlockDefinition; +use Reliese\MetaCode\Definition\StatementDefinitionCollection; +use Reliese\MetaCode\Definition\TraitDefinition; +use Reliese\MetaCode\Enum\InstanceEnum; use Reliese\MetaCode\Enum\PhpTypeEnum; +use Reliese\MetaCode\Enum\VisibilityEnum; use Reliese\MetaCode\Format\ClassFormatter; use Reliese\MetaCode\Tool\ClassNameTool; +use Reliese\MetaCode\Writers\CodeWriter; use function file_exists; use function file_put_contents; use function mkdir; @@ -147,6 +158,112 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) // dd($dtoPropertyAssignmentStatement); // dd([$modelParameterName, $modelConstant, $dtoParameterName, $setterName]); } + /* + * Look through FK Dto properties and Model FKs to assign DTO + */ + /* + * Example: + if ($account->relationLoaded('organization')) { + $organizationDto = $accountDto->getOrganizationDto() ?? new OrganizationDto(); + if ($this->organizationMap->toOrganizationDto($account->organization, $organizationDto)) { + $accountDto->setOrganizationDto($organizationDto); + } else { + return false; + } + } + */ + $requiredMapAccessorTraits = []; + $fkDtoProperties = $this->dataTransportGenerator->getForeignKeyDtoPropertyDefinitions($tableBlueprint); + foreach ($fkDtoProperties as $fkDtoProperty) { +// $fkDtoProperty = $fkDtoProperties[$foreignKeyBlueprint->getName()]; + + $fkDtoFullyQualifiedClassName = $fkDtoProperty->getPhpTypeEnum()->getFullyQualifiedObjectClassName(); + $fkDtoClassName = ClassNameTool::fullyQualifiedClassNameToClassName($fkDtoFullyQualifiedClassName); + $fkModelName = \substr($fkDtoClassName, 0, \strlen($fkDtoClassName)-3); + $modelRelationshipName = str::snake($fkModelName); + $fkModelMapType = $fkModelName.'Map'; +// $fkModelMapTraitType = $this->modelDataMapGeneratorConfiguration->getAccessorTraitNamespace() +// ."\\$fkModelMapType"; + $fkModelMapGetter = "get$fkModelMapType"; + $fkModelMapMapping = "to$fkDtoClassName"; + $relationshipName = str::snake($fkModelName); + $fkDtoVariableName = ClassNameTool::dtoClassNameToVariableName($fkDtoClassName); + $fkDtoGetterName = ClassNameTool::variableNameToGetterName($fkDtoVariableName); + $fkDtoSetterName = ClassNameTool::variableNameToSetterName($fkDtoVariableName); + + if (!\array_key_exists($fkModelMapType, $requiredMapAccessorTraits)) { + $requiredMapAccessorTraits[$fkModelMapType] + = $traitDefinition + = $this->generateModelDataMapAccessorTrait($this->getClassNamespaceByType($fkModelMapType)); + $modelMapAbstractClassDefinition->addTrait(new ClassTraitDefinition($traitDefinition->getFullyQualifiedName())); + } + + $statements = new StatementBlockDefinition( + /* + * example output: + * if ($account->relationLoaded('organization')) { + */ + new RawStatementDefinition(\sprintf("if (\$%s->relationLoaded('%s'))", $modelParameterName, $relationshipName)) + ); + $statements->addStatementDefinition( + new RawStatementDefinition( + /* + * example output: + * $organizationDto = $accountDto->getOrganizationDto() ?? new OrganizationDto(); + */ + \sprintf( + "\$%s = \$%s->%s() ?? new %s();", + $fkDtoVariableName, + $dtoParameterName, + $fkDtoGetterName, + $fkDtoFullyQualifiedClassName + ) + ) + ); + + $mapFkDtoStatement = new StatementBlockDefinition( + new RawStatementDefinition( + /* + * example output: + * if ($this->getOrganizationMap()->toOrganizationDto($account->organization, $organizationDto)) + */ + \sprintf( + "if (\$this->%s()->%s(\$%s->%s, \$%s))", + $fkModelMapGetter, + $fkModelMapMapping, + $modelParameterName, + $modelRelationshipName, + $fkDtoVariableName + ) + ) + ); + $mapFkDtoStatement + ->addStatementDefinition( + new RawStatementDefinition( + /* + * example output: + * $accountDto->setOrganizationDto($organizationDto); + */ + \sprintf( + "\$%s->%s(\$%s);", + $dtoParameterName, + $fkDtoSetterName, + $fkDtoVariableName, + ) + ) + ) + ->setBlockSuffixStatement( + (new StatementBlockDefinition(new RawStatementDefinition(" else "))) + ->addStatementDefinition(new RawStatementDefinition("return false;")) + ); + + $statements->addStatementDefinition($mapFkDtoStatement); + $mapToDtoMethodDefinition->appendBodyStatement($statements); + } + + + + $mapToDtoMethodDefinition->appendBodyStatement(new RawStatementDefinition("return true;")); $modelMapAbstractClassDefinition->addMethodDefinition($mapToDtoMethodDefinition); @@ -177,9 +294,61 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) /* * Write the Class Files */ + $codeWriter = new CodeWriter(); + foreach ($requiredMapAccessorTraits as $traitDefinition) { + $traitSource = (new ClassFormatter())->format($traitDefinition); + $filePath = $this->modelDataMapGeneratorConfiguration->getAccessorTraitPath().'/' + .$traitDefinition->getClassName().".php"; + $codeWriter->overwriteClassDefinition($filePath, $traitSource); + } $this->writeClassFiles($modelMapClassDefinition, $modelMapAbstractClassDefinition); } + public function generateModelDataMapAccessorTrait(string $fullyQualifiedModelDataMapClass) : TraitDefinition + { + $dataMapClass = ClassNameTool::fullyQualifiedClassNameToClassName($fullyQualifiedModelDataMapClass); + $dataMapNamespace = ClassNameTool::fullyQualifiedClassNameToNamespace($fullyQualifiedModelDataMapClass); + + $namespace = $this->modelDataMapGeneratorConfiguration->getAccessorTraitNamespace(); + $className = ClassNameTool::snakeCaseToClassName('With', $dataMapClass, null); + + $traitDefinition = new TraitDefinition($className, $namespace); + + $traitDefinition + ->addClassComment( + sprintf("Generated Accessor Trait for %s", $fullyQualifiedModelDataMapClass) + ) + ->addClassComment( + "This file is only generated if it does not already exist. To regenerate, remove this file." + ) + ; + + $propertyName = ClassNameTool::classNameToParameterName($dataMapClass); + $phpTypeEnum = PhpTypeEnum::nullableObjectOfType($fullyQualifiedModelDataMapClass); + + $getterStatementBlock = (new StatementDefinitionCollection()) + ->addStatementDefinition( + new RawStatementDefinition( + \sprintf( + "return \$this->%s ?? app(%s::class);", + $propertyName, + ClassNameTool::globalClassFQN($fullyQualifiedModelDataMapClass) + ) + ) + ); + + $property = (new ClassPropertyDefinition($propertyName, $phpTypeEnum)) + ->withGetter( + VisibilityEnum::protectedEnum(), + InstanceEnum::instanceEnum(), + $getterStatementBlock + ); + + $traitDefinition->addProperty($property); + + return $traitDefinition; + } + /** * @param TableBlueprint $tableBlueprint * @@ -266,4 +435,9 @@ private function writeClassFiles( } file_put_contents($abstractFilePath, $abstractPhpCode); } + + private function getClassNamespaceByType(string $fkModelMapType): string + { + return $this->modelDataMapGeneratorConfiguration->getNamespace()."\\".$fkModelMapType; + } } diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index a4edbe40..eb029a0e 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -133,68 +133,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) $dtoAbstractClassDefinition->addProperty($columnClassProperty); } - /** - * Examine FKs - * @var ForeignKeyBlueprint $foreignKeyBlueprint - */ - foreach ($tableBlueprint->getForeignKeyBlueprintsGroupedByReferencedTable() as - $referencedTableName => $foreignKeyBlueprints - ) { - $commonColumns = []; - $fkDtoProperty = null; - $dtoVariableName = null; - - $referencedTableBlueprint = null; - foreach ($foreignKeyBlueprints as $foreignKeyName => $foreignKeyBlueprint) { - - $referencedTableBlueprint ??= $foreignKeyBlueprint->getReferencedTableBlueprint(); - - $fkDtoClassName = $this->getClassName($referencedTableBlueprint); - - $dtoVariableName = ClassNameTool::dtoClassNameToVariableName($fkDtoClassName); -// - if (\is_null($fkDtoProperty)) { - $fkDtoProperty = ( - new ClassPropertyDefinition( - $dtoVariableName, - PhpTypeEnum::nullableObjectOfType( - $this->getFullyQualifiedClassName($referencedTableBlueprint) - ) - ) - ) - ->setIsBeforeChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) - ->setIsAfterChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) - ->withSetter() - ->withGetter() - ; - } - - foreach ($foreignKeyBlueprint->getFkColumnPairs() as $columns) { - /** - * @var ColumnBlueprint $referencingColumn - * @var ColumnBlueprint $referencedColumn - */ - [$referencingColumn, $referencedColumn] = $columns; - - $commonColumns[$referencingColumn->getColumnName().' = '.$referencedColumn->getColumnName()] = - [$referencingColumn, $referencedColumn]; - } - } - - foreach ($commonColumns as $columnPairs) { - [$referencingColumn, $referencedColumn] = $columnPairs; - - $fkDtoProperty->addAdditionalSetterOperation( - new RawStatementDefinition( - \sprintf( - "\$this->%s(\$%s->%s());\n", - ClassNameTool::columnNameToSetterName($referencingColumn->getColumnName()), - $dtoVariableName, - ClassNameTool::columnNameToGetterName($referencedColumn->getColumnName()), - ) - ) - ); - } + foreach ($this->getForeignKeyDtoPropertyDefinitions($tableBlueprint) as $fkDtoProperty) { $dtoAbstractClassDefinition->addProperty($fkDtoProperty); } @@ -271,5 +210,85 @@ private function writeClassFiles( file_put_contents($abstractDtoFilePath, $abstractDtoPhpCode); } + + /** + * @param TableBlueprint $tableBlueprint + * TODO: figure out how to cache these so they are not rebuilt on every call + * @return ClassPropertyDefinition[] + */ + public function getForeignKeyDtoPropertyDefinitions(TableBlueprint $tableBlueprint): array + { + $results = []; + + if (empty($tableBlueprint->getForeignKeyBlueprints())) { + return $results; + } + + /** + * Examine FKs + * @var ForeignKeyBlueprint $foreignKeyBlueprint + */ + foreach ($tableBlueprint->getForeignKeyBlueprintsGroupedByReferencedTable() as + $referencedTableName => $foreignKeyBlueprints + ) { + $commonColumns = []; + $fkDtoProperty = null; + $dtoVariableName = null; + + $referencedTableBlueprint = null; + foreach ($foreignKeyBlueprints as $foreignKeyName => $foreignKeyBlueprint) { + + $referencedTableBlueprint ??= $foreignKeyBlueprint->getReferencedTableBlueprint(); + + $fkDtoClassName = $this->getClassName($referencedTableBlueprint); + + $dtoVariableName = ClassNameTool::dtoClassNameToVariableName($fkDtoClassName); + // + if (\is_null($fkDtoProperty)) { + $fkDtoProperty = ( + new ClassPropertyDefinition( + $dtoVariableName, + PhpTypeEnum::nullableObjectOfType( + $this->getFullyQualifiedClassName($referencedTableBlueprint) + ) + ) + ) + ->setIsBeforeChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) + ->setIsAfterChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) + ->withSetter() + ->withGetter() + ; + } + + foreach ($foreignKeyBlueprint->getFkColumnPairs() as $columns) { + /** + * @var ColumnBlueprint $referencingColumn + * @var ColumnBlueprint $referencedColumn + */ + [$referencingColumn, $referencedColumn] = $columns; + + $commonColumns[$referencingColumn->getColumnName().' = '.$referencedColumn->getColumnName()] = + [$referencingColumn, $referencedColumn]; + } + } + + foreach ($commonColumns as $columnPairs) { + [$referencingColumn, $referencedColumn] = $columnPairs; + + $fkDtoProperty->addAdditionalSetterOperation( + new RawStatementDefinition( + \sprintf( + "\$this->%s(\$%s->%s());", + ClassNameTool::columnNameToSetterName($referencingColumn->getColumnName()), + $dtoVariableName, + ClassNameTool::columnNameToGetterName($referencedColumn->getColumnName()), + ) + ) + ); + } + $results[] = $fkDtoProperty; + } + return $results; + } } diff --git a/src/MetaCode/Definition/ClassPropertyDefinition.php b/src/MetaCode/Definition/ClassPropertyDefinition.php index 9f27aaae..23008bb1 100644 --- a/src/MetaCode/Definition/ClassPropertyDefinition.php +++ b/src/MetaCode/Definition/ClassPropertyDefinition.php @@ -6,6 +6,7 @@ use Reliese\MetaCode\Enum\InstanceEnum; use Reliese\MetaCode\Enum\PhpTypeEnum; use Reliese\MetaCode\Enum\VisibilityEnum; +use Reliese\MetaCode\Tool\ClassNameTool; /** * Class ClassPropertyDefinition @@ -17,6 +18,11 @@ class ClassPropertyDefinition */ private ?InstanceEnum $getterInstanceEnum = null; + /** + * @var StatementDefinitionInterface|null + */ + private ?StatementDefinitionInterface $getterMethodBody; + /** * @var VisibilityEnum|null */ @@ -245,16 +251,20 @@ public function setIsBeforeChangeObservable(bool $isBeforeChangeObservable): Cla } /** - * @param VisibilityEnum|null $getterVisibilityEnum - * @param InstanceEnum|null $getterInstanceEnum + * @param VisibilityEnum|null $getterVisibilityEnum + * @param InstanceEnum|null $getterInstanceEnum + * @param StatementDefinitionInterface|null $statementDefinitionInterface * * @return $this */ - public function withGetter(?VisibilityEnum $getterVisibilityEnum = null, - ?InstanceEnum $getterInstanceEnum = null): ClassPropertyDefinition - { + public function withGetter( + ?VisibilityEnum $getterVisibilityEnum = null, + ?InstanceEnum $getterInstanceEnum = null, + ?StatementDefinitionInterface $statementDefinitionInterface = null + ): ClassPropertyDefinition { $this->getterVisibilityEnum = $getterVisibilityEnum ?? VisibilityEnum::publicEnum(); $this->getterInstanceEnum = $getterInstanceEnum ?? InstanceEnum::instanceEnum(); + $this->getterMethodBody = $statementDefinitionInterface; return $this; } @@ -314,4 +324,33 @@ public function addAdditionalSetterOperation(StatementDefinitionInterface $state $this->additionalSetterOperations[] = $statementDefinition; return $this; } + + /** + * @param ClassDefinition $classDefinition + * + * @return ClassMethodDefinition + */ + public function getGetterMethodDefinition(ClassDefinition $classDefinition) : ClassMethodDefinition + { + return $this->getterMethodDefinition ??= $this->defaultGetterMethodDefinition(); + } + + /** + * @return ClassMethodDefinition + */ + protected function defaultGetterMethodDefinition(): ClassMethodDefinition + { + $getterFunctionName = ClassNameTool::variableNameToGetterName($this->getVariableName()); + $getterFunctionType = $this->getPhpTypeEnum(); + + $classMethod = new ClassMethodDefinition($getterFunctionName, $getterFunctionType); + + if ($this->getterMethodBody instanceof StatementDefinitionInterface) { + $classMethod->appendBodyStatement($this->getterMethodBody); + } else { + $classMethod->appendBodyStatement(new RawStatementDefinition('return $this->' . $this->getVariableName() . ';')); + } + + return $classMethod; + } } diff --git a/src/MetaCode/Definition/ClassTraitDefinition.php b/src/MetaCode/Definition/ClassTraitDefinition.php index 2db0e598..bb7f0b1e 100644 --- a/src/MetaCode/Definition/ClassTraitDefinition.php +++ b/src/MetaCode/Definition/ClassTraitDefinition.php @@ -4,6 +4,7 @@ namespace Reliese\MetaCode\Definition; +use Reliese\MetaCode\Tool\ClassNameTool; class ClassTraitDefinition implements ImportableInterface { private string $name; @@ -17,11 +18,8 @@ class ClassTraitDefinition implements ImportableInterface */ public function __construct(string $fullyQualifiedTraitName) { - $parts = explode('\\', \ltrim($fullyQualifiedTraitName, '\\')); - $name = \array_pop($parts); - $namespace = \implode('\\', $parts); - $this->name = $name; - $this->namespace = trim($namespace, '\\'); + $this->name = ClassNameTool::fullyQualifiedClassNameToClassName($fullyQualifiedTraitName); + $this->namespace = trim(ClassNameTool::fullyQualifiedClassNameToNamespace($fullyQualifiedTraitName)); } /** diff --git a/src/MetaCode/Definition/RawStatementDefinition.php b/src/MetaCode/Definition/RawStatementDefinition.php index f7cebaf7..736abae6 100644 --- a/src/MetaCode/Definition/RawStatementDefinition.php +++ b/src/MetaCode/Definition/RawStatementDefinition.php @@ -2,6 +2,7 @@ namespace Reliese\MetaCode\Definition; +use Reliese\MetaCode\Format\IndentationProviderInterface; /** * Class RawStatementDefinition */ @@ -11,11 +12,11 @@ class RawStatementDefinition implements StatementDefinitionInterface public function __construct(string $rawPhpCode) { - $this->rawPhpCode = $rawPhpCode; + $this->rawPhpCode = trim($rawPhpCode); } - public function toPhpCode(): string + public function toPhpCode(IndentationProviderInterface $indentationProvider, int $blockDepth): string { - return $this->rawPhpCode; + return $indentationProvider->getIndentation($blockDepth).$this->rawPhpCode; } } diff --git a/src/MetaCode/Definition/StatementBlockDefinition.php b/src/MetaCode/Definition/StatementBlockDefinition.php new file mode 100644 index 00000000..c3701737 --- /dev/null +++ b/src/MetaCode/Definition/StatementBlockDefinition.php @@ -0,0 +1,60 @@ +blockPrefixStatement = $blockPrefixStatement; + } + + private ?StatementDefinitionInterface $blockSuffixStatement = null; + + /** + * @return string + */ + public function toPhpCode(IndentationProviderInterface $indentationProvider, int $blockDepth): string + { + $prefixStatement = ""; + $suffixStatement = ""; + + if ($this->blockPrefixStatement instanceof StatementDefinitionInterface) { + $prefixStatement = $this->blockPrefixStatement->toPhpCode($indentationProvider, $blockDepth)." "; + } + + if ($this->blockSuffixStatement instanceof StatementBlockDefinition) { + $suffixStatement = " ".ltrim($this->blockSuffixStatement->toPhpCode($indentationProvider, $blockDepth)); + } + + return \sprintf( + "%s{\n%s\n%s}%s\n", + $prefixStatement, + parent::toPhpCode($indentationProvider, $blockDepth + 1), + $indentationProvider->getIndentation($blockDepth), + $suffixStatement + ); + } + + /** + * @param StatementDefinitionInterface|null $blockSuffixStatement + * + * @return StatementBlockDefinition + */ + public function setBlockSuffixStatement(?StatementDefinitionInterface $blockSuffixStatement): StatementBlockDefinition + { + $this->blockSuffixStatement = $blockSuffixStatement; + return $this; + } +} diff --git a/src/MetaCode/Definition/StatementDefinitionCollection.php b/src/MetaCode/Definition/StatementDefinitionCollection.php new file mode 100644 index 00000000..37b4e508 --- /dev/null +++ b/src/MetaCode/Definition/StatementDefinitionCollection.php @@ -0,0 +1,38 @@ +statementDefinitions[] = $statementDefinition; + return $this; + } + + /** + * @return string + */ + public function toPhpCode(IndentationProviderInterface $indentationProvider, int $blockDepth): string + { + $statements = []; + foreach ($this->statementDefinitions as $statementDefinition) { + $statements[] = $statementDefinition->toPhpCode($indentationProvider, $blockDepth); + } + return \implode("\n", $statements); + } +} diff --git a/src/MetaCode/Definition/StatementDefinitionInterface.php b/src/MetaCode/Definition/StatementDefinitionInterface.php index 07da2c1b..d13ccb0a 100644 --- a/src/MetaCode/Definition/StatementDefinitionInterface.php +++ b/src/MetaCode/Definition/StatementDefinitionInterface.php @@ -2,7 +2,9 @@ namespace Reliese\MetaCode\Definition; +use Reliese\MetaCode\Format\IndentationProviderInterface; + interface StatementDefinitionInterface { - public function toPhpCode():string; + public function toPhpCode(IndentationProviderInterface $indentationProvider, int $blockDepth): string; } diff --git a/src/MetaCode/Enum/PhpTypeEnum.php b/src/MetaCode/Enum/PhpTypeEnum.php index 465c8262..d08e4ee9 100644 --- a/src/MetaCode/Enum/PhpTypeEnum.php +++ b/src/MetaCode/Enum/PhpTypeEnum.php @@ -437,6 +437,11 @@ public function __toString(): string return __METHOD__.' failed'; } + public function getFullyQualifiedObjectClassName(): ?string + { + return '\\'.trim($this->fullyQualifiedObjectClassName, '\\'); + } + private function setContainedTypeName(string $containedTypeName) : PhpTypeEnum { $this->containedTypeName = $containedTypeName; diff --git a/src/MetaCode/Format/ClassFormatter.php b/src/MetaCode/Format/ClassFormatter.php index 44d81929..8be9075a 100644 --- a/src/MetaCode/Format/ClassFormatter.php +++ b/src/MetaCode/Format/ClassFormatter.php @@ -16,7 +16,7 @@ /** * Class ClassFormatter */ -class ClassFormatter +class ClassFormatter implements IndentationProviderInterface { /** * @param ClassDefinition $classDefinition @@ -81,7 +81,7 @@ public function format(ClassDefinition $classDefinition): string * * @return string */ - private function getIndentation(int $depth): string + public function getIndentation(int $depth): string { return str_repeat($this->getIndentationSymbol(), $depth); } @@ -89,7 +89,7 @@ private function getIndentation(int $depth): string /** * @return string */ - private function getIndentationSymbol(): string + public function getIndentationSymbol(): string { return ' '; } @@ -107,7 +107,9 @@ private function prepareGettersAndSetters(ClassDefinition $classDefinition): voi ); } if ($property->hasGetter()) { - $this->appendGetter($property, $classDefinition); + $classDefinition->addMethodDefinition( + $property->getGetterMethodDefinition($classDefinition) + ); } } } @@ -248,19 +250,6 @@ private function appendSetter(ClassPropertyDefinition $property, ClassDefinition $classDefinition->addMethodDefinition($getter); } - /** - * @param ClassPropertyDefinition $property - * @param ClassDefinition $classDefinition - */ - private function appendGetter(ClassPropertyDefinition $property, ClassDefinition $classDefinition): void - { - $getter = new ClassMethodDefinition('get' . Str::studly($property->getVariableName()), - $property->getPhpTypeEnum()); - $getter->appendBodyStatement(new RawStatementDefinition('return $this->' . $property->getVariableName() . ';')); - - $classDefinition->addMethodDefinition($getter); - } - /** * @param ClassDefinition $classDefinition * @param int $depth @@ -309,8 +298,7 @@ private function formatMethod(ClassDefinition $classDefinition, ClassMethodDefin $blockDepth = $depth + 1; foreach ($method->getBlockStatements() as $statement) { - $signature .= $this->getIndentation($blockDepth) - . $statement->toPhpCode() + $signature .= $statement->toPhpCode($this, $blockDepth) . "\n"; } diff --git a/src/MetaCode/Format/IndentationProviderInterface.php b/src/MetaCode/Format/IndentationProviderInterface.php new file mode 100644 index 00000000..3e1da368 --- /dev/null +++ b/src/MetaCode/Format/IndentationProviderInterface.php @@ -0,0 +1,21 @@ + Date: Thu, 13 May 2021 03:19:25 -0400 Subject: [PATCH 11/35] fixed issue with implement statements missing the leading '\' chareacter --- src/MetaCode/Definition/ClassDefinition.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php index b43a9693..9833c053 100644 --- a/src/MetaCode/Definition/ClassDefinition.php +++ b/src/MetaCode/Definition/ClassDefinition.php @@ -2,6 +2,7 @@ namespace Reliese\MetaCode\Definition; +use Reliese\MetaCode\Tool\ClassNameTool; use RuntimeException; /** @@ -110,6 +111,7 @@ public function __construct( */ public function addInterface(string $fullyQualifiedInterfaceName) { + $fullyQualifiedInterfaceName = ClassNameTool::globalClassFQN($fullyQualifiedInterfaceName); $this->interfaces[$fullyQualifiedInterfaceName] = true; } From 842ffc4c11c316245cb0d7dadef97bd1c221bf41 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 05:07:20 -0400 Subject: [PATCH 12/35] added dependency for php-libs/value-states --- composer.json | 3 +- composer.lock | 352 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 215 insertions(+), 140 deletions(-) diff --git a/composer.json b/composer.json index 81731254..6e9c586c 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "illuminate/contracts": ">=5.1", "illuminate/filesystem": ">=5.1", "illuminate/console": ">=5.1", - "php-libs/observable": "^1.0" + "php-libs/observable": "^1.0", + "php-libs/value-states": "^1.0" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index 6da42dcb..9ed1b504 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "811e4566886ac6e2a5a71c710bd3c214", + "content-hash": "dd44ace547e9f9a0fd5e030c72306f70", "packages": [ { "name": "composer/package-versions-deprecated", @@ -81,40 +81,39 @@ }, { "name": "doctrine/cache", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "13e3381b25847283a91948d04640543941309727" + "reference": "a9c1b59eba5a08ca2770a76eddb88922f504e8e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/13e3381b25847283a91948d04640543941309727", - "reference": "13e3381b25847283a91948d04640543941309727", + "url": "https://api.github.com/repos/doctrine/cache/zipball/a9c1b59eba5a08ca2770a76eddb88922f504e8e0", + "reference": "a9c1b59eba5a08ca2770a76eddb88922f504e8e0", "shasum": "" }, "require": { "php": "~7.1 || ^8.0" }, "conflict": { - "doctrine/common": ">2.2,<2.4" + "doctrine/common": ">2.2,<2.4", + "psr/cache": ">=3" }, "require-dev": { "alcaeus/mongo-php-adapter": "^1.1", - "doctrine/coding-standard": "^6.0", + "cache/integration-tests": "dev-master", + "doctrine/coding-standard": "^8.0", "mongodb/mongodb": "^1.1", - "phpunit/phpunit": "^7.0", - "predis/predis": "~1.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "predis/predis": "~1.0", + "psr/cache": "^1.0 || ^2.0", + "symfony/cache": "^4.4 || ^5.2" }, "suggest": { "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" @@ -161,7 +160,7 @@ ], "support": { "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/1.10.x" + "source": "https://github.com/doctrine/cache/tree/1.11.0" }, "funding": [ { @@ -177,37 +176,39 @@ "type": "tidelift" } ], - "time": "2020-07-07T18:54:01+00:00" + "time": "2021-04-13T14:46:17+00:00" }, { "name": "doctrine/dbal", - "version": "3.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "ee6d1260d5cc20ec506455a585945d7bdb98662c" + "reference": "5ba62e7e40df119424866064faf2cef66cb5232a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/ee6d1260d5cc20ec506455a585945d7bdb98662c", - "reference": "ee6d1260d5cc20ec506455a585945d7bdb98662c", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/5ba62e7e40df119424866064faf2cef66cb5232a", + "reference": "5ba62e7e40df119424866064faf2cef66cb5232a", "shasum": "" }, "require": { "composer/package-versions-deprecated": "^1.11.99", "doctrine/cache": "^1.0", + "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", "php": "^7.3 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^8.1", - "jetbrains/phpstorm-stubs": "^2019.1", - "phpstan/phpstan": "^0.12.40", + "doctrine/coding-standard": "8.2.0", + "jetbrains/phpstorm-stubs": "2020.2", + "phpstan/phpstan": "0.12.81", "phpstan/phpstan-strict-rules": "^0.12.2", - "phpunit/phpunit": "^9.4", - "psalm/plugin-phpunit": "^0.10.0", + "phpunit/phpunit": "9.5.0", + "psalm/plugin-phpunit": "0.13.0", + "squizlabs/php_codesniffer": "3.6.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0", - "vimeo/psalm": "^3.17.2" + "vimeo/psalm": "4.6.4" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -216,11 +217,6 @@ "bin/doctrine-dbal" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\DBAL\\": "src" @@ -272,7 +268,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.0.0" + "source": "https://github.com/doctrine/dbal/tree/3.1.0" }, "funding": [ { @@ -288,7 +284,50 @@ "type": "tidelift" } ], - "time": "2020-11-15T18:20:41+00:00" + "time": "2021-04-19T17:51:23+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "v0.5.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/9504165960a1f83cc1480e2be1dd0a0478561314", + "reference": "9504165960a1f83cc1480e2be1dd0a0478561314", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0|^7.0|^8.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v0.5.3" + }, + "time": "2021-03-21T12:59:47+00:00" }, { "name": "doctrine/event-manager", @@ -481,16 +520,16 @@ }, { "name": "illuminate/collections", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", - "reference": "e18d6e4cf03dd597bc3ecd86fefc2023d0c7a5e8" + "reference": "deccb956d38710f3f8baf36dd876c3fa1585ec22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/collections/zipball/e18d6e4cf03dd597bc3ecd86fefc2023d0c7a5e8", - "reference": "e18d6e4cf03dd597bc3ecd86fefc2023d0c7a5e8", + "url": "https://api.github.com/repos/illuminate/collections/zipball/deccb956d38710f3f8baf36dd876c3fa1585ec22", + "reference": "deccb956d38710f3f8baf36dd876c3fa1585ec22", "shasum": "" }, "require": { @@ -531,20 +570,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-03-19T00:05:33+00:00" + "time": "2021-04-22T21:08:09+00:00" }, { "name": "illuminate/console", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/console.git", - "reference": "dcc1fd330b7ea8fcf259bbf73243bfedc98e45a3" + "reference": "395002ac2d4ec404c42e6e97997f4236dc8ab2b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/console/zipball/dcc1fd330b7ea8fcf259bbf73243bfedc98e45a3", - "reference": "dcc1fd330b7ea8fcf259bbf73243bfedc98e45a3", + "url": "https://api.github.com/repos/illuminate/console/zipball/395002ac2d4ec404c42e6e97997f4236dc8ab2b6", + "reference": "395002ac2d4ec404c42e6e97997f4236dc8ab2b6", "shasum": "" }, "require": { @@ -591,11 +630,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-03-16T21:53:44+00:00" + "time": "2021-04-26T12:39:58+00:00" }, { "name": "illuminate/container", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/container.git", @@ -646,16 +685,16 @@ }, { "name": "illuminate/contracts", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "121cea1d8b8772bc7fee99c71ecf0f57c1d77b3b" + "reference": "64abbe2aeee0855a11cfce49d0ea08a0aa967cd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/121cea1d8b8772bc7fee99c71ecf0f57c1d77b3b", - "reference": "121cea1d8b8772bc7fee99c71ecf0f57c1d77b3b", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/64abbe2aeee0855a11cfce49d0ea08a0aa967cd2", + "reference": "64abbe2aeee0855a11cfce49d0ea08a0aa967cd2", "shasum": "" }, "require": { @@ -690,20 +729,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-03-12T14:45:30+00:00" + "time": "2021-05-06T14:58:48+00:00" }, { "name": "illuminate/database", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/database.git", - "reference": "74a165fd07b36cc0ea3558fa391b762867af87e8" + "reference": "6277b39728bce436d2509d215223137d87265792" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/database/zipball/74a165fd07b36cc0ea3558fa391b762867af87e8", - "reference": "74a165fd07b36cc0ea3558fa391b762867af87e8", + "url": "https://api.github.com/repos/illuminate/database/zipball/6277b39728bce436d2509d215223137d87265792", + "reference": "6277b39728bce436d2509d215223137d87265792", "shasum": "" }, "require": { @@ -758,20 +797,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-03-23T15:12:51+00:00" + "time": "2021-05-11T13:24:37+00:00" }, { "name": "illuminate/filesystem", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/filesystem.git", - "reference": "25e31d4f114baf1f99110bb5fc7538f26b4367cb" + "reference": "8ef5902052c5b3bb4a6c1c3afc399f30e7723cb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/filesystem/zipball/25e31d4f114baf1f99110bb5fc7538f26b4367cb", - "reference": "25e31d4f114baf1f99110bb5fc7538f26b4367cb", + "url": "https://api.github.com/repos/illuminate/filesystem/zipball/8ef5902052c5b3bb4a6c1c3afc399f30e7723cb8", + "reference": "8ef5902052c5b3bb4a6c1c3afc399f30e7723cb8", "shasum": "" }, "require": { @@ -820,11 +859,11 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-03-21T13:46:59+00:00" + "time": "2021-04-05T18:45:36+00:00" }, { "name": "illuminate/macroable", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -870,16 +909,16 @@ }, { "name": "illuminate/support", - "version": "v8.34.0", + "version": "v8.41.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "b7b27e758b68aad44558c62e7374328835895386" + "reference": "31e91a12f0aac770d02a05b5d5771829132213b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/b7b27e758b68aad44558c62e7374328835895386", - "reference": "b7b27e758b68aad44558c62e7374328835895386", + "url": "https://api.github.com/repos/illuminate/support/zipball/31e91a12f0aac770d02a05b5d5771829132213b4", + "reference": "31e91a12f0aac770d02a05b5d5771829132213b4", "shasum": "" }, "require": { @@ -934,20 +973,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-03-21T13:37:37+00:00" + "time": "2021-05-10T13:42:57+00:00" }, { "name": "nesbot/carbon", - "version": "2.46.0", + "version": "2.48.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4" + "reference": "d3c447f21072766cddec3522f9468a5849a76147" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4", - "reference": "2fd2c4a77d58a4e95234c8a61c5df1f157a91bf4", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d3c447f21072766cddec3522f9468a5849a76147", + "reference": "d3c447f21072766cddec3522f9468a5849a76147", "shasum": "" }, "require": { @@ -1027,7 +1066,7 @@ "type": "tidelift" } ], - "time": "2021-02-24T17:30:44+00:00" + "time": "2021-05-07T10:08:30+00:00" }, { "name": "php-libs/observable", @@ -1063,6 +1102,41 @@ }, "time": "2021-05-06T20:42:12+00:00" }, + { + "name": "php-libs/value-states", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/php-libs/value-state.git", + "reference": "6f7d16b25e4417d23be0f4092a44fca940247d89" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-libs/value-state/zipball/6f7d16b25e4417d23be0f4092a44fca940247d89", + "reference": "6f7d16b25e4417d23be0f4092a44fca940247d89", + "shasum": "" + }, + "require": { + "php": "^8.0", + "php-libs/observable": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpLibs\\ValueState\\": "src/PhpLibs/ValueState" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extends php-libs/observer to track if a values have been initialized or modified (changed after initialization)", + "support": { + "issues": "https://github.com/php-libs/value-state/issues", + "source": "https://github.com/php-libs/value-state/tree/1.0" + }, + "time": "2021-05-13T08:31:45+00:00" + }, { "name": "psr/container", "version": "1.1.1", @@ -1164,16 +1238,16 @@ }, { "name": "symfony/console", - "version": "v5.2.5", + "version": "v5.2.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79" + "reference": "864568fdc0208b3eba3638b6000b69d2386e6768" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/938ebbadae1b0a9c9d1ec313f87f9708609f1b79", - "reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79", + "url": "https://api.github.com/repos/symfony/console/zipball/864568fdc0208b3eba3638b6000b69d2386e6768", + "reference": "864568fdc0208b3eba3638b6000b69d2386e6768", "shasum": "" }, "require": { @@ -1241,7 +1315,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.2.5" + "source": "https://github.com/symfony/console/tree/v5.2.8" }, "funding": [ { @@ -1257,20 +1331,20 @@ "type": "tidelift" } ], - "time": "2021-03-06T13:42:15+00:00" + "time": "2021-05-11T15:45:21+00:00" }, { "name": "symfony/finder", - "version": "v5.2.4", + "version": "v5.2.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "0d639a0943822626290d169965804f79400e6a04" + "reference": "eccb8be70d7a6a2230d05f6ecede40f3fdd9e252" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", - "reference": "0d639a0943822626290d169965804f79400e6a04", + "url": "https://api.github.com/repos/symfony/finder/zipball/eccb8be70d7a6a2230d05f6ecede40f3fdd9e252", + "reference": "eccb8be70d7a6a2230d05f6ecede40f3fdd9e252", "shasum": "" }, "require": { @@ -1302,7 +1376,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.4" + "source": "https://github.com/symfony/finder/tree/v5.2.8" }, "funding": [ { @@ -1318,7 +1392,7 @@ "type": "tidelift" } ], - "time": "2021-02-15T18:55:04+00:00" + "time": "2021-05-10T14:39:23+00:00" }, { "name": "symfony/polyfill-ctype", @@ -1808,16 +1882,16 @@ }, { "name": "symfony/process", - "version": "v5.2.4", + "version": "v5.2.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f" + "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f", - "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f", + "url": "https://api.github.com/repos/symfony/process/zipball/98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e", + "reference": "98cb8eeb72e55d4196dd1e36f1f16e7b3a9a088e", "shasum": "" }, "require": { @@ -1850,7 +1924,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.2.4" + "source": "https://github.com/symfony/process/tree/v5.3.0-BETA1" }, "funding": [ { @@ -1866,25 +1940,25 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:15:41+00:00" + "time": "2021-04-08T10:27:02+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.2.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" + "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", - "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", + "reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.0" + "psr/container": "^1.1" }, "suggest": { "symfony/service-implementation": "" @@ -1892,7 +1966,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-main": "2.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -1929,7 +2003,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/master" + "source": "https://github.com/symfony/service-contracts/tree/v2.4.0" }, "funding": [ { @@ -1945,20 +2019,20 @@ "type": "tidelift" } ], - "time": "2020-09-07T11:33:47+00:00" + "time": "2021-04-01T10:43:52+00:00" }, { "name": "symfony/string", - "version": "v5.2.4", + "version": "v5.2.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "4e78d7d47061fa183639927ec40d607973699609" + "reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/4e78d7d47061fa183639927ec40d607973699609", - "reference": "4e78d7d47061fa183639927ec40d607973699609", + "url": "https://api.github.com/repos/symfony/string/zipball/01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db", + "reference": "01b35eb64cac8467c3f94cd0ce2d0d376bb7d1db", "shasum": "" }, "require": { @@ -2012,7 +2086,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.2.4" + "source": "https://github.com/symfony/string/tree/v5.2.8" }, "funding": [ { @@ -2028,20 +2102,20 @@ "type": "tidelift" } ], - "time": "2021-02-16T10:20:28+00:00" + "time": "2021-05-10T14:56:10+00:00" }, { "name": "symfony/translation", - "version": "v5.2.5", + "version": "v5.2.8", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "0947ab1e3aabd22a6bef393874b2555d2bb976da" + "reference": "445caa74a5986f1cc9dd91a2975ef68fa7cb2068" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/0947ab1e3aabd22a6bef393874b2555d2bb976da", - "reference": "0947ab1e3aabd22a6bef393874b2555d2bb976da", + "url": "https://api.github.com/repos/symfony/translation/zipball/445caa74a5986f1cc9dd91a2975ef68fa7cb2068", + "reference": "445caa74a5986f1cc9dd91a2975ef68fa7cb2068", "shasum": "" }, "require": { @@ -2105,7 +2179,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.2.5" + "source": "https://github.com/symfony/translation/tree/v5.2.8" }, "funding": [ { @@ -2121,20 +2195,20 @@ "type": "tidelift" } ], - "time": "2021-03-06T07:59:01+00:00" + "time": "2021-05-07T13:41:16+00:00" }, { "name": "symfony/translation-contracts", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105" + "reference": "95c812666f3e91db75385749fe219c5e494c7f95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/e2eaa60b558f26a4b0354e1bbb25636efaaad105", - "reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/95c812666f3e91db75385749fe219c5e494c7f95", + "reference": "95c812666f3e91db75385749fe219c5e494c7f95", "shasum": "" }, "require": { @@ -2146,7 +2220,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-main": "2.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2183,7 +2257,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v2.3.0" + "source": "https://github.com/symfony/translation-contracts/tree/v2.4.0" }, "funding": [ { @@ -2199,7 +2273,7 @@ "type": "tidelift" } ], - "time": "2020-09-28T13:05:58+00:00" + "time": "2021-03-23T23:28:01+00:00" }, { "name": "voku/portable-ascii", @@ -2783,16 +2857,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.10.4", + "version": "v4.10.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" + "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4432ba399e47c66624bc73c8c0f811e5c109576f", + "reference": "4432ba399e47c66624bc73c8c0f811e5c109576f", "shasum": "" }, "require": { @@ -2833,9 +2907,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.5" }, - "time": "2020-12-20T10:01:03+00:00" + "time": "2021-05-03T19:11:20+00:00" }, { "name": "phar-io/manifest", @@ -3175,16 +3249,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.5", + "version": "9.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1" + "reference": "f6293e1b30a2354e8428e004689671b83871edde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", + "reference": "f6293e1b30a2354e8428e004689671b83871edde", "shasum": "" }, "require": { @@ -3240,7 +3314,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.5" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" }, "funding": [ { @@ -3248,7 +3322,7 @@ "type": "github" } ], - "time": "2020-11-28T06:44:49+00:00" + "time": "2021-03-28T07:26:59+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4610,16 +4684,16 @@ }, { "name": "symfony/config", - "version": "v5.2.7", + "version": "v5.2.8", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "3817662ada105c8c4d1afdb4ec003003efd1d8d8" + "reference": "8dfa5f8adea9cd5155920069224beb04f11d6b7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/3817662ada105c8c4d1afdb4ec003003efd1d8d8", - "reference": "3817662ada105c8c4d1afdb4ec003003efd1d8d8", + "url": "https://api.github.com/repos/symfony/config/zipball/8dfa5f8adea9cd5155920069224beb04f11d6b7e", + "reference": "8dfa5f8adea9cd5155920069224beb04f11d6b7e", "shasum": "" }, "require": { @@ -4668,7 +4742,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.2.7" + "source": "https://github.com/symfony/config/tree/v5.2.8" }, "funding": [ { @@ -4684,20 +4758,20 @@ "type": "tidelift" } ], - "time": "2021-04-07T16:07:52+00:00" + "time": "2021-05-07T13:41:16+00:00" }, { "name": "symfony/dependency-injection", - "version": "v5.2.7", + "version": "v5.2.8", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "6ca378b99e3c9ba6127eb43b68389fb2b7348577" + "reference": "024e929da5a994cbab0ce2291d332f7edf926acf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/6ca378b99e3c9ba6127eb43b68389fb2b7348577", - "reference": "6ca378b99e3c9ba6127eb43b68389fb2b7348577", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/024e929da5a994cbab0ce2291d332f7edf926acf", + "reference": "024e929da5a994cbab0ce2291d332f7edf926acf", "shasum": "" }, "require": { @@ -4755,7 +4829,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.2.7" + "source": "https://github.com/symfony/dependency-injection/tree/v5.2.8" }, "funding": [ { @@ -4771,7 +4845,7 @@ "type": "tidelift" } ], - "time": "2021-04-24T14:32:26+00:00" + "time": "2021-05-11T16:07:35+00:00" }, { "name": "symfony/deprecation-contracts", From f915a7a306f29996cd6193cb12b08378740636f7 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 05:09:49 -0400 Subject: [PATCH 13/35] Added constructor generation for data transport objects --- .../DataTransport/DataTransportGenerator.php | 7 ++++- src/MetaCode/Definition/ClassDefinition.php | 28 +++++++++++++++++++ .../Definition/ClassPropertyDefinition.php | 13 ++++++--- .../StatementDefinitionCollection.php | 5 ++++ src/MetaCode/Enum/PhpTypeEnum.php | 28 +++++++++++++++++++ src/MetaCode/Format/ClassFormatter.php | 22 +++++++++++++-- src/MetaCode/Tool/ClassNameTool.php | 5 ++++ 7 files changed, 101 insertions(+), 7 deletions(-) diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index eb029a0e..2d9667cc 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -2,6 +2,7 @@ namespace Reliese\Generator\DataTransport; +use PhpLibs\ValueState\WithValueStates; use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\ForeignKeyBlueprint; @@ -18,7 +19,6 @@ use Reliese\MetaCode\Tool\ClassNameTool; use function file_exists; use function file_put_contents; -use function mkdir; use const DIRECTORY_SEPARATOR; /** @@ -80,6 +80,11 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) $abstractNamespace = $this->getAbstractClassNamespace($tableBlueprint); $dtoAbstractClassDefinition = new ClassDefinition($abstractClassName, $abstractNamespace); + $dtoAbstractClassDefinition + ->addTrait(new ClassTraitDefinition(WithValueStates::class)) + ->addConstructorStatement( + new RawStatementDefinition("\$this->bindValueChangeStateTracking();") + ); if ($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) { $dtoAbstractClassDefinition->addInterface( diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php index 9833c053..74cc9201 100644 --- a/src/MetaCode/Definition/ClassDefinition.php +++ b/src/MetaCode/Definition/ClassDefinition.php @@ -104,6 +104,7 @@ public function __construct( ) { $this->className = $className; $this->namespace = trim($namespace, '\\'); + $this->constructorStatementsCollection = new StatementDefinitionCollection(); } /** @@ -171,6 +172,20 @@ public function hasInterfaces(): bool public function addProperty(ClassPropertyDefinition $classPropertyDefinition): ClassDefinition { $this->properties[$classPropertyDefinition->getVariableName()] = $classPropertyDefinition; + + if ($classPropertyDefinition->getIsBeforeChangeObservable() + || $classPropertyDefinition->getIsAfterChangeObservable()) { + + $this->addConstant( + new ClassConstantDefinition( + $classPropertyDefinition->getPropertyNameConstantName( + $classPropertyDefinition->getVariableName() + ), + $classPropertyDefinition->getVariableName() + ) + ); + } + return $this; } @@ -390,6 +405,19 @@ public function addConstants(array $constants): static return $this; } + private StatementDefinitionCollection $constructorStatementsCollection; + + public function getConstructorStatementsCollection(): StatementDefinitionCollection + { + return $this->constructorStatementsCollection; + } + + public function addConstructorStatement(StatementDefinitionInterface $statementDefinition) + { + $this->getConstructorStatementsCollection() + ->addStatementDefinition($statementDefinition); + } + /** * @todo: Put this on a helper class * diff --git a/src/MetaCode/Definition/ClassPropertyDefinition.php b/src/MetaCode/Definition/ClassPropertyDefinition.php index 23008bb1..c5ce1f0f 100644 --- a/src/MetaCode/Definition/ClassPropertyDefinition.php +++ b/src/MetaCode/Definition/ClassPropertyDefinition.php @@ -160,8 +160,8 @@ public function getSetterMethodDefinition(ClassDefinition $containingClass): Cla $setter->appendBodyStatement( new RawStatementDefinition( \sprintf( - "\$this->raiseBeforeValueChange('%s', \$this->%s, \$%s);\n", - $this->getVariableName(), + "\$this->raiseBeforeValueChange(static::%s, \$this->%s, \$%s);\n", + $this->getPropertyNameConstantName($this->getVariableName()), $this->getVariableName(), $param->getParameterName(), ) @@ -178,8 +178,8 @@ public function getSetterMethodDefinition(ClassDefinition $containingClass): Cla } if ($this->getIsAfterChangeObservable() && $containingClass->hasTrait('AfterValueChangeObservableTrait')) { - $setter->appendBodyStatement(new RawStatementDefinition(\sprintf("\$this->raiseAfterValueChange('%s', \$this->%s);\n", - $this->getVariableName(), + $setter->appendBodyStatement(new RawStatementDefinition(\sprintf("\$this->raiseAfterValueChange(static::%s, \$this->%s);\n", + $this->getPropertyNameConstantName($this->getVariableName()), $this->getVariableName()))); } @@ -353,4 +353,9 @@ protected function defaultGetterMethodDefinition(): ClassMethodDefinition return $classMethod; } + + public function getPropertyNameConstantName(string $propertyName) + { + return ClassNameTool::identifierNameToConstantName($propertyName)."_PROPERTY"; + } } diff --git a/src/MetaCode/Definition/StatementDefinitionCollection.php b/src/MetaCode/Definition/StatementDefinitionCollection.php index 37b4e508..63c94895 100644 --- a/src/MetaCode/Definition/StatementDefinitionCollection.php +++ b/src/MetaCode/Definition/StatementDefinitionCollection.php @@ -35,4 +35,9 @@ public function toPhpCode(IndentationProviderInterface $indentationProvider, int } return \implode("\n", $statements); } + + public function hasStatements(): bool + { + return !empty($this->statementDefinitions); + } } diff --git a/src/MetaCode/Enum/PhpTypeEnum.php b/src/MetaCode/Enum/PhpTypeEnum.php index d08e4ee9..ab3a0d53 100644 --- a/src/MetaCode/Enum/PhpTypeEnum.php +++ b/src/MetaCode/Enum/PhpTypeEnum.php @@ -30,6 +30,13 @@ class PhpTypeEnum protected const STATIC_TYPE_ID = 70; protected const NULLABLE_STATIC_TYPE_ID = 75; + protected const NOT_DEFINED_TYPE_ID = 80; + + /** + * @var PhpTypeEnum + */ + private static ?PhpTypeEnum $notDefined = null; + private static ?PhpTypeEnum $stringTypeInstance = null; private static ?PhpTypeEnum $nullableStringTypeInstance = null; @@ -79,6 +86,19 @@ private function __construct($phpTypeId, $isNullable) $this->isNullable = $isNullable; } + public static function notDefined(): PhpTypeEnum + { + if (static::$notDefined) { + return static::$notDefined; + } + return static::$notDefined = new static(static::NOT_DEFINED_TYPE_ID, true); + } + + public function isDefined(): bool + { + return static::NOT_DEFINED_TYPE_ID !== $this->phpTypeId; + } + public function isNullable(): bool { return $this->isNullable; @@ -364,6 +384,10 @@ public function toDeclarationType() : string return '?static'; } + if (static::NOT_DEFINED_TYPE_ID === $this->phpTypeId) { + return ''; + } + throw new RuntimeException(__METHOD__." Died because ".__CLASS__." was misused."); } @@ -425,6 +449,10 @@ public function toAnnotationTypeString() : string return 'nullable static'; } + if (static::NOT_DEFINED_TYPE_ID === $this->phpTypeId) { + return ''; + } + throw new RuntimeException(__METHOD__." Died because ".__CLASS__." was misused."); } diff --git a/src/MetaCode/Format/ClassFormatter.php b/src/MetaCode/Format/ClassFormatter.php index 8be9075a..ad71bfe1 100644 --- a/src/MetaCode/Format/ClassFormatter.php +++ b/src/MetaCode/Format/ClassFormatter.php @@ -37,6 +37,7 @@ public function format(ClassDefinition $classDefinition): string $body[] = $this->formatTraits($classDefinition, $depth); $body[] = $this->formatConstants($classDefinition, $depth); $body[] = $this->formatProperties($classDefinition, $depth); + $body[] = $this->formatConstructor($classDefinition, $depth); $body[] = $this->formatMethods($classDefinition, $depth); $lines[] = "shortenTypeHint($classDefinition, $method->getReturnPhpTypeEnum()); + $signature .= ')'; + if ($method->getReturnPhpTypeEnum()->isDefined()) { + /* + * This condition is required because constructors do not have return types + */ + $signature .= ": ". $this->shortenTypeHint($classDefinition, $method->getReturnPhpTypeEnum()); + } $signature .= "\n"; $signature .= $this->getIndentation($depth) . "{\n"; @@ -355,4 +361,16 @@ private function shortenTypeHint(ClassDefinition $classDefinition, PhpTypeEnum $ return $typeHint; } + + private function formatConstructor(ClassDefinition $classDefinition, int $depth): string + { + if (!$classDefinition->getConstructorStatementsCollection()->hasStatements()) { + return ""; + } + + $constructorMethodDefinition = new ClassMethodDefinition('__construct', PhpTypeEnum::notDefined()); + $constructorMethodDefinition->appendBodyStatement($classDefinition->getConstructorStatementsCollection()); + + return $this->formatMethod($classDefinition, $constructorMethodDefinition, $depth+1); + } } diff --git a/src/MetaCode/Tool/ClassNameTool.php b/src/MetaCode/Tool/ClassNameTool.php index 214944cd..2ad376a1 100644 --- a/src/MetaCode/Tool/ClassNameTool.php +++ b/src/MetaCode/Tool/ClassNameTool.php @@ -105,4 +105,9 @@ public static function globalClassFQN(string $fullyQualifiedTypeName): string { return "\\".trim($fullyQualifiedTypeName, "\\"); } + + public static function identifierNameToConstantName(string $identifierName): string + { + return \strtoupper(str::snake($identifierName)); + } } From 03672ef87b7dcf9ab0e40ff6e0564b4d8d547c0c Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 05:26:54 -0400 Subject: [PATCH 14/35] Added configuration value for including value tracking --- composer.json | 2 +- composer.lock | 14 ++++++------- config/reliese.php | 1 + ...aTransportObjectGeneratorConfiguration.php | 8 +++++++ .../DataTransport/DataTransportGenerator.php | 21 ++++++++++++++----- src/MetaCode/Definition/ClassDefinition.php | 8 +++++-- tests/Behat/Assets/default_reliese_config.php | 1 + tests/MetaCode/Format/ClassFormatterTest.php | 3 +-- 8 files changed, 41 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index 6e9c586c..0e1166d8 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "illuminate/filesystem": ">=5.1", "illuminate/console": ">=5.1", "php-libs/observable": "^1.0", - "php-libs/value-states": "^1.0" + "php-libs/value-states": "^1.1" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index 9ed1b504..7d5f0bf1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dd44ace547e9f9a0fd5e030c72306f70", + "content-hash": "2287d487b5bed6fcb9aca7901763151d", "packages": [ { "name": "composer/package-versions-deprecated", @@ -1104,16 +1104,16 @@ }, { "name": "php-libs/value-states", - "version": "1.0", + "version": "1.1", "source": { "type": "git", "url": "https://github.com/php-libs/value-state.git", - "reference": "6f7d16b25e4417d23be0f4092a44fca940247d89" + "reference": "3f402085d7299cbe49914914542509c9979db2b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-libs/value-state/zipball/6f7d16b25e4417d23be0f4092a44fca940247d89", - "reference": "6f7d16b25e4417d23be0f4092a44fca940247d89", + "url": "https://api.github.com/repos/php-libs/value-state/zipball/3f402085d7299cbe49914914542509c9979db2b6", + "reference": "3f402085d7299cbe49914914542509c9979db2b6", "shasum": "" }, "require": { @@ -1133,9 +1133,9 @@ "description": "Extends php-libs/observer to track if a values have been initialized or modified (changed after initialization)", "support": { "issues": "https://github.com/php-libs/value-state/issues", - "source": "https://github.com/php-libs/value-state/tree/1.0" + "source": "https://github.com/php-libs/value-state/tree/1.1" }, - "time": "2021-05-13T08:31:45+00:00" + "time": "2021-05-13T09:17:15+00:00" }, { "name": "psr/container", diff --git a/config/reliese.php b/config/reliese.php index bc040a3b..f7bcf0de 100644 --- a/config/reliese.php +++ b/config/reliese.php @@ -557,6 +557,7 @@ 'Namespace' => 'App\DataTransportObjects', 'ClassSuffix' => 'Dto', 'ParentClassPrefix' => 'Abstract', + 'UseValueStateTracking' => true, 'ObservableProperties' => [ 'BeforeChange' => false, 'AfterChange' => false, diff --git a/src/Configuration/DataTransportObjectGeneratorConfiguration.php b/src/Configuration/DataTransportObjectGeneratorConfiguration.php index e4883ce2..f8c70841 100644 --- a/src/Configuration/DataTransportObjectGeneratorConfiguration.php +++ b/src/Configuration/DataTransportObjectGeneratorConfiguration.php @@ -38,6 +38,8 @@ class DataTransportObjectGeneratorConfiguration */ private bool $useAfterChangeObservableProperties = false; + private $useValueStateTracking; + /** * DataTransportGeneratorConfiguration constructor. * @@ -51,6 +53,7 @@ public function __construct(array $configuration) $this->parentClassPrefix = $configuration['ParentClassPrefix'] ?? ''; $this->classSuffix = $configuration['ClassSuffix']; $this->parentClassPrefix = $configuration['ParentClassPrefix']; + $this->useValueStateTracking = $configuration['UseValueStateTracking'] ?? false; if (\array_key_exists('ObservableProperties', $configuration)) { $observableConfig = $configuration['ObservableProperties']; if (\array_key_exists('BeforeChange', $observableConfig)) { @@ -109,4 +112,9 @@ public function getUseBeforeChangeObservableProperties(): bool { return $this->useBeforeChangeObservableProperties; } + + public function getUseValueStateTracking(): bool + { + return $this->useValueStateTracking; + } } diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 2d9667cc..3773a209 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -2,6 +2,7 @@ namespace Reliese\Generator\DataTransport; +use PhpLibs\ValueState\ValueStateProviderInterface; use PhpLibs\ValueState\WithValueStates; use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\DatabaseBlueprint; @@ -80,11 +81,21 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) $abstractNamespace = $this->getAbstractClassNamespace($tableBlueprint); $dtoAbstractClassDefinition = new ClassDefinition($abstractClassName, $abstractNamespace); - $dtoAbstractClassDefinition - ->addTrait(new ClassTraitDefinition(WithValueStates::class)) - ->addConstructorStatement( - new RawStatementDefinition("\$this->bindValueChangeStateTracking();") - ); + if ($this->dataTransportGeneratorConfiguration->getUseValueStateTracking()) { + /* + * Add interface: + * ValueStateProviderInterface + * include: + * use WithValueStates; + * And bind the tracking in the constructor: + * $this->bindValueChangeStateTracking(); + */ + $dtoAbstractClassDefinition + ->addInterface(ValueStateProviderInterface::class) + ->addTrait(new ClassTraitDefinition(WithValueStates::class)) + ->addConstructorStatement(new RawStatementDefinition("\$this->bindValueChangeStateTracking();")) + ; + } if ($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) { $dtoAbstractClassDefinition->addInterface( diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php index 74cc9201..70321c43 100644 --- a/src/MetaCode/Definition/ClassDefinition.php +++ b/src/MetaCode/Definition/ClassDefinition.php @@ -109,11 +109,14 @@ public function __construct( /** * @param string $fullyQualifiedInterfaceName + * + * @return $this */ - public function addInterface(string $fullyQualifiedInterfaceName) + public function addInterface(string $fullyQualifiedInterfaceName): static { $fullyQualifiedInterfaceName = ClassNameTool::globalClassFQN($fullyQualifiedInterfaceName); $this->interfaces[$fullyQualifiedInterfaceName] = true; + return $this; } /* @@ -412,10 +415,11 @@ public function getConstructorStatementsCollection(): StatementDefinitionCollect return $this->constructorStatementsCollection; } - public function addConstructorStatement(StatementDefinitionInterface $statementDefinition) + public function addConstructorStatement(StatementDefinitionInterface $statementDefinition): static { $this->getConstructorStatementsCollection() ->addStatementDefinition($statementDefinition); + return $this; } /** diff --git a/tests/Behat/Assets/default_reliese_config.php b/tests/Behat/Assets/default_reliese_config.php index 4e58c202..ce11ce8a 100644 --- a/tests/Behat/Assets/default_reliese_config.php +++ b/tests/Behat/Assets/default_reliese_config.php @@ -556,6 +556,7 @@ 'Namespace' => 'App\DataTransportObjects', 'ClassSuffix' => 'Dto', 'ParentClassPrefix' => 'Abstract', + 'UseValueStateTracking' => true, 'ObservableProperties' => [ 'BeforeChange' => false, 'AfterChange' => false, diff --git a/tests/MetaCode/Format/ClassFormatterTest.php b/tests/MetaCode/Format/ClassFormatterTest.php index 72247689..eacb37fb 100644 --- a/tests/MetaCode/Format/ClassFormatterTest.php +++ b/tests/MetaCode/Format/ClassFormatterTest.php @@ -807,7 +807,6 @@ class OneClass public function setOneProperty(string \$oneProperty): static { \$this->oneProperty = \$oneProperty; - return \$this; } @@ -831,6 +830,6 @@ public function getOneProperty(): string $classOutput = $classFormatter->format($classDefinition); - $this->assertEquals($expectedClassOutput, $classOutput); + $this->assertEquals($expectedClassOutput, $classOutput, "\n $expectedClassOutput \n VERSUS \n $classOutput"); } } From 7a9b3340af0673f7af5f6894ae939027ba9b16c8 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 05:45:18 -0400 Subject: [PATCH 15/35] made value tracking checks in mappings conditional --- .../DataMap/ModelDataMapGenerateCommand.php | 1 + .../DataMap/ModelDataMapGenerator.php | 41 +++++++++++++++---- src/MetaCode/Definition/ClassDefinition.php | 2 +- .../Definition/ClassPropertyDefinition.php | 6 +-- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/Command/DataMap/ModelDataMapGenerateCommand.php b/src/Command/DataMap/ModelDataMapGenerateCommand.php index 6e44cb65..0b3e3362 100644 --- a/src/Command/DataMap/ModelDataMapGenerateCommand.php +++ b/src/Command/DataMap/ModelDataMapGenerateCommand.php @@ -105,6 +105,7 @@ public function handle( */ $modelDataMapGenerator = new ModelDataMapGenerator( $relieseConfiguration->getModelDataMapGeneratorConfiguration(), + $relieseConfiguration->getDataTransportGeneratorConfiguration(), new ModelGenerator($relieseConfiguration->getModelGeneratorConfiguration()), new DataTransportGenerator( $relieseConfiguration->getDataTransportGeneratorConfiguration(), diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index cde5fc01..50feead5 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -8,6 +8,7 @@ use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\TableBlueprint; +use Reliese\Configuration\DataTransportObjectGeneratorConfiguration; use Reliese\Configuration\ModelDataMapGeneratorConfiguration; use Reliese\Generator\DataTransport\DataTransportGenerator; use Reliese\Generator\Model\ModelGenerator; @@ -42,6 +43,11 @@ class ModelDataMapGenerator */ private DataTransportGenerator $dataTransportGenerator; + /** + * @var DataTransportObjectGeneratorConfiguration + */ + private DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration; + /** * @var ModelDataMapGeneratorConfiguration */ @@ -65,12 +71,14 @@ class ModelDataMapGenerator /** * ModelDataMapGenerator constructor. * - * @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration - * @param ModelGenerator $modelGenerator - * @param DataTransportGenerator $dataTransportGenerator + * @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration + * @param DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration + * @param ModelGenerator $modelGenerator + * @param DataTransportGenerator $dataTransportGenerator */ public function __construct( ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration, + DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration, ModelGenerator $modelGenerator, DataTransportGenerator $dataTransportGenerator ) { @@ -82,6 +90,7 @@ public function __construct( $this->modelGenerator = $modelGenerator; $this->dataTransportGenerator = $dataTransportGenerator; + $this->dataTransportObjectGeneratorConfiguration = $dataTransportObjectGeneratorConfiguration; } /** @@ -282,10 +291,28 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) foreach ($tableBlueprint->getColumnBlueprints() as $columnBlueprint) { $modelConstant = '\\'.$modelParameterType->toDeclarationType().'::'.Str::upper($columnBlueprint->getColumnName()); $getterName = ClassNameTool::columnNameToGetterName($columnBlueprint->getColumnName()); - $dtoPropertyAssignmentStatement = "\${$modelParameterName}[{$modelConstant}] = \${$dtoParameterName}->{$getterName}();"; - $mapToDtoMethodDefinition->appendBodyStatement(new RawStatementDefinition($dtoPropertyAssignmentStatement)); - // dd($dtoPropertyAssignmentStatement); - // dd([$modelParameterName, $modelConstant, $dtoParameterName, $setterName]); + $propertyConstant = ClassPropertyDefinition::getPropertyNameConstantName( + ClassNameTool::columnNameToPropertyName($columnBlueprint->getColumnName()) + ); + + $dtoPropertyAssignmentStatement = new RawStatementDefinition( + "\${$modelParameterName}[{$modelConstant}] = \${$dtoParameterName}->{$getterName}();" + ); + + if ($this->dataTransportObjectGeneratorConfiguration->getUseValueStateTracking()) { + $conditionalAssignmentBlock + = new StatementBlockDefinition( + new RawStatementDefinition(\sprintf("if (\$%s->getValueState()->isInitialized(%s::%s))", + $dtoParameterName, + $dtoClassName, + $propertyConstant))); + $conditionalAssignmentBlock->addStatementDefinition($dtoPropertyAssignmentStatement); + $mapToDtoMethodDefinition->appendBodyStatement($conditionalAssignmentBlock); + } else { + $mapToDtoMethodDefinition->appendBodyStatement($dtoPropertyAssignmentStatement); + } + + $mapToDtoMethodDefinition->appendBodyStatement($conditionalAssignmentBlock); } $mapToDtoMethodDefinition->appendBodyStatement(new RawStatementDefinition("return true;")); diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php index 70321c43..f860ba19 100644 --- a/src/MetaCode/Definition/ClassDefinition.php +++ b/src/MetaCode/Definition/ClassDefinition.php @@ -181,7 +181,7 @@ public function addProperty(ClassPropertyDefinition $classPropertyDefinition): C $this->addConstant( new ClassConstantDefinition( - $classPropertyDefinition->getPropertyNameConstantName( + ClassPropertyDefinition::getPropertyNameConstantName( $classPropertyDefinition->getVariableName() ), $classPropertyDefinition->getVariableName() diff --git a/src/MetaCode/Definition/ClassPropertyDefinition.php b/src/MetaCode/Definition/ClassPropertyDefinition.php index c5ce1f0f..a1663fff 100644 --- a/src/MetaCode/Definition/ClassPropertyDefinition.php +++ b/src/MetaCode/Definition/ClassPropertyDefinition.php @@ -161,7 +161,7 @@ public function getSetterMethodDefinition(ClassDefinition $containingClass): Cla new RawStatementDefinition( \sprintf( "\$this->raiseBeforeValueChange(static::%s, \$this->%s, \$%s);\n", - $this->getPropertyNameConstantName($this->getVariableName()), + ClassPropertyDefinition::getPropertyNameConstantName($this->getVariableName()), $this->getVariableName(), $param->getParameterName(), ) @@ -179,7 +179,7 @@ public function getSetterMethodDefinition(ClassDefinition $containingClass): Cla if ($this->getIsAfterChangeObservable() && $containingClass->hasTrait('AfterValueChangeObservableTrait')) { $setter->appendBodyStatement(new RawStatementDefinition(\sprintf("\$this->raiseAfterValueChange(static::%s, \$this->%s);\n", - $this->getPropertyNameConstantName($this->getVariableName()), + ClassPropertyDefinition::getPropertyNameConstantName($this->getVariableName()), $this->getVariableName()))); } @@ -354,7 +354,7 @@ protected function defaultGetterMethodDefinition(): ClassMethodDefinition return $classMethod; } - public function getPropertyNameConstantName(string $propertyName) + public static function getPropertyNameConstantName(string $propertyName): string { return ClassNameTool::identifierNameToConstantName($propertyName)."_PROPERTY"; } From 75e63b1dd62db445659271a641b68b8275dae313 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 06:43:56 -0400 Subject: [PATCH 16/35] updated value tracking generation --- composer.lock | 12 ++++++------ src/Generator/DataMap/ModelDataMapGenerator.php | 2 +- .../DataTransport/DataTransportGenerator.php | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.lock b/composer.lock index 7d5f0bf1..8fd20ccb 100644 --- a/composer.lock +++ b/composer.lock @@ -1104,16 +1104,16 @@ }, { "name": "php-libs/value-states", - "version": "1.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/php-libs/value-state.git", - "reference": "3f402085d7299cbe49914914542509c9979db2b6" + "reference": "d8d215a525b67695256addf20d53b9d7b8a3d523" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-libs/value-state/zipball/3f402085d7299cbe49914914542509c9979db2b6", - "reference": "3f402085d7299cbe49914914542509c9979db2b6", + "url": "https://api.github.com/repos/php-libs/value-state/zipball/d8d215a525b67695256addf20d53b9d7b8a3d523", + "reference": "d8d215a525b67695256addf20d53b9d7b8a3d523", "shasum": "" }, "require": { @@ -1133,9 +1133,9 @@ "description": "Extends php-libs/observer to track if a values have been initialized or modified (changed after initialization)", "support": { "issues": "https://github.com/php-libs/value-state/issues", - "source": "https://github.com/php-libs/value-state/tree/1.1" + "source": "https://github.com/php-libs/value-state/tree/1.2.1" }, - "time": "2021-05-13T09:17:15+00:00" + "time": "2021-05-13T10:42:22+00:00" }, { "name": "psr/container", diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index 50feead5..d2ad7657 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -302,7 +302,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) if ($this->dataTransportObjectGeneratorConfiguration->getUseValueStateTracking()) { $conditionalAssignmentBlock = new StatementBlockDefinition( - new RawStatementDefinition(\sprintf("if (\$%s->getValueState()->isInitialized(%s::%s))", + new RawStatementDefinition(\sprintf("if (\$%s->getValueIsInitialized(%s::%s))", $dtoParameterName, $dtoClassName, $propertyConstant))); diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 3773a209..bf148ffe 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -3,7 +3,7 @@ namespace Reliese\Generator\DataTransport; use PhpLibs\ValueState\ValueStateProviderInterface; -use PhpLibs\ValueState\WithValueStates; +use PhpLibs\ValueState\WithValueStateManager; use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\ForeignKeyBlueprint; @@ -92,7 +92,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) */ $dtoAbstractClassDefinition ->addInterface(ValueStateProviderInterface::class) - ->addTrait(new ClassTraitDefinition(WithValueStates::class)) + ->addTrait(new ClassTraitDefinition(WithValueStateManager::class)) ->addConstructorStatement(new RawStatementDefinition("\$this->bindValueChangeStateTracking();")) ; } From 91e1d2d786f4aa1dce7dfb83c2de7ac68115592e Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 06:50:19 -0400 Subject: [PATCH 17/35] comment update --- src/Generator/DataTransport/DataTransportGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index bf148ffe..5ea64727 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -86,7 +86,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) * Add interface: * ValueStateProviderInterface * include: - * use WithValueStates; + * use WithValueStateManager; * And bind the tracking in the constructor: * $this->bindValueChangeStateTracking(); */ From df90b37f8c605b95eaf74fd7f3851c9533389939 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 13 May 2021 06:52:33 -0400 Subject: [PATCH 18/35] fixed bug --- src/Generator/DataMap/ModelDataMapGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index d2ad7657..ba793f5e 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -302,7 +302,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) if ($this->dataTransportObjectGeneratorConfiguration->getUseValueStateTracking()) { $conditionalAssignmentBlock = new StatementBlockDefinition( - new RawStatementDefinition(\sprintf("if (\$%s->getValueIsInitialized(%s::%s))", + new RawStatementDefinition(\sprintf("if (\$%s->getValueWasInitialized(%s::%s))", $dtoParameterName, $dtoClassName, $propertyConstant))); From bfb062acf1592da31bc3242b982fb8295a65ecd9 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 18 May 2021 16:11:44 -0400 Subject: [PATCH 19/35] updated blueprint processing to respect filters for tables and columns --- .../Doctrine/DoctrineDatabaseAnalyser.php | 13 +++++++--- .../Doctrine/DoctrineSchemaAnalyser.php | 26 ++++++++++++++++++- src/Blueprint/ColumnOwnerInterface.php | 9 +------ src/Blueprint/IndexBlueprint.php | 6 +++++ src/Blueprint/SchemaMemberInterface.php | 5 ++++ src/Blueprint/SchemaMemberTrait.php | 14 ++++++++++ src/Blueprint/TableBlueprint.php | 10 ------- 7 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/Analyser/Doctrine/DoctrineDatabaseAnalyser.php b/src/Analyser/Doctrine/DoctrineDatabaseAnalyser.php index 82dff7d4..2fe1ac36 100644 --- a/src/Analyser/Doctrine/DoctrineDatabaseAnalyser.php +++ b/src/Analyser/Doctrine/DoctrineDatabaseAnalyser.php @@ -60,7 +60,7 @@ public function analyseDatabase(DatabaseBlueprintConfiguration $databaseBlueprin continue; } - $schemaAnalyser = $this->getSchemaAnalyser($databaseBlueprint, $schemaName); + $schemaAnalyser = $this->getSchemaAnalyser($databaseBlueprint, $schemaName, $databaseBlueprintConfiguration); $databaseBlueprint->addSchemaBlueprint( // TODO: Add support for Views $schemaAnalyser->analyseSchemaObjectStructures() @@ -71,7 +71,7 @@ public function analyseDatabase(DatabaseBlueprintConfiguration $databaseBlueprin * Analyse foreign key constraint relationships which could potentially span schemas */ foreach ($schemaNames as $schemaName) { - $schemaAnalyser = $this->getSchemaAnalyser($databaseBlueprint, $schemaName); + $schemaAnalyser = $this->getSchemaAnalyser($databaseBlueprint, $schemaName, $databaseBlueprintConfiguration); foreach ($schemaAnalyser->getTableDefinitions() as $tableName => $doctrineTableDefinition) { @@ -164,7 +164,11 @@ protected function getSchemaNames(): array * * @return DoctrineSchemaAnalyser */ - protected function getSchemaAnalyser(DatabaseBlueprint $databaseBlueprint, string $schemaName): DoctrineSchemaAnalyser + protected function getSchemaAnalyser( + DatabaseBlueprint $databaseBlueprint, + string $schemaName, + DatabaseBlueprintConfiguration $databaseBlueprintConfiguration + ): DoctrineSchemaAnalyser { if (array_key_exists($schemaName, $this->schemaAnalysers)) { return $this->schemaAnalysers[$schemaName]; @@ -178,7 +182,8 @@ protected function getSchemaAnalyser(DatabaseBlueprint $databaseBlueprint, strin $databaseBlueprint, $this, $schemaSpecificConnection, - $schemaSpecificDoctrineSchemaManager + $schemaSpecificDoctrineSchemaManager, + $databaseBlueprintConfiguration ); } } diff --git a/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php b/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php index 509ccbc1..e700344f 100644 --- a/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php +++ b/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php @@ -16,6 +16,7 @@ use Reliese\Blueprint\IndexBlueprint; use Reliese\Blueprint\SchemaBlueprint; use Reliese\Blueprint\TableBlueprint; +use Reliese\Configuration\DatabaseBlueprintConfiguration; /** * Class DoctrineSchemaAnalyser @@ -27,6 +28,11 @@ class DoctrineSchemaAnalyser */ private DatabaseBlueprint $databaseBlueprint; + /** + * @var DatabaseBlueprintConfiguration + */ + private DatabaseBlueprintConfiguration $databaseBlueprintConfiguration; + /** * @var DoctrineDatabaseAnalyser */ @@ -66,7 +72,8 @@ public function __construct( DatabaseBlueprint $databaseBlueprint, DoctrineDatabaseAnalyser $doctrineDatabaseAnalyser, ConnectionInterface $connection, - AbstractSchemaManager $doctrineSchemaManager + AbstractSchemaManager $doctrineSchemaManager, + DatabaseBlueprintConfiguration $databaseBlueprintConfiguration ) { $this->schemaName = $schemaName; @@ -74,6 +81,7 @@ public function __construct( $this->doctrineDatabaseAnalyser = $doctrineDatabaseAnalyser; $this->schemaSpecificConnection = $connection; $this->doctrineSchemaManager = $doctrineSchemaManager; + $this->databaseBlueprintConfiguration = $databaseBlueprintConfiguration; } /** @@ -110,6 +118,13 @@ public function analyseSchemaObjectStructures(): SchemaBlueprint $tableDefinitions = $this->getDoctrineSchemaManager()->listTables(); if (!empty($tableDefinitions)) { foreach ($tableDefinitions as $tableDefinition) { + $isExcluded = $this->databaseBlueprintConfiguration + ->getSchemaFilter() + ->isExcludedTable($this->getSchemaName(), $tableDefinition->getName()) + ; + if ($isExcluded) { + continue; + } /* * Keep for future use */ @@ -189,6 +204,15 @@ private function analyseTableColumns(Table $tableDefinition, TableBlueprint $tab } foreach ($columnDefinitions as $columnDefinition) { + $isExcluded = $this->databaseBlueprintConfiguration->getSchemaFilter()->isExcludedColumn( + $this->getSchemaName(), + $tableDefinition->getName(), + $columnDefinition->getName() + ); + if ($isExcluded) { + continue; + } + $columnBlueprint = $this->analyseColumn($tableBlueprint, $columnDefinition); $tableBlueprint->addColumnBlueprint($columnBlueprint); } diff --git a/src/Blueprint/ColumnOwnerInterface.php b/src/Blueprint/ColumnOwnerInterface.php index d896d313..c099e674 100644 --- a/src/Blueprint/ColumnOwnerInterface.php +++ b/src/Blueprint/ColumnOwnerInterface.php @@ -7,7 +7,7 @@ * * @package Reliese\Blueprint */ -interface ColumnOwnerInterface +interface ColumnOwnerInterface extends SchemaMemberInterface { /** * @param ColumnBlueprint $columnBlueprint @@ -30,11 +30,4 @@ public function getColumnBlueprints(): array; * @return string[] */ public function getColumnNames(): array; - - /** - * returns "Schema.[TableName |View Name]" - * - * @return string - */ - public function getUniqueName(): string; } diff --git a/src/Blueprint/IndexBlueprint.php b/src/Blueprint/IndexBlueprint.php index 20312ef9..e60aa046 100644 --- a/src/Blueprint/IndexBlueprint.php +++ b/src/Blueprint/IndexBlueprint.php @@ -8,6 +8,7 @@ class IndexBlueprint implements ColumnOwnerInterface { use ColumnOwnerTrait; + use SchemaMemberTrait; /** * @var string @@ -79,4 +80,9 @@ public function isUnique(): bool { return $this->isUnique || $this->isPrimaryKey(); } + + public function getSchemaMemberType(): SchemaMemberType + { + return SchemaMemberType::Index(); + } } diff --git a/src/Blueprint/SchemaMemberInterface.php b/src/Blueprint/SchemaMemberInterface.php index 7bdde788..bc2a6c26 100644 --- a/src/Blueprint/SchemaMemberInterface.php +++ b/src/Blueprint/SchemaMemberInterface.php @@ -18,6 +18,11 @@ interface SchemaMemberInterface */ public function getName(): string; + /** + * @return string + */ + public function getUniqueName(): string; + /** * Returns an instance of SchemaMemberType * diff --git a/src/Blueprint/SchemaMemberTrait.php b/src/Blueprint/SchemaMemberTrait.php index 85af65b4..7b149a4b 100644 --- a/src/Blueprint/SchemaMemberTrait.php +++ b/src/Blueprint/SchemaMemberTrait.php @@ -54,4 +54,18 @@ public function setName(string $name) { $this->name = $name; } + + /** + * @return string + */ + public function getUniqueName(): string + { + if (empty($this->getSchemaBlueprint()->getSchemaName())) { + return $this->getName(); + } + + return sprintf('%s.%s', + $this->getSchemaBlueprint()->getSchemaName(), + $this->getName()); + } } \ No newline at end of file diff --git a/src/Blueprint/TableBlueprint.php b/src/Blueprint/TableBlueprint.php index 92a08353..514c8212 100644 --- a/src/Blueprint/TableBlueprint.php +++ b/src/Blueprint/TableBlueprint.php @@ -97,16 +97,6 @@ public function getSchemaMemberType(): SchemaMemberType return SchemaMemberType::Table(); } - /** - * @return string - */ - public function getUniqueName(): string - { - return sprintf('%s.%s', - $this->getSchemaBlueprint()->getSchemaName(), - $this->getName()); - } - /** * @return ForeignKeyBlueprint[] */ From 4540dda31c051da574374e502bc1ac8435678f14 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 18 May 2021 16:13:15 -0400 Subject: [PATCH 20/35] updates to dto generator --- .../DataTransport/DataTransportGenerator.php | 197 +++++++++++++++--- src/Generator/Model/ModelGenerator.php | 15 ++ src/MetaCode/Definition/ClassDefinition.php | 5 +- .../Definition/ClassPropertyDefinition.php | 5 +- src/MetaCode/Tool/ClassNameTool.php | 6 + 5 files changed, 195 insertions(+), 33 deletions(-) diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 5ea64727..85c8e234 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -5,6 +5,7 @@ use PhpLibs\ValueState\ValueStateProviderInterface; use PhpLibs\ValueState\WithValueStateManager; use Reliese\Blueprint\ColumnBlueprint; +use Reliese\Blueprint\ColumnOwnerInterface; use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\ForeignKeyBlueprint; use Reliese\Blueprint\TableBlueprint; @@ -15,6 +16,7 @@ use Reliese\MetaCode\Definition\ClassPropertyDefinition; use Reliese\MetaCode\Definition\ClassTraitDefinition; use Reliese\MetaCode\Definition\RawStatementDefinition; +use Reliese\MetaCode\Definition\StatementBlockDefinition; use Reliese\MetaCode\Enum\PhpTypeEnum; use Reliese\MetaCode\Format\ClassFormatter; use Reliese\MetaCode\Tool\ClassNameTool; @@ -49,6 +51,21 @@ class DataTransportGenerator */ private DatabaseBlueprint $databaseBlueprint; + /** + * @var ClassDefinition[] + */ + private array $generatedDataTransportObjectClassDefinitions = []; + + /** + * @var ClassDefinition[] + */ + private array $generatedAbstractDataTransportObjectClassDefinitions = []; + + /** + * @var ClassPropertyDefinition[] + */ + private array $generatedForeignKeyDtoPropertyDefinitions = []; + /** * DataTransportGenerator constructor. * @@ -72,15 +89,52 @@ public function __construct( */ public function fromTableBlueprint(TableBlueprint $tableBlueprint) { - $className = $this->getClassName($tableBlueprint); + $dtoAbstractClassDefinition = $this->generateAbstractDataTransportObjectClassDefinition($tableBlueprint); + $dtoClassDefinition = $this->generateDataTransportObjectClassDefinition($tableBlueprint); - $abstractClassName = $this->getAbstractClassName($tableBlueprint); + /* + * Write the Class Files + */ + $this->writeClassFiles($dtoClassDefinition, $dtoAbstractClassDefinition); + } - $namespace = $this->getClassNamespace($tableBlueprint); + /** + * @param TableBlueprint $tableBlueprint + * + * @return string + */ + public function getFullyQualifiedClassName(ColumnOwnerInterface $tableBlueprint): string + { + return $this->getClassNamespace($tableBlueprint).'\\'.$this->getClassName($tableBlueprint); + } - $abstractNamespace = $this->getAbstractClassNamespace($tableBlueprint); + public function getClassNamespace(TableBlueprint $tableBlueprint): string + { + return $this->dataTransportGeneratorConfiguration->getNamespace(); + } + + public function getClassName(ColumnOwnerInterface $tableBlueprint): string + { + return ClassNameTool::snakeCaseToClassName( + null, + $tableBlueprint->getName(), + $this->dataTransportGeneratorConfiguration->getClassSuffix() + ); + } + + public function generateAbstractDataTransportObjectClassDefinition(TableBlueprint $tableBlueprint): ClassDefinition + { + if (\array_key_exists($tableBlueprint->getUniqueName(), + $this->generatedAbstractDataTransportObjectClassDefinitions) + ) { + return $this->generatedAbstractDataTransportObjectClassDefinitions[$tableBlueprint->getUniqueName()]; + } + + $dtoAbstractClassDefinition = new ClassDefinition( + $this->getAbstractClassName($tableBlueprint), + $this->getAbstractClassNamespace($tableBlueprint) + ); - $dtoAbstractClassDefinition = new ClassDefinition($abstractClassName, $abstractNamespace); if ($this->dataTransportGeneratorConfiguration->getUseValueStateTracking()) { /* * Add interface: @@ -114,9 +168,6 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) new ClassTraitDefinition(\PhpLibs\Observable\AfterValueChangeObservableTrait::class) ); } - - $dtoClassDefinition = new ClassDefinition($className, $namespace); - $dtoClassDefinition->setParentClass($dtoAbstractClassDefinition->getFullyQualifiedName()); foreach ($tableBlueprint->getColumnBlueprints() as $columnBlueprint) { @@ -153,34 +204,25 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) $dtoAbstractClassDefinition->addProperty($fkDtoProperty); } - /* - * Write the Class Files - */ - $this->writeClassFiles($dtoClassDefinition, $dtoAbstractClassDefinition); + return $dtoAbstractClassDefinition; } - /** - * @param TableBlueprint $tableBlueprint - * - * @return string - */ - public function getFullyQualifiedClassName(TableBlueprint $tableBlueprint): string + public function generateDataTransportObjectClassDefinition(TableBlueprint $tableBlueprint): ClassDefinition { - return $this->getClassNamespace($tableBlueprint).'\\'.$this->getClassName($tableBlueprint); - } - - public function getClassNamespace(TableBlueprint $tableBlueprint): string - { - return $this->dataTransportGeneratorConfiguration->getNamespace(); - } + if (\array_key_exists($tableBlueprint->getUniqueName(), $this->generatedDataTransportObjectClassDefinitions)) { + return $this->generatedDataTransportObjectClassDefinitions[$tableBlueprint->getUniqueName()]; + } - public function getClassName(TableBlueprint $tableBlueprint): string - { - return ClassNameTool::snakeCaseToClassName( - null, - $tableBlueprint->getName(), - $this->dataTransportGeneratorConfiguration->getClassSuffix() + $dtoClassDefinition = new ClassDefinition( + $this->getClassName($tableBlueprint), + $this->getClassNamespace($tableBlueprint) + ); + $dtoClassDefinition->setParentClass( + $this->generateAbstractDataTransportObjectClassDefinition($tableBlueprint)->getFullyQualifiedName() ); + + return $this->generatedDataTransportObjectClassDefinitions[$tableBlueprint->getUniqueName()] + = $dtoClassDefinition; } private function getAbstractClassName(TableBlueprint $tableBlueprint): string @@ -227,6 +269,93 @@ private function writeClassFiles( file_put_contents($abstractDtoFilePath, $abstractDtoPhpCode); } + public function generateForeignKeyDtoPropertyDefinition( + TableBlueprint $tableBlueprint, + ForeignKeyBlueprint $foreignKeyBlueprint + ) : ClassPropertyDefinition { + + if (\array_key_exists($foreignKeyBlueprint->getName(), $this->generatedForeignKeyDtoPropertyDefinitions)) { + return $this->generatedForeignKeyDtoPropertyDefinitions[$foreignKeyBlueprint->getName()]; + } + + $fkDtoProperty = null; + $dtoVariableName = null; + + $referencedTableBlueprint = $foreignKeyBlueprint->getReferencedTableBlueprint(); + + $fkDtoClassName = $this->getClassName($referencedTableBlueprint); + + $dtoVariableName = ClassNameTool::dtoClassNameToVariableName($fkDtoClassName); + + $fkDtoProperty = new ClassPropertyDefinition( + $dtoVariableName, + PhpTypeEnum::nullableObjectOfType($this->getFullyQualifiedClassName($referencedTableBlueprint)) + ); + + $fkDtoProperty + ->setIsBeforeChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) + ->setIsAfterChangeObservable($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) + ->withSetter() + ->withGetter() + ; + + $commonColumns = []; + /* + * Track which columns should be updated when this property is set + */ + foreach ($foreignKeyBlueprint->getFkColumnPairs() as $columns) { + /** + * @var ColumnBlueprint $referencingColumn + * @var ColumnBlueprint $referencedColumn + */ + [$referencingColumn, $referencedColumn] = $columns; + + $commonColumns[$referencingColumn->getColumnName().' = '.$referencedColumn->getColumnName()] = + [$referencingColumn, $referencedColumn]; + } + + foreach ($commonColumns as $columnPairs) { + [$referencingColumn, $referencedColumn] = $columnPairs; + + $propertyConstant = ClassPropertyDefinition::getPropertyNameConstantName( + ClassNameTool::columnNameToPropertyName($referencedColumn->getColumnName()) + ); + + $propertyGetterCall = \sprintf( + "\$%s->%s()", + $dtoVariableName, + ClassNameTool::columnNameToGetterName($referencedColumn->getColumnName()), + ); + + /* + * If the referenced value was initialized, then set the fk value to match + */ + $ifInitialized = new RawStatementDefinition( + sprintf( + "if (\$%s->getValueWasInitialized(%s::%s) && !empty(%s))", + $dtoVariableName, + $fkDtoClassName, + $propertyConstant, + $propertyGetterCall + ) + ); + + $setFkFieldIfInitialized = new StatementBlockDefinition($ifInitialized); + $setFkFieldIfInitialized->addStatementDefinition( + new RawStatementDefinition( + \sprintf( + "\$this->%s(%s);", + ClassNameTool::columnNameToSetterName($referencingColumn->getColumnName()), + $propertyGetterCall, + ) + ) + ); + + $fkDtoProperty->addAdditionalSetterOperation($setFkFieldIfInitialized); + } + return $fkDtoProperty; + } + /** * @param TableBlueprint $tableBlueprint * TODO: figure out how to cache these so they are not rebuilt on every call @@ -240,6 +369,12 @@ public function getForeignKeyDtoPropertyDefinitions(TableBlueprint $tableBluepri return $results; } + foreach ($tableBlueprint->getForeignKeyBlueprints() as $foreignKeyBlueprint) { + $fkDtoProperty = $this->generateForeignKeyDtoPropertyDefinition($tableBlueprint, $foreignKeyBlueprint); + $results[] = $fkDtoProperty; + } + return $results; + /** * Examine FKs * @var ForeignKeyBlueprint $foreignKeyBlueprint diff --git a/src/Generator/Model/ModelGenerator.php b/src/Generator/Model/ModelGenerator.php index efcf74eb..f47a76bd 100644 --- a/src/Generator/Model/ModelGenerator.php +++ b/src/Generator/Model/ModelGenerator.php @@ -2,6 +2,7 @@ namespace Reliese\Generator\Model; +use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\ModelGeneratorConfiguration; use Reliese\Generator\MySqlDataTypeMap; @@ -136,6 +137,20 @@ public function getAbstractClassNamespace(TableBlueprint $tableBlueprint): strin return $this->getClassNamespace($tableBlueprint) .'\\Generated'; } + /** + * @param ColumnBlueprint $columnBlueprint + * + * @return ClassConstantDefinition + */ + public function generateColumnConstantDefinition(ColumnBlueprint $columnBlueprint): ClassConstantDefinition + { + return new ClassConstantDefinition( + ClassNameTool::columnNameToConstantName($columnBlueprint->getColumnName()), + $columnBlueprint->getColumnName(), + VisibilityEnum::publicEnum() + ); + } + /** * @return string */ diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php index f860ba19..6ed154d9 100644 --- a/src/MetaCode/Definition/ClassDefinition.php +++ b/src/MetaCode/Definition/ClassDefinition.php @@ -148,10 +148,13 @@ public function addImport(ImportableInterface $import): static /** * @param ClassMethodDefinition $classMethodDefinition + * + * @return $this */ - public function addMethodDefinition(ClassMethodDefinition $classMethodDefinition) + public function addMethodDefinition(ClassMethodDefinition $classMethodDefinition) : static { $this->methods[$classMethodDefinition->getFunctionName()] = $classMethodDefinition; + return $this; } /** diff --git a/src/MetaCode/Definition/ClassPropertyDefinition.php b/src/MetaCode/Definition/ClassPropertyDefinition.php index a1663fff..1d123a01 100644 --- a/src/MetaCode/Definition/ClassPropertyDefinition.php +++ b/src/MetaCode/Definition/ClassPropertyDefinition.php @@ -145,7 +145,10 @@ public function getSetterInstanceEnum(): InstanceEnum */ public function getSetterMethodDefinition(ClassDefinition $containingClass): ClassMethodDefinition { - $param = new FunctionParameterDefinition($this->getVariableName(), $this->getPhpTypeEnum()); + $param = new FunctionParameterDefinition( + $this->getVariableName(), + $this->getPhpTypeEnum() + ); $setter = new ClassMethodDefinition( $this->getSetterMethodName(), PhpTypeEnum::staticTypeEnum(), diff --git a/src/MetaCode/Tool/ClassNameTool.php b/src/MetaCode/Tool/ClassNameTool.php index 2ad376a1..1353c09e 100644 --- a/src/MetaCode/Tool/ClassNameTool.php +++ b/src/MetaCode/Tool/ClassNameTool.php @@ -110,4 +110,10 @@ public static function identifierNameToConstantName(string $identifierName): str { return \strtoupper(str::snake($identifierName)); } + + public static function fkNameToVariableName(string $foreignKeyname): string + { + $name = str::studly($foreignKeyname); + return \strtolower($name[0]).\substr($foreignKeyname, 1); + } } From 6215a65e8334034fa870090a0efcd65bb2d2e573 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 18 May 2021 16:42:13 -0400 Subject: [PATCH 21/35] removed dead test code --- .../DataTransportObjectGeneratorContext.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/Behat/Contexts/Generator/DataTransportObjectGeneratorContext.php b/tests/Behat/Contexts/Generator/DataTransportObjectGeneratorContext.php index b0ee04be..ac895b1a 100644 --- a/tests/Behat/Contexts/Generator/DataTransportObjectGeneratorContext.php +++ b/tests/Behat/Contexts/Generator/DataTransportObjectGeneratorContext.php @@ -2,24 +2,12 @@ namespace Tests\Behat\Contexts\Generator; -use Behat\Behat\Tester\Exception\PendingException; -use Reliese\Generator\DataTransport\DataTransportGenerator; use Reliese\Generator\DataTransport\DataTransportObjectGenerator; -use Tests\Behat\Contexts\FeatureContext; /** * Class DataTransportObjectGeneratorContext */ class DataTransportObjectGeneratorContext extends GeneratorContexts { - public function getDataTransportObjectGenerator(): DataTransportObjectGenerator - { - return new DataTransportObjectGenerator( - $this->getConfigurationContexts() - ->getDataTransportObjectGeneratorConfigurationContext() - ->getDataTransportObjectGeneratorConfiguration() - ); - } - /** * @When /^DataTransportObjectGenerator generates Abstract Dto from Schema "([^"]*)" Table "([^"]*)"$/ */ From a050245b3455b5634a8040f2d6c810cce8961841 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 18 May 2021 16:43:09 -0400 Subject: [PATCH 22/35] replaced usages of DataTransportGenerator with DataTransportObjectGenerator --- src/Command/DataMap/ModelDataMapGenerateCommand.php | 4 ++-- .../DataTransport/DataTransportGenerateCommand.php | 4 ++-- src/Generator/DataMap/ModelDataMapGenerator.php | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Command/DataMap/ModelDataMapGenerateCommand.php b/src/Command/DataMap/ModelDataMapGenerateCommand.php index 0b3e3362..2dcee544 100644 --- a/src/Command/DataMap/ModelDataMapGenerateCommand.php +++ b/src/Command/DataMap/ModelDataMapGenerateCommand.php @@ -11,7 +11,7 @@ use Reliese\Configuration\RelieseConfigurationFactory; use Reliese\Generator\DataAttribute\DataAttributeGenerator; use Reliese\Generator\DataMap\ModelDataMapGenerator; -use Reliese\Generator\DataTransport\DataTransportGenerator; +use Reliese\Generator\DataTransport\DataTransportObjectGenerator; use Reliese\Generator\Model\ModelGenerator; /** @@ -107,7 +107,7 @@ public function handle( $relieseConfiguration->getModelDataMapGeneratorConfiguration(), $relieseConfiguration->getDataTransportGeneratorConfiguration(), new ModelGenerator($relieseConfiguration->getModelGeneratorConfiguration()), - new DataTransportGenerator( + new DataTransportObjectGenerator( $relieseConfiguration->getDataTransportGeneratorConfiguration(), new DataAttributeGenerator($relieseConfiguration->getDataAttributeGeneratorConfiguration()) ), diff --git a/src/Command/DataTransport/DataTransportGenerateCommand.php b/src/Command/DataTransport/DataTransportGenerateCommand.php index 035bf975..2ada9df8 100644 --- a/src/Command/DataTransport/DataTransportGenerateCommand.php +++ b/src/Command/DataTransport/DataTransportGenerateCommand.php @@ -10,7 +10,7 @@ use Reliese\Command\ConfigurationProfileOptionTrait; use Reliese\Configuration\RelieseConfigurationFactory; use Reliese\Generator\DataAttribute\DataAttributeGenerator; -use Reliese\Generator\DataTransport\DataTransportGenerator; +use Reliese\Generator\DataTransport\DataTransportObjectGenerator; /** * Class DataTransportGenerateCommand @@ -95,7 +95,7 @@ public function handle( /* * Generate class files */ - $dataTransportGenerator = new DataTransportGenerator( + $dataTransportGenerator = new DataTransportObjectGenerator( $relieseConfiguration->getDataTransportGeneratorConfiguration(), new DataAttributeGenerator($relieseConfiguration->getDataAttributeGeneratorConfiguration()) ); diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index ba793f5e..676b3e3e 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -10,7 +10,7 @@ use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\DataTransportObjectGeneratorConfiguration; use Reliese\Configuration\ModelDataMapGeneratorConfiguration; -use Reliese\Generator\DataTransport\DataTransportGenerator; +use Reliese\Generator\DataTransport\DataTransportObjectGenerator; use Reliese\Generator\Model\ModelGenerator; use Reliese\Generator\MySqlDataTypeMap; use Reliese\MetaCode\Definition\ClassDefinition; @@ -39,9 +39,9 @@ class ModelDataMapGenerator { /** - * @var DataTransportGenerator + * @var DataTransportObjectGenerator */ - private DataTransportGenerator $dataTransportGenerator; + private DataTransportObjectGenerator $dataTransportObjectGenerator; /** * @var DataTransportObjectGeneratorConfiguration @@ -74,13 +74,13 @@ class ModelDataMapGenerator * @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration * @param DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration * @param ModelGenerator $modelGenerator - * @param DataTransportGenerator $dataTransportGenerator + * @param DataTransportObjectGenerator $dataTransportObjectGenerator */ public function __construct( ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration, DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration, ModelGenerator $modelGenerator, - DataTransportGenerator $dataTransportGenerator + DataTransportObjectGenerator $dataTransportObjectGenerator ) { $this->modelDataMapGeneratorConfiguration = $modelDataMapGeneratorConfiguration; /* @@ -89,7 +89,7 @@ public function __construct( $this->dataTypeMap = new MySqlDataTypeMap(); $this->modelGenerator = $modelGenerator; - $this->dataTransportGenerator = $dataTransportGenerator; + $this->dataTransportObjectGenerator = $dataTransportObjectGenerator; $this->dataTransportObjectGeneratorConfiguration = $dataTransportObjectGeneratorConfiguration; } From 57cd44b30641e2d0adc2824672751b8831f9b185 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Tue, 18 May 2021 16:50:04 -0400 Subject: [PATCH 23/35] Fixed bug that caused duplicate assignments in data maps --- src/Generator/DataMap/ModelDataMapGenerator.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index 676b3e3e..6e343d41 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -48,6 +48,16 @@ class ModelDataMapGenerator */ private DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration; + /** + * @var ClassDefinition[] + */ + private array $generatedAbstractModelDataMapClassDefinitions = []; + + /** + * @var ClassDefinition[] + */ + private array $generatedModelDataMapClassDefinitions = []; + /** * @var ModelDataMapGeneratorConfiguration */ @@ -311,8 +321,6 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) } else { $mapToDtoMethodDefinition->appendBodyStatement($dtoPropertyAssignmentStatement); } - - $mapToDtoMethodDefinition->appendBodyStatement($conditionalAssignmentBlock); } $mapToDtoMethodDefinition->appendBodyStatement(new RawStatementDefinition("return true;")); From 5fe3ae11e950e427c6f72ad69ebbd375dd143f6b Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Wed, 19 May 2021 03:20:29 -0400 Subject: [PATCH 24/35] updated dependencies on php-libs --- composer.json | 4 ++-- composer.lock | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 0e1166d8..0028702e 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,8 @@ "illuminate/contracts": ">=5.1", "illuminate/filesystem": ">=5.1", "illuminate/console": ">=5.1", - "php-libs/observable": "^1.0", - "php-libs/value-states": "^1.1" + "php-libs/observable": "^1.3", + "php-libs/value-states": "^1.3" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index 8fd20ccb..7ee45541 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2287d487b5bed6fcb9aca7901763151d", + "content-hash": "42ab9c20c5e6de27e9fab27a0869a8ef", "packages": [ { "name": "composer/package-versions-deprecated", @@ -1070,16 +1070,16 @@ }, { "name": "php-libs/observable", - "version": "1.0", + "version": "1.3", "source": { "type": "git", "url": "https://github.com/php-libs/observable.git", - "reference": "68efabfa33f9bbe1e25e1b7c95e6bcd7fc5b62c5" + "reference": "0f6b33db27228c7800556a2c11e1ca7a7c80871e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-libs/observable/zipball/68efabfa33f9bbe1e25e1b7c95e6bcd7fc5b62c5", - "reference": "68efabfa33f9bbe1e25e1b7c95e6bcd7fc5b62c5", + "url": "https://api.github.com/repos/php-libs/observable/zipball/0f6b33db27228c7800556a2c11e1ca7a7c80871e", + "reference": "0f6b33db27228c7800556a2c11e1ca7a7c80871e", "shasum": "" }, "require": { @@ -1098,27 +1098,27 @@ "description": "Provides clases to simplify observer pattern implementation", "support": { "issues": "https://github.com/php-libs/observable/issues", - "source": "https://github.com/php-libs/observable/tree/1.0" + "source": "https://github.com/php-libs/observable/tree/1.3" }, - "time": "2021-05-06T20:42:12+00:00" + "time": "2021-05-19T07:15:17+00:00" }, { "name": "php-libs/value-states", - "version": "1.2.1", + "version": "1.3", "source": { "type": "git", "url": "https://github.com/php-libs/value-state.git", - "reference": "d8d215a525b67695256addf20d53b9d7b8a3d523" + "reference": "d9dcc44c5826dfbd7e7350bf5b217654151bf773" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-libs/value-state/zipball/d8d215a525b67695256addf20d53b9d7b8a3d523", - "reference": "d8d215a525b67695256addf20d53b9d7b8a3d523", + "url": "https://api.github.com/repos/php-libs/value-state/zipball/d9dcc44c5826dfbd7e7350bf5b217654151bf773", + "reference": "d9dcc44c5826dfbd7e7350bf5b217654151bf773", "shasum": "" }, "require": { "php": "^8.0", - "php-libs/observable": "^1.0" + "php-libs/observable": "^1.3" }, "type": "library", "autoload": { @@ -1133,9 +1133,9 @@ "description": "Extends php-libs/observer to track if a values have been initialized or modified (changed after initialization)", "support": { "issues": "https://github.com/php-libs/value-state/issues", - "source": "https://github.com/php-libs/value-state/tree/1.2.1" + "source": "https://github.com/php-libs/value-state/tree/1.3" }, - "time": "2021-05-13T10:42:22+00:00" + "time": "2021-05-19T07:16:58+00:00" }, { "name": "psr/container", From 7c2c128444658e91412da1f0ea62db4959ad783f Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:42:22 -0400 Subject: [PATCH 25/35] updated index is-unique tracking --- src/Analyser/Doctrine/DoctrineSchemaAnalyser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php b/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php index e700344f..f29f96cb 100644 --- a/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php +++ b/src/Analyser/Doctrine/DoctrineSchemaAnalyser.php @@ -282,7 +282,7 @@ private function analyseIndex(TableBlueprint $tableBlueprint, Index $indexDefini $indexDefinition->getName(), $columnBlueprints, $indexDefinition->isPrimary(), - false + $indexDefinition->isUnique() ); } From 84692816569a8eeea410e2dedea5e41d0ff1f881 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:45:41 -0400 Subject: [PATCH 26/35] updated generator constructors to only require the root configuration object --- src/Blueprint/IndexBlueprint.php | 5 ++ src/Blueprint/TableBlueprint.php | 50 +++++++++++++++++++ .../DataAccess/DataAccessGenerateCommand.php | 18 ++++--- .../DataAttributeGenerateCommand.php | 9 +--- .../DataMap/ModelDataMapGenerateCommand.php | 14 +----- .../DataTransportGenerateCommand.php | 5 +- src/Command/Model/NewModelGenerateCommand.php | 6 +-- .../DataAttribute/DataAttributeGenerator.php | 10 ++-- .../DataMap/ModelDataMapGenerator.php | 22 +++----- .../DataTransport/DataTransportGenerator.php | 11 ++-- src/Generator/Model/ModelGenerator.php | 7 +-- 11 files changed, 95 insertions(+), 62 deletions(-) diff --git a/src/Blueprint/IndexBlueprint.php b/src/Blueprint/IndexBlueprint.php index e60aa046..29ffd83e 100644 --- a/src/Blueprint/IndexBlueprint.php +++ b/src/Blueprint/IndexBlueprint.php @@ -85,4 +85,9 @@ public function getSchemaMemberType(): SchemaMemberType { return SchemaMemberType::Index(); } + + public function getName(): string + { + return $this->indexName; + } } diff --git a/src/Blueprint/TableBlueprint.php b/src/Blueprint/TableBlueprint.php index 514c8212..5e7ee474 100644 --- a/src/Blueprint/TableBlueprint.php +++ b/src/Blueprint/TableBlueprint.php @@ -116,4 +116,54 @@ public function getForeignKeyBlueprintsGroupedByReferencedTable() : array } return $results; } + + /** + * @param bool $includePrimaryKey + * + * @return array[] + */ + public function getUniqueColumnGroups(bool $includePrimaryKey = true): array + { + $uniqueColumnGroups = []; + + foreach ($this->indexBlueprints as $indexBlueprint) { + if ($indexBlueprint->isPrimaryKey() && !$includePrimaryKey) { + continue; + } + if (!$indexBlueprint->isUnique()) { + continue; + } + + $uniqueColumnGroups[] = $indexBlueprint->getColumnBlueprints(); + } + + return $uniqueColumnGroups; + } + + /** + * @param bool $includePrimaryKey + * + * @return IndexBlueprint[] + */ + public function getUniqueIndexes(bool $includePrimaryKey = true): array + { + $uniqueIndexes = []; + + foreach ($this->indexBlueprints as $indexBlueprint) { + if ($indexBlueprint->isPrimaryKey() && !$includePrimaryKey) { + continue; + } + if (!$indexBlueprint->isUnique()) { + continue; + } + + $uniqueIndexes[] = $indexBlueprint; + } + + usort($uniqueIndexes, function (IndexBlueprint $a, IndexBlueprint $b) { + return strncasecmp($a->getName(), + $b->getName(), mb_strlen($a->getName()));}); + + return $uniqueIndexes; + } } diff --git a/src/Command/DataAccess/DataAccessGenerateCommand.php b/src/Command/DataAccess/DataAccessGenerateCommand.php index 6e3ccf58..82658701 100644 --- a/src/Command/DataAccess/DataAccessGenerateCommand.php +++ b/src/Command/DataAccess/DataAccessGenerateCommand.php @@ -9,6 +9,8 @@ use Reliese\Command\ConfigurationProfileOptionTrait; use Reliese\Configuration\RelieseConfigurationFactory; use Reliese\Generator\DataAccess\DataAccessGenerator; +use Reliese\Generator\DataTransport\DataTransportObjectGenerator; +use Reliese\Generator\Model\ModelGenerator; /** * Class DataAccessGenerateCommand @@ -81,10 +83,7 @@ public function handle( /* * Create the correct analyser for the configuration profile */ - $databaseAnalyser = $analyserFactory->databaseAnalyser( - $relieseConfiguration->getDatabaseBlueprintConfiguration(), - $relieseConfiguration->getDatabaseAnalyserConfiguration() - ); + $databaseAnalyser = $analyserFactory->databaseAnalyser($relieseConfiguration); /* * Allow the $databaseAnalyser to create the Database Blueprint @@ -94,12 +93,17 @@ public function handle( /* * Generate class files */ - $dataAccessGenerator = new DataAccessGenerator( - $relieseConfiguration->getDataAccessGeneratorConfiguration() - ); + $dataAccessGenerator = new DataAccessGenerator($relieseConfiguration); $schemaBlueprint = $databaseBlueprint->getSchemaBlueprint($schema); + if (!empty($table)) { + // Generate only for the specified table + $tableBlueprint = $schemaBlueprint->getTableBlueprint($table); + $dataAccessGenerator->fromTableBlueprint($tableBlueprint); + return; + } + /* * Display the data that would be used to perform code generation */ diff --git a/src/Command/DataAttribute/DataAttributeGenerateCommand.php b/src/Command/DataAttribute/DataAttributeGenerateCommand.php index 07a4c9c3..9478957e 100644 --- a/src/Command/DataAttribute/DataAttributeGenerateCommand.php +++ b/src/Command/DataAttribute/DataAttributeGenerateCommand.php @@ -81,10 +81,7 @@ public function handle( /* * Create the correct analyser for the configuration profile */ - $databaseAnalyser = $analyserFactory->databaseAnalyser( - $relieseConfiguration->getDatabaseBlueprintConfiguration(), - $relieseConfiguration->getDatabaseAnalyserConfiguration() - ); + $databaseAnalyser = $analyserFactory->databaseAnalyser($relieseConfiguration); /* * Allow the $databaseAnalyser to create the Database Blueprint @@ -94,9 +91,7 @@ public function handle( /* * Generate class files */ - $dataAttributeGenerator = new DataAttributeGenerator( - $relieseConfiguration->getDataAttributeGeneratorConfiguration() - ); + $dataAttributeGenerator = new DataAttributeGenerator($relieseConfiguration); $schemaBlueprint = $databaseBlueprint->getSchemaBlueprint($schema); diff --git a/src/Command/DataMap/ModelDataMapGenerateCommand.php b/src/Command/DataMap/ModelDataMapGenerateCommand.php index 2dcee544..b1a4b21e 100644 --- a/src/Command/DataMap/ModelDataMapGenerateCommand.php +++ b/src/Command/DataMap/ModelDataMapGenerateCommand.php @@ -87,9 +87,7 @@ public function handle( /* * Create the correct analyser for the configuration profile */ - $databaseAnalyser = $analyserFactory->databaseAnalyser( - $relieseConfiguration - ); + $databaseAnalyser = $analyserFactory->databaseAnalyser($relieseConfiguration); /* * Allow the $databaseAnalyser to create the Database Blueprint @@ -103,15 +101,7 @@ public function handle( /* * Create a ModelDataMapGenerator */ - $modelDataMapGenerator = new ModelDataMapGenerator( - $relieseConfiguration->getModelDataMapGeneratorConfiguration(), - $relieseConfiguration->getDataTransportGeneratorConfiguration(), - new ModelGenerator($relieseConfiguration->getModelGeneratorConfiguration()), - new DataTransportObjectGenerator( - $relieseConfiguration->getDataTransportGeneratorConfiguration(), - new DataAttributeGenerator($relieseConfiguration->getDataAttributeGeneratorConfiguration()) - ), - ); + $modelDataMapGenerator = new ModelDataMapGenerator($relieseConfiguration); if (!empty($table)) { // Generate only for the specified table diff --git a/src/Command/DataTransport/DataTransportGenerateCommand.php b/src/Command/DataTransport/DataTransportGenerateCommand.php index 2ada9df8..42e2c77a 100644 --- a/src/Command/DataTransport/DataTransportGenerateCommand.php +++ b/src/Command/DataTransport/DataTransportGenerateCommand.php @@ -95,10 +95,7 @@ public function handle( /* * Generate class files */ - $dataTransportGenerator = new DataTransportObjectGenerator( - $relieseConfiguration->getDataTransportGeneratorConfiguration(), - new DataAttributeGenerator($relieseConfiguration->getDataAttributeGeneratorConfiguration()) - ); + $dataTransportGenerator = new DataTransportObjectGenerator($relieseConfiguration); $schemaBlueprint = $databaseBlueprint->getSchemaBlueprint($schema); diff --git a/src/Command/Model/NewModelGenerateCommand.php b/src/Command/Model/NewModelGenerateCommand.php index 43beba85..00312c5a 100644 --- a/src/Command/Model/NewModelGenerateCommand.php +++ b/src/Command/Model/NewModelGenerateCommand.php @@ -100,9 +100,7 @@ public function handle( /* * Create the correct analyser for the configuration profile */ - $databaseAnalyser = $analyserFactory->databaseAnalyser( - $relieseConfiguration - ); + $databaseAnalyser = $analyserFactory->databaseAnalyser($relieseConfiguration); /* * Allow the $databaseAnalyser to create the Database Blueprint @@ -110,7 +108,7 @@ public function handle( $databaseBlueprint = $databaseAnalyser->analyseDatabase($relieseConfiguration->getDatabaseBlueprintConfiguration()); // TODO: Apply Command Line options that override the configuration values - $modelGenerator = new ModelGenerator($relieseConfiguration->getModelGeneratorConfiguration()); + $modelGenerator = new ModelGenerator($relieseConfiguration); $schemaBlueprint = $databaseBlueprint->getSchemaBlueprint($schema); diff --git a/src/Generator/DataAttribute/DataAttributeGenerator.php b/src/Generator/DataAttribute/DataAttributeGenerator.php index f48a6beb..75256080 100644 --- a/src/Generator/DataAttribute/DataAttributeGenerator.php +++ b/src/Generator/DataAttribute/DataAttributeGenerator.php @@ -8,6 +8,7 @@ use Reliese\Blueprint\DatabaseBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\DataAttributeGeneratorConfiguration; +use Reliese\Configuration\RelieseConfiguration; use Reliese\Generator\MySqlDataTypeMap; use Reliese\MetaCode\Definition\TraitDefinition; use Reliese\MetaCode\Definition\ClassPropertyDefinition; @@ -38,12 +39,11 @@ class DataAttributeGenerator /** * DataAttributeGenerator constructor. * - * @param DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration + * @param RelieseConfiguration $relieseConfiguration */ - public function __construct( - DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration - ) { - $this->dataAttributeGeneratorConfiguration = $dataAttributeGeneratorConfiguration; + public function __construct(RelieseConfiguration $relieseConfiguration) + { + $this->dataAttributeGeneratorConfiguration = $relieseConfiguration->getDataAttributeGeneratorConfiguration(); /* * TODO: inject a MySql / Postgress or other DataType mapping as needed */ diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index 6e343d41..5466432f 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -10,6 +10,7 @@ use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\DataTransportObjectGeneratorConfiguration; use Reliese\Configuration\ModelDataMapGeneratorConfiguration; +use Reliese\Configuration\RelieseConfiguration; use Reliese\Generator\DataTransport\DataTransportObjectGenerator; use Reliese\Generator\Model\ModelGenerator; use Reliese\Generator\MySqlDataTypeMap; @@ -81,26 +82,19 @@ class ModelDataMapGenerator /** * ModelDataMapGenerator constructor. * - * @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration - * @param DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration - * @param ModelGenerator $modelGenerator - * @param DataTransportObjectGenerator $dataTransportObjectGenerator + * @param RelieseConfiguration $relieseConfiguration */ - public function __construct( - ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration, - DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration, - ModelGenerator $modelGenerator, - DataTransportObjectGenerator $dataTransportObjectGenerator - ) { - $this->modelDataMapGeneratorConfiguration = $modelDataMapGeneratorConfiguration; + public function __construct(RelieseConfiguration $relieseConfiguration) + { + $this->modelDataMapGeneratorConfiguration = $relieseConfiguration->getModelDataMapGeneratorConfiguration(); /* * TODO: inject a MySql / Postgress or other DataType mapping as needed */ $this->dataTypeMap = new MySqlDataTypeMap(); - $this->modelGenerator = $modelGenerator; - $this->dataTransportObjectGenerator = $dataTransportObjectGenerator; - $this->dataTransportObjectGeneratorConfiguration = $dataTransportObjectGeneratorConfiguration; + $this->modelGenerator = new ModelGenerator($relieseConfiguration); + $this->dataTransportObjectGenerator = new DataTransportObjectGenerator($relieseConfiguration); + $this->dataTransportObjectGeneratorConfiguration = $relieseConfiguration->getDataTransportGeneratorConfiguration(); } /** diff --git a/src/Generator/DataTransport/DataTransportGenerator.php b/src/Generator/DataTransport/DataTransportGenerator.php index 85c8e234..26be0eab 100644 --- a/src/Generator/DataTransport/DataTransportGenerator.php +++ b/src/Generator/DataTransport/DataTransportGenerator.php @@ -10,6 +10,7 @@ use Reliese\Blueprint\ForeignKeyBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\DataTransportObjectGeneratorConfiguration; +use Reliese\Configuration\RelieseConfiguration; use Reliese\Generator\DataAttribute\DataAttributeGenerator; use Reliese\Generator\MySqlDataTypeMap; use Reliese\MetaCode\Definition\ClassDefinition; @@ -69,19 +70,17 @@ class DataTransportGenerator /** * DataTransportGenerator constructor. * - * @param DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration - * @param DataAttributeGenerator $dataAttributeGenerator + * @param RelieseConfiguration $relieseConfiguration */ public function __construct( - DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration, - DataAttributeGenerator $dataAttributeGenerator + RelieseConfiguration $relieseConfiguration ) { - $this->dataTransportGeneratorConfiguration = $dataTransportGeneratorConfiguration; + $this->dataTransportGeneratorConfiguration = $relieseConfiguration->getDataTransportGeneratorConfiguration(); /* * TODO: inject a MySql / Postgress or other DataType mapping as needed */ $this->dataTypeMap = new MySqlDataTypeMap(); - $this->dataAttributeGenerator = $dataAttributeGenerator; + $this->dataAttributeGenerator = new DataAttributeGenerator($relieseConfiguration); } /** diff --git a/src/Generator/Model/ModelGenerator.php b/src/Generator/Model/ModelGenerator.php index f47a76bd..1717a0f3 100644 --- a/src/Generator/Model/ModelGenerator.php +++ b/src/Generator/Model/ModelGenerator.php @@ -2,9 +2,11 @@ namespace Reliese\Generator\Model; +use Illuminate\Support\Str; use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\ModelGeneratorConfiguration; +use Reliese\Configuration\RelieseConfiguration; use Reliese\Generator\MySqlDataTypeMap; use Reliese\MetaCode\Definition\ClassConstantDefinition; use Reliese\MetaCode\Definition\ClassDefinition; @@ -15,7 +17,6 @@ use Reliese\MetaCode\Enum\VisibilityEnum; use Reliese\MetaCode\Format\ClassFormatter; use Reliese\MetaCode\Tool\ClassNameTool; -use const DIRECTORY_SEPARATOR; /** * Class ModelGenerator @@ -36,9 +37,9 @@ class ModelGenerator * * @param ModelGeneratorConfiguration $modelGeneratorConfiguration */ - public function __construct(ModelGeneratorConfiguration $modelGeneratorConfiguration) + public function __construct(RelieseConfiguration $relieseConfiguration) { - $this->modelGeneratorConfiguration = $modelGeneratorConfiguration; + $this->modelGeneratorConfiguration = $relieseConfiguration->getModelGeneratorConfiguration(); /* * TODO: inject a MySql / Postgress or other DataType mapping as needed */ From 1a4ff8eda8ce3e5d595c03d3ae668c7c8160783c Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:47:00 -0400 Subject: [PATCH 27/35] updated formatter to format abstract methods --- src/MetaCode/Definition/ClassDefinition.php | 23 ++++++++++++++++++--- src/MetaCode/Format/ClassFormatter.php | 16 +++++++++----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php index 6ed154d9..ab227156 100644 --- a/src/MetaCode/Definition/ClassDefinition.php +++ b/src/MetaCode/Definition/ClassDefinition.php @@ -2,6 +2,7 @@ namespace Reliese\MetaCode\Definition; +use Reliese\MetaCode\Enum\AbstractEnum; use Reliese\MetaCode\Tool\ClassNameTool; use RuntimeException; @@ -10,6 +11,11 @@ */ class ClassDefinition implements ImportableInterface, CodeDefinitionInterface { + /** + * @var AbstractEnum + */ + private ?AbstractEnum $abstractEnumType; + /** * @var bool[] Array keys are fully qualified interface names */ @@ -95,16 +101,19 @@ public function addConstant(ClassConstantDefinition $constant): static /** * ClassDefinition constructor. * - * @param string $className - * @param string $namespace + * @param string $className + * @param string $namespace + * @param ?AbstractEnum $abstractEnumType */ public function __construct( string $className, - string $namespace + string $namespace, + ?AbstractEnum $abstractEnumType = null ) { $this->className = $className; $this->namespace = trim($namespace, '\\'); $this->constructorStatementsCollection = new StatementDefinitionCollection(); + $this->abstractEnumType = $abstractEnumType ?? AbstractEnum::concreteEnum(); } /** @@ -480,4 +489,12 @@ public function getFilePath(): string { return $this->filePath; } + + /** + * @return AbstractEnum + */ + public function getAbstractEnumType(): AbstractEnum + { + return $this->abstractEnumType; + } } diff --git a/src/MetaCode/Format/ClassFormatter.php b/src/MetaCode/Format/ClassFormatter.php index ad71bfe1..c287b247 100644 --- a/src/MetaCode/Format/ClassFormatter.php +++ b/src/MetaCode/Format/ClassFormatter.php @@ -57,7 +57,10 @@ public function format(ClassDefinition $classDefinition): string $lines[] = " * \n * ".$line."\n"; } $lines[] = " */\n"; - $lines[] = Str::lower($classDefinition->getStructureType()) . ' ' . $classDefinition->getName(); + $lines[] = $classDefinition->getAbstractEnumType()->toReservedWord(true) + . Str::lower($classDefinition->getStructureType()) + . ' ' + . $classDefinition->getClassName(); if (!empty($parent)) { $lines[] = ' extends ' . $parent; @@ -272,14 +275,14 @@ private function formatMethod(ClassDefinition $classDefinition, ClassMethodDefin { $signature = $this->getIndentation($depth); - if ($method->getAbstractEnum()->isAbstract()) { - $signature .= $method->getAbstractEnum()->toReservedWord() . ' '; - } - if ($method->getVisibilityEnum()) { $signature .= $method->getVisibilityEnum()->toReservedWord() . ' '; } + if ($method->getAbstractEnum()->isAbstract()) { + $signature .= $method->getAbstractEnum()->toReservedWord() . ' '; + } + $signature .= 'function ' . $method->getFunctionName() . '('; $parameters = []; @@ -298,6 +301,9 @@ private function formatMethod(ClassDefinition $classDefinition, ClassMethodDefin */ $signature .= ": ". $this->shortenTypeHint($classDefinition, $method->getReturnPhpTypeEnum()); } + if ($method->getAbstractEnum()->isAbstract()) { + return $signature . ";\n"; + } $signature .= "\n"; $signature .= $this->getIndentation($depth) . "{\n"; From 1e1ae85f1b777b0260b36967e6f61180983182d9 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:47:58 -0400 Subject: [PATCH 28/35] added method to ensure the prefix of '\' is on a fully qualified name --- src/MetaCode/Tool/ClassNameTool.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/MetaCode/Tool/ClassNameTool.php b/src/MetaCode/Tool/ClassNameTool.php index 1353c09e..b021d621 100644 --- a/src/MetaCode/Tool/ClassNameTool.php +++ b/src/MetaCode/Tool/ClassNameTool.php @@ -116,4 +116,9 @@ public static function fkNameToVariableName(string $foreignKeyname): string $name = str::studly($foreignKeyname); return \strtolower($name[0]).\substr($foreignKeyname, 1); } + + public static function fullyQualifiedName(string $name) + { + return '\\'. ltrim($name, '\\'); + } } From 3269a2762120d90d3c97678324120a926f1e1383 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:49:31 -0400 Subject: [PATCH 29/35] modified Statement Block and Statement Definition Collection and added Statement Definition Collection Interface --- .../Definition/StatementBlockDefinition.php | 28 +++++++++++++++++-- .../StatementDefinitionCollection.php | 2 +- ...StatementDefinitionCollectionInterface.php | 10 +++++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 src/MetaCode/Definition/StatementDefinitionCollectionInterface.php diff --git a/src/MetaCode/Definition/StatementBlockDefinition.php b/src/MetaCode/Definition/StatementBlockDefinition.php index c3701737..883ee6ea 100644 --- a/src/MetaCode/Definition/StatementBlockDefinition.php +++ b/src/MetaCode/Definition/StatementBlockDefinition.php @@ -7,21 +7,43 @@ /** * Class StatementBlockDefinition */ -class StatementBlockDefinition extends StatementDefinitionCollection +class StatementBlockDefinition implements StatementDefinitionInterface, StatementDefinitionCollectionInterface { /** * @var StatementDefinitionInterface|null */ private ?StatementDefinitionInterface $blockPrefixStatement; + /** + * @var StatementDefinitionCollectionInterface + */ + private StatementDefinitionCollectionInterface $statementDefinitionCollection; + + /** + * StatementBlockDefinition constructor. + * + * @param StatementDefinitionInterface|null $blockPrefixStatement + * @param StatementDefinitionCollectionInterface|null $statementDefinitionCollection + */ public function __construct( - ?StatementDefinitionInterface $blockPrefixStatement + ?StatementDefinitionInterface $blockPrefixStatement, + ?StatementDefinitionCollectionInterface $statementDefinitionCollection = null, ) { $this->blockPrefixStatement = $blockPrefixStatement; + $this->statementDefinitionCollection = $statementDefinitionCollection ?? new StatementDefinitionCollection(); } private ?StatementDefinitionInterface $blockSuffixStatement = null; + public function addStatementDefinition(StatementDefinitionInterface $statementDefinition) : static + { + $this->statementDefinitionCollection->addStatementDefinition($statementDefinition); + return $this; + } + public function hasStatements(): bool + { + return $this->statementDefinitionCollection->hasStatements(); + } /** * @return string */ @@ -41,7 +63,7 @@ public function toPhpCode(IndentationProviderInterface $indentationProvider, int return \sprintf( "%s{\n%s\n%s}%s\n", $prefixStatement, - parent::toPhpCode($indentationProvider, $blockDepth + 1), + $this->statementDefinitionCollection->toPhpCode($indentationProvider, $blockDepth + 1), $indentationProvider->getIndentation($blockDepth), $suffixStatement ); diff --git a/src/MetaCode/Definition/StatementDefinitionCollection.php b/src/MetaCode/Definition/StatementDefinitionCollection.php index 63c94895..66005d2e 100644 --- a/src/MetaCode/Definition/StatementDefinitionCollection.php +++ b/src/MetaCode/Definition/StatementDefinitionCollection.php @@ -6,7 +6,7 @@ /** * Class StatementDefinitionCollection */ -class StatementDefinitionCollection implements StatementDefinitionInterface +class StatementDefinitionCollection implements StatementDefinitionInterface, StatementDefinitionCollectionInterface { /** * @var StatementDefinitionInterface[] diff --git a/src/MetaCode/Definition/StatementDefinitionCollectionInterface.php b/src/MetaCode/Definition/StatementDefinitionCollectionInterface.php new file mode 100644 index 00000000..c5c03222 --- /dev/null +++ b/src/MetaCode/Definition/StatementDefinitionCollectionInterface.php @@ -0,0 +1,10 @@ + Date: Thu, 20 May 2021 04:49:46 -0400 Subject: [PATCH 30/35] Added TryBlock Definition --- .../Definition/TryBlockDefinition.php | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/MetaCode/Definition/TryBlockDefinition.php diff --git a/src/MetaCode/Definition/TryBlockDefinition.php b/src/MetaCode/Definition/TryBlockDefinition.php new file mode 100644 index 00000000..e11b65df --- /dev/null +++ b/src/MetaCode/Definition/TryBlockDefinition.php @@ -0,0 +1,43 @@ +toDeclarationType()), + $exceptionVariableName + ) + ); + + $this->setBlockSuffixStatement( + (new StatementBlockDefinition( + $catchStatement, + $catchStatementDefinitionCollection + )) + ); + + return $this; + } +} From eda16c67a842407441f2fb42e33ed03f48ddc33f Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:50:13 -0400 Subject: [PATCH 31/35] Added Comment Block Statement Definition --- .../CommentBlockStatementDefinition.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/MetaCode/Definition/CommentBlockStatementDefinition.php diff --git a/src/MetaCode/Definition/CommentBlockStatementDefinition.php b/src/MetaCode/Definition/CommentBlockStatementDefinition.php new file mode 100644 index 00000000..e2ceee8d --- /dev/null +++ b/src/MetaCode/Definition/CommentBlockStatementDefinition.php @@ -0,0 +1,35 @@ +text[] = $line; + return $this; + } + + public function toPhpCode(IndentationProviderInterface $indentationProvider, int $blockDepth): string + { + if (empty($this->text)) { + return ""; + } + + $statements[] = $indentationProvider->getIndentation($blockDepth)."/**"; + foreach ($this->text as $line) { + $statements[] = $indentationProvider->getIndentation($blockDepth).' * '.$line; + } + $statements[] = $indentationProvider->getIndentation($blockDepth)." */"; + return \implode("\n", $statements); + } +} \ No newline at end of file From 64beb5f10eb36f0ef53de99663272b4d6f295efb Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:50:44 -0400 Subject: [PATCH 32/35] updated Abstract Enum --- src/MetaCode/Enum/AbstractEnum.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MetaCode/Enum/AbstractEnum.php b/src/MetaCode/Enum/AbstractEnum.php index fed94664..9348613c 100644 --- a/src/MetaCode/Enum/AbstractEnum.php +++ b/src/MetaCode/Enum/AbstractEnum.php @@ -7,7 +7,7 @@ */ class AbstractEnum { - protected const CONCRETE_TYPE_ID = 0; + protected const CONCRETE_TYPE_ID = 10; protected const ABSTRACT_TYPE_ID = 20; @@ -48,10 +48,10 @@ public static function concreteEnum(): AbstractEnum return static::$abstractEnumInstance = new static(static::CONCRETE_TYPE_ID); } - public function toReservedWord() : string + public function toReservedWord(bool $includeTrailingSpace = false) : string { if (static::isAbstract()) { - return 'abstract'; + return 'abstract' . ($includeTrailingSpace ? ' ' : ''); } if (static::isConcrete()) { @@ -68,7 +68,7 @@ public function __toString(): string } if (static::isAbstract()) { - return 'static'; + return 'abstract'; } return 'UNKNOWN'; From bcfcd83435ccce758bfdd5565b46ea426858e059 Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:51:15 -0400 Subject: [PATCH 33/35] Added ModelGenerate::getClassAsVariableName() --- src/Generator/Model/ModelGenerator.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Generator/Model/ModelGenerator.php b/src/Generator/Model/ModelGenerator.php index 1717a0f3..cf5d1a0c 100644 --- a/src/Generator/Model/ModelGenerator.php +++ b/src/Generator/Model/ModelGenerator.php @@ -152,6 +152,12 @@ public function generateColumnConstantDefinition(ColumnBlueprint $columnBlueprin ); } + public function getClassAsVariableName(TableBlueprint $tableBlueprint): string + { + $name = $this->getClassName($tableBlueprint); + return strtolower($name[0]).substr($name, 1); + } + /** * @return string */ From b016a77a46f8dcdbb5f0769695af8ddccf74141b Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:53:22 -0400 Subject: [PATCH 34/35] Updates to ModelDataMapGenerator to always generate accessor traits --- .../DataMap/ModelDataMapGenerator.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Generator/DataMap/ModelDataMapGenerator.php b/src/Generator/DataMap/ModelDataMapGenerator.php index 5466432f..cde2fe08 100644 --- a/src/Generator/DataMap/ModelDataMapGenerator.php +++ b/src/Generator/DataMap/ModelDataMapGenerator.php @@ -128,8 +128,8 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) /* * Determine the dto Class name and namespace */ - $dtoClassName = $this->dataTransportGenerator->getClassName($tableBlueprint); - $dtoFullyQualifiedClassName = $this->dataTransportGenerator->getFullyQualifiedClassName($tableBlueprint); + $dtoClassName = $this->dataTransportObjectGenerator->getClassName($tableBlueprint); + $dtoFullyQualifiedClassName = $this->dataTransportObjectGenerator->getFullyQualifiedClassName($tableBlueprint); $dtoParameterName = ClassNameTool::classNameToParameterName($dtoClassName); $dtoParameterType = PhpTypeEnum::objectOfType($dtoFullyQualifiedClassName); @@ -186,7 +186,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) } */ $requiredMapAccessorTraits = []; - $fkDtoProperties = $this->dataTransportGenerator->getForeignKeyDtoPropertyDefinitions($tableBlueprint); + $fkDtoProperties = $this->dataTransportObjectGenerator->getForeignKeyDtoPropertyDefinitions($tableBlueprint); foreach ($fkDtoProperties as $fkDtoProperty) { // $fkDtoProperty = $fkDtoProperties[$foreignKeyBlueprint->getName()]; @@ -330,6 +330,13 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint) .$traitDefinition->getClassName().".php"; $codeWriter->overwriteClassDefinition($filePath, $traitSource); } + + $traitDefinition = $this->generateModelDataMapAccessorTrait($modelMapClassDefinition->getFullyQualifiedName()); + $traitSource = (new ClassFormatter())->format($traitDefinition); + $filePath = $this->modelDataMapGeneratorConfiguration->getAccessorTraitPath().'/' + .$traitDefinition->getClassName().".php"; + $codeWriter->overwriteClassDefinition($filePath, $traitSource); + $this->writeClassFiles($modelMapClassDefinition, $modelMapAbstractClassDefinition); } @@ -433,6 +440,11 @@ public function getAbstractClassNamespace(TableBlueprint $tableBlueprint): strin return $this->getClassNamespace($tableBlueprint) .'\\Generated'; } + public function getModelMapAccessorTraitMethodName(TableBlueprint $tableBlueprint): string + { + return 'get'.$this->getClassName($tableBlueprint); + } + /** * @param ClassDefinition $classDefinition * @param ClassDefinition $abstractClassDefinition From a202671f8a27592766022f8d7842ff6dda68ef4c Mon Sep 17 00:00:00 2001 From: Adam Lenda Date: Thu, 20 May 2021 04:54:11 -0400 Subject: [PATCH 35/35] DataAccess layer code generation for Fetch By , Create and Update --- .../DataAccess/DataAccessGenerator.php | 703 +++++++++++++++++- 1 file changed, 666 insertions(+), 37 deletions(-) diff --git a/src/Generator/DataAccess/DataAccessGenerator.php b/src/Generator/DataAccess/DataAccessGenerator.php index 36cbccad..19cf2d90 100644 --- a/src/Generator/DataAccess/DataAccessGenerator.php +++ b/src/Generator/DataAccess/DataAccessGenerator.php @@ -2,32 +2,64 @@ namespace Reliese\Generator\DataAccess; +use app\DataStores\MySql\MySqlErrorTypes; +use app\DataTransport\Objects\PrimaryDatabase\AccountDto; +use App\Models\PrimaryDatabase\Account; +use app\Patterns\Log\LogException; +use app\Patterns\Log\LogMessage; +use app\Patterns\MethodResponses\CreateMethodResponse; +use app\Patterns\MethodResponses\FetchMethodResponse; +use app\Patterns\MethodResponses\GetMethodResponse; +use app\Patterns\MethodResponses\UpdateMethodResponse; +use Illuminate\Support\Str; +use Reliese\Blueprint\ColumnBlueprint; use Reliese\Blueprint\DatabaseBlueprint; +use Reliese\Blueprint\IndexBlueprint; use Reliese\Blueprint\TableBlueprint; use Reliese\Configuration\DataAccessGeneratorConfiguration; +use Reliese\Configuration\RelieseConfiguration; use Reliese\Generator\DataAttribute\DataAttributeGenerator; +use Reliese\Generator\DataMap\ModelDataMapGenerator; +use Reliese\Generator\DataTransport\DataTransportObjectGenerator; +use Reliese\Generator\Model\ModelGenerator; use Reliese\Generator\MySqlDataTypeMap; +use Reliese\MetaCode\Definition\ClassConstantDefinition; use Reliese\MetaCode\Definition\ClassDefinition; -use Reliese\MetaCode\Definition\ClassPropertyDefinition; +use Reliese\MetaCode\Definition\ClassMethodDefinition; use Reliese\MetaCode\Definition\ClassTraitDefinition; +use Reliese\MetaCode\Definition\CommentBlockStatementDefinition; +use Reliese\MetaCode\Definition\FunctionParameterDefinition; +use Reliese\MetaCode\Definition\ObjectTypeDefinition; +use Reliese\MetaCode\Definition\RawStatementDefinition; +use Reliese\MetaCode\Definition\StatementBlockDefinition; +use Reliese\MetaCode\Definition\StatementDefinitionCollection; +use Reliese\MetaCode\Definition\TryBlockDefinition; +use Reliese\MetaCode\Enum\AbstractEnum; +use Reliese\MetaCode\Enum\InstanceEnum; +use Reliese\MetaCode\Enum\PhpTypeEnum; +use Reliese\MetaCode\Enum\VisibilityEnum; use Reliese\MetaCode\Format\ClassFormatter; use Reliese\MetaCode\Tool\ClassNameTool; -use const DIRECTORY_SEPARATOR; /** * Class DataAccessGenerator */ class DataAccessGenerator { + /** + * @var DataAccessGeneratorConfiguration + */ + private DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration; + /** * @var DataAttributeGenerator */ private DataAttributeGenerator $dataAttributeGenerator; /** - * @var DataAccessGeneratorConfiguration + * @var DataTransportObjectGenerator */ - private DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration; + private DataTransportObjectGenerator $dataTransportObjectGenerator; /** * @var MySqlDataTypeMap @@ -39,49 +71,95 @@ class DataAccessGenerator */ private DatabaseBlueprint $databaseBlueprint; + /** + * @var ModelDataMapGenerator + */ + private ModelDataMapGenerator $modelDataMapGenerator; + + /** + * @var ModelGenerator + */ + private ModelGenerator $modelGenerator; + /** * DataAccessGenerator constructor. * - * @param DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration + * @param RelieseConfiguration $relieseConfiguration */ - public function __construct( - DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration - ) { - $this->dataAccessGeneratorConfiguration = $dataAccessGeneratorConfiguration; + public function __construct(RelieseConfiguration $relieseConfiguration) + { + $this->dataAccessGeneratorConfiguration = $relieseConfiguration->getDataAccessGeneratorConfiguration(); /* * TODO: inject a MySql / Postgress or other DataType mapping as needed */ $this->dataTypeMap = new MySqlDataTypeMap(); + $this->modelGenerator = new ModelGenerator($relieseConfiguration); + $this->dataTransportObjectGenerator = new DataTransportObjectGenerator($relieseConfiguration); + $this->modelDataMapGenerator = new ModelDataMapGenerator($relieseConfiguration); } /** * @param TableBlueprint $tableBlueprint */ - public function fromTableBlueprint( - TableBlueprint $tableBlueprint - ) { + public function fromTableBlueprint(TableBlueprint $tableBlueprint) + { + $classDefinition = $this->generateClassDefinition($tableBlueprint); + $abstractClassDefinition = $this->generateAbstractClassDefinition($tableBlueprint); - $className = $this->getClassName($tableBlueprint); + /* + * TODO: Add generic methods like "get by id" + */ - $abstractClassName = $this->getAbstractClassName($tableBlueprint); + /* + * Write the Class Files + */ + $this->writeClassFiles($classDefinition, $abstractClassDefinition); + } + public function generateClassDefinition(TableBlueprint $tableBlueprint): ClassDefinition + { + $abstractClassDefinition = $this->generateAbstractClassDefinition($tableBlueprint); + + $className = $this->getClassName($tableBlueprint); $namespace = $this->getClassNamespace($tableBlueprint); + $classDefinition = new ClassDefinition($className, $namespace); + $classDefinition->setParentClass($abstractClassDefinition->getFullyQualifiedName()); + + return $classDefinition; + } + public function generateAbstractClassDefinition(TableBlueprint $tableBlueprint): ClassDefinition + { + $abstractClassName = $this->getAbstractClassName($tableBlueprint); $abstractNamespace = $this->getAbstractClassNamespace($tableBlueprint); + $abstractClassDefinition = new ClassDefinition($abstractClassName, + $abstractNamespace, + AbstractEnum::abstractEnum()); - $dtoAbstractClassDefinition = new ClassDefinition($abstractClassName, $abstractNamespace); + $modelObjectTypeDefinition + = new ObjectTypeDefinition($this->modelGenerator->getFullyQualifiedClassName($tableBlueprint)); - $dtoClassDefinition = new ClassDefinition($className, $namespace); - $dtoClassDefinition->setParentClass($dtoAbstractClassDefinition->getFullyQualifiedName()); + $abstractClassDefinition + # include the WithDataMap trait + ->addTrait(new ClassTraitDefinition($this->modelDataMapGenerator->generateModelDataMapAccessorTrait($this->modelDataMapGenerator->getFullyQualifiedClassName($tableBlueprint)) + ->getFullyQualifiedName())) + ->addConstant(new ClassConstantDefinition($this->getMapFromFailedConstantName($modelObjectTypeDefinition), + $this->getMapFromFailedConstantName($modelObjectTypeDefinition), + VisibilityEnum::protectedEnum()),) + ->addConstant(new ClassConstantDefinition($this->getMapToFailedConstantName($modelObjectTypeDefinition), + $this->getMapToFailedConstantName($modelObjectTypeDefinition), + VisibilityEnum::protectedEnum())) + ; - /* - * TODO: Add generic methods like "get by id" - */ + $this->addFetchByUniqueColumnMethods($tableBlueprint, $abstractClassDefinition); - /* - * Write the Class Files - */ - $this->writeClassFiles($dtoClassDefinition, $dtoAbstractClassDefinition); + $abstractClassDefinition->addMethodDefinition($this->generateCreateMethod($tableBlueprint, + $abstractClassDefinition)); + + $abstractClassDefinition->addMethodDefinition($this->generateUpdateMethod($tableBlueprint, + $abstractClassDefinition)); + + return $abstractClassDefinition; } /** @@ -91,7 +169,7 @@ public function fromTableBlueprint( */ public function getFullyQualifiedClassName(TableBlueprint $tableBlueprint): string { - return $this->getClassNamespace($tableBlueprint).'\\'.$this->getClassName($tableBlueprint); + return $this->getClassNamespace($tableBlueprint) . '\\' . $this->getClassName($tableBlueprint); } public function getClassNamespace(TableBlueprint $tableBlueprint): string @@ -101,32 +179,424 @@ public function getClassNamespace(TableBlueprint $tableBlueprint): string public function getClassName(TableBlueprint $tableBlueprint): string { - return ClassNameTool::snakeCaseToClassName( - $this->dataAccessGeneratorConfiguration->getClassPrefix(), + return ClassNameTool::snakeCaseToClassName($this->dataAccessGeneratorConfiguration->getClassPrefix(), $tableBlueprint->getName(), - $this->dataAccessGeneratorConfiguration->getClassSuffix() - ); + $this->dataAccessGeneratorConfiguration->getClassSuffix()); + } + + public function getFetchByUniqueColumnFunctionName(ColumnBlueprint $uniqueColumn): string + { + return "fetchBy" . Str::studly($uniqueColumn->getColumnName()); + } + + private function generateCreateMethod(TableBlueprint $tableBlueprint, + ClassDefinition $classDefinition): ClassMethodDefinition + { + $modelObjectTypeDefinition + = new ObjectTypeDefinition($this->modelGenerator->getFullyQualifiedClassName($tableBlueprint)); + $mySqlErrorTypesObjectTypeDefinition = new ObjectTypeDefinition('\app\DataStores\MySql\MySqlErrorTypes'); + $queryExceptionTypeDefinition = new ObjectTypeDefinition('\Illuminate\Database\QueryException'); + $logMessageObjectTypeDefinition = new ObjectTypeDefinition('\app\Patterns\Log\LogMessage'); + $logExceptionObjectTypeDefinition = new ObjectTypeDefinition('\app\Patterns\Log\LogException'); + $returnTypeObjectTypeDefinition + = new ObjectTypeDefinition('\app\Patterns\MethodResponses\CreateMethodResponse'); + $dtoTypeObjectTypeDefinition + = new ObjectTypeDefinition($this->dataTransportObjectGenerator->getFullyQualifiedClassName($tableBlueprint)); + $modelTypeObjectTypeDefinition + = new ObjectTypeDefinition($this->modelGenerator->getFullyQualifiedClassName($tableBlueprint)); + $modelDataMapTraitObjectTypeDefinition + = new ObjectTypeDefinition($this->modelDataMapGenerator->generateModelDataMapAccessorTrait($this->modelDataMapGenerator->getFullyQualifiedClassName($tableBlueprint)) + ->getFullyQualifiedName()); + $classDefinition->addImport($modelObjectTypeDefinition) + ->addImport($mySqlErrorTypesObjectTypeDefinition) + ->addImport($logMessageObjectTypeDefinition) + ->addImport($logExceptionObjectTypeDefinition) + ->addImport($returnTypeObjectTypeDefinition) + ->addImport($dtoTypeObjectTypeDefinition) + ->addImport($modelTypeObjectTypeDefinition) + ->addImport($modelDataMapTraitObjectTypeDefinition) + ; + + $functionName = "create"; + $returnType = PhpTypeEnum::objectOfType($returnTypeObjectTypeDefinition->getFullyQualifiedName()); + $modelVariableName = $this->modelGenerator->getClassAsVariableName($tableBlueprint); + + $methodFailedConstantName = sprintf('%s_CREATE_FAILED', + Str::upper($modelTypeObjectTypeDefinition->getImportableName())); + $classDefinition->addConstant(new ClassConstantDefinition($methodFailedConstantName, + $methodFailedConstantName, + VisibilityEnum::protectedEnum())); + $dtoParameterDefinition = $this->getDtoFunctionParameterDefinition($dtoTypeObjectTypeDefinition); + $exceptionVariableName = 'exception'; + + /* + * Build Unique Constraint Error Handling Conditions + */ + $catchBlockStatements = new StatementDefinitionCollection(); + $catchBlockStatements->addStatementDefinition((new CommentBlockStatementDefinition())->addLine("Treat unique key errors as validation failures")) + ->addStatementDefinition((new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (!empty(\$%s->errorInfo[1]) && %s::UNIQUE_KEY_VIOLATION_TYPE_ID === \$%s->errorInfo[1])", + $exceptionVariableName, + $mySqlErrorTypesObjectTypeDefinition->getImportableName(), + $exceptionVariableName))))->addStatementDefinition($foreachBlock + = (new StatementBlockDefinition(new RawStatementDefinition(sprintf("foreach (\$%s->errorInfo as \$value)", + $exceptionVariableName,)))))) + ; + + foreach ($tableBlueprint->getUniqueIndexes(false) as $uniqueIndexBlueprint) { + $validationMessageMethod = $this->getUniqueKeyViolationValidationMessageMethod($classDefinition, + $uniqueIndexBlueprint); + + $classDefinition->addMethodDefinition($validationMessageMethod); + + $foreachBlock->addStatementDefinition((new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (str_contains(\$value, '%s'))", + $uniqueIndexBlueprint->getName()))))->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::invalid([\$this->%s()]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $validationMessageMethod->getFunctionName())))); + } + + $catchBlockStatements->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::error([new %s(static::%s), new %s(\$%s),]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $logMessageObjectTypeDefinition->getImportableName(), + $methodFailedConstantName, + $logExceptionObjectTypeDefinition->getImportableName(), + $exceptionVariableName))); + /* + * Build Class Method definition + */ + $classMethodDefinition = new ClassMethodDefinition($functionName, $returnType, [$dtoParameterDefinition]); + $classMethodDefinition->appendBodyStatement(// new model statement + new RawStatementDefinition(sprintf("\$%s = new %s();", + $modelVariableName, + $modelTypeObjectTypeDefinition->getImportableName()))) + ->appendBodyStatement((new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (!\$this->%s()->from%s(\$%s, \$%s))", + $this->modelDataMapGenerator->getModelMapAccessorTraitMethodName($tableBlueprint), + $dtoTypeObjectTypeDefinition->getImportableName(), + $modelVariableName, + $dtoParameterDefinition->getParameterName()))))->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::error([new %s(static::%s), new %s(static::%s)]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $logMessageObjectTypeDefinition->getImportableName(), + $this->getMapFromFailedConstantName($modelTypeObjectTypeDefinition), + $logMessageObjectTypeDefinition->getImportableName(), + $methodFailedConstantName)))) + // try save block + ->appendBodyStatement( + $this->getSaveModelTryBlock($modelVariableName, + $returnTypeObjectTypeDefinition, + $logMessageObjectTypeDefinition, + $methodFailedConstantName, + $queryExceptionTypeDefinition, + $exceptionVariableName, + $catchBlockStatements)) + // after try block, map model to dto + ->appendBodyStatement($this->getMapToDtoStatementBlock($tableBlueprint, + $dtoTypeObjectTypeDefinition, + $modelVariableName, + $dtoParameterDefinition, + $this->getMapToFailedConstantName($modelObjectTypeDefinition), + $returnTypeObjectTypeDefinition)) + # return created + ->appendBodyStatement(new RawStatementDefinition(sprintf("return %s::created();", + $returnTypeObjectTypeDefinition->getImportableName()))) + ; + + return $classMethodDefinition; + } + + private function generateUpdateMethod(TableBlueprint $tableBlueprint, + ClassDefinition $classDefinition): ClassMethodDefinition + { + $modelObjectTypeDefinition + = new ObjectTypeDefinition($this->modelGenerator->getFullyQualifiedClassName($tableBlueprint)); + $mySqlErrorTypesObjectTypeDefinition = new ObjectTypeDefinition('\app\DataStores\MySql\MySqlErrorTypes'); + $queryExceptionTypeDefinition = new ObjectTypeDefinition('\Illuminate\Database\QueryException'); + $logMessageObjectTypeDefinition = new ObjectTypeDefinition('\app\Patterns\Log\LogMessage'); + $logExceptionObjectTypeDefinition = new ObjectTypeDefinition('\app\Patterns\Log\LogException'); + $returnTypeObjectTypeDefinition + = new ObjectTypeDefinition('\app\Patterns\MethodResponses\UpdateMethodResponse'); + $dtoTypeObjectTypeDefinition + = new ObjectTypeDefinition($this->dataTransportObjectGenerator->getFullyQualifiedClassName($tableBlueprint)); + $modelTypeObjectTypeDefinition + = new ObjectTypeDefinition($this->modelGenerator->getFullyQualifiedClassName($tableBlueprint)); + $modelDataMapTraitObjectTypeDefinition + = new ObjectTypeDefinition($this->modelDataMapGenerator->generateModelDataMapAccessorTrait($this->modelDataMapGenerator->getFullyQualifiedClassName($tableBlueprint)) + ->getFullyQualifiedName()); + $classDefinition->addImport($modelObjectTypeDefinition) + ->addImport($mySqlErrorTypesObjectTypeDefinition) + ->addImport($logMessageObjectTypeDefinition) + ->addImport($logExceptionObjectTypeDefinition) + ->addImport($returnTypeObjectTypeDefinition) + ->addImport($dtoTypeObjectTypeDefinition) + ->addImport($modelTypeObjectTypeDefinition) + ->addImport($modelDataMapTraitObjectTypeDefinition) + ; + + $functionName = "update"; + $returnType = PhpTypeEnum::objectOfType($returnTypeObjectTypeDefinition->getFullyQualifiedName()); + $modelVariableName = $this->modelGenerator->getClassAsVariableName($tableBlueprint); + + $methodFailedConstantName = sprintf('%s_UPDATE_FAILED', + Str::upper($modelTypeObjectTypeDefinition->getImportableName())); + $classDefinition->addConstant(new ClassConstantDefinition($methodFailedConstantName, + $methodFailedConstantName, + VisibilityEnum::protectedEnum())); + $dtoParameterDefinition = $this->getDtoFunctionParameterDefinition($dtoTypeObjectTypeDefinition); + $exceptionVariableName = 'exception'; + + /* + * Build Unique Constraint Error Handling Conditions + */ + $catchBlockStatements = new StatementDefinitionCollection(); + $catchBlockStatements->addStatementDefinition((new CommentBlockStatementDefinition())->addLine("Treat unique key errors as validation failures")) + ->addStatementDefinition((new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (!empty(\$%s->errorInfo[1]) && %s::UNIQUE_KEY_VIOLATION_TYPE_ID === \$%s->errorInfo[1])", + $exceptionVariableName, + $mySqlErrorTypesObjectTypeDefinition->getImportableName(), + $exceptionVariableName))))->addStatementDefinition($foreachBlock + = (new StatementBlockDefinition(new RawStatementDefinition(sprintf("foreach (\$%s->errorInfo as \$value)", + $exceptionVariableName,)))))) + ; + + foreach ($tableBlueprint->getUniqueIndexes(false) as $uniqueIndexBlueprint) { + $validationMessageMethod = $this->getUniqueKeyViolationValidationMessageMethod($classDefinition, + $uniqueIndexBlueprint); + + $classDefinition->addMethodDefinition($validationMessageMethod); + + $foreachBlock->addStatementDefinition((new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (str_contains(\$value, '%s'))", + $uniqueIndexBlueprint->getName()))))->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::invalid([\$this->%s()]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $validationMessageMethod->getFunctionName())))); + } + + $catchBlockStatements->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::error([new %s(static::%s), new %s(\$%s),]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $logMessageObjectTypeDefinition->getImportableName(), + $methodFailedConstantName, + $logExceptionObjectTypeDefinition->getImportableName(), + $exceptionVariableName))); + /* + * Define Find Model by Dto Id try block + */ + $findModelTryBlock = new TryBlockDefinition(); + $findModelTryBlock->addStatementDefinition(// find model statement + new RawStatementDefinition(sprintf("\$%s = %s::find(\$%s->getId());", + $modelVariableName, + $modelTypeObjectTypeDefinition->getImportableName(), + $dtoParameterDefinition->getParameterName()))) + ->addCatchStatements(PhpTypeEnum::objectOfType(\Exception::class), + $exceptionVariableName, + (new StatementDefinitionCollection())->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::error([new LogMessage(static::%s), new LogException(\$%s),]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $methodFailedConstantName, + $exceptionVariableName)))) + ; + /* + * Define if model->save() Try Block + */ + $modelSaveTryBlock = new TryBlockDefinition(); + $modelSaveTryBlock + ->addStatementDefinition( + (new StatementBlockDefinition( + new RawStatementDefinition( + sprintf( + "if (!\$%s->save())", + $modelVariableName)))) + ->addStatementDefinition( + new RawStatementDefinition( + sprintf( + "return %s::error([new %s(static::%s)]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $logMessageObjectTypeDefinition->getImportableName(), + $methodFailedConstantName + ))) + ); + // if (!$model->save()) + /* + * Build Class Method definition + */ + $classMethodDefinition = new ClassMethodDefinition($functionName, $returnType, [$dtoParameterDefinition]); + $classMethodDefinition + // Add try find model + ->appendBodyStatement($findModelTryBlock) + // Add if model not found + ->appendBodyStatement($this->getModelNotFoundStatementBlock($modelVariableName, + $returnTypeObjectTypeDefinition)) + // Add map DTO to Model block + ->appendBodyStatement($this->getMapFromDtoStatementBlock($tableBlueprint, + $dtoTypeObjectTypeDefinition, + $modelVariableName, + $dtoParameterDefinition, + $returnTypeObjectTypeDefinition, + $logMessageObjectTypeDefinition, + $modelTypeObjectTypeDefinition, + $methodFailedConstantName)) + // try save block + ->appendBodyStatement( + $this->getSaveModelTryBlock($modelVariableName, + $returnTypeObjectTypeDefinition, + $logMessageObjectTypeDefinition, + $methodFailedConstantName, + $queryExceptionTypeDefinition, + $exceptionVariableName, + $catchBlockStatements)) + // after try block, map model to dto + ->appendBodyStatement($this->getMapToDtoStatementBlock($tableBlueprint, + $dtoTypeObjectTypeDefinition, + $modelVariableName, + $dtoParameterDefinition, + $this->getMapToFailedConstantName($modelObjectTypeDefinition), + $returnTypeObjectTypeDefinition)) + # return updated + ->appendBodyStatement(new RawStatementDefinition(sprintf("return %s::updated();", + $returnTypeObjectTypeDefinition->getImportableName()))) + ; + + return $classMethodDefinition; + } + + /** + * Calls \Reliese\Generator\DataAccess\DataAccessGenerator::generateFetchByUniqueColumnMethodDefinition foreach + * unique column + * + * @param TableBlueprint $tableBlueprint + * @param ClassDefinition $abstractClassDefinition + * + * @return array + */ + private function addFetchByUniqueColumnMethods(TableBlueprint $tableBlueprint, + ClassDefinition $abstractClassDefinition) + { + $uniqueColumnGroups = $tableBlueprint->getUniqueColumnGroups(); + + foreach ($uniqueColumnGroups as $uniqueColumnGroup) { + if (1 < count($uniqueColumnGroup)) { + continue; + } + + $uniqueColumn = array_pop($uniqueColumnGroup); + + $abstractClassDefinition->addMethodDefinition($this->generateFetchByUniqueColumnMethodDefinition($abstractClassDefinition, + $tableBlueprint, + $uniqueColumn)); + } + } + + /** + * Example Output + * + * public function fetchByExternalKey(AccountDto $accountDto): FetchMethodResponse + * { + * try { + * $account = Account::where(Account::EXTERNAL_KEY, $accountDto->getExternalKey())->first(); + * } catch (\Exception $exception) { + * return FetchMethodResponse::error([new LogMessage(static::ACCOUNT_FETCH_BY_EXTERNAL_KEY_FAILED), new + * LogException($exception),]); + * } + * if (!$account) { + * return FetchMethodResponse::notFound(); + * } + * if (!$this->getAccountMap()->toAccountDto($account, $accountDto)) { + * return FetchMethodResponse::error([new LogMessage(self::ACCOUNT_MAP_TO_DTO_FAILED)]); + * } + * return FetchMethodResponse::found(); + * } + * + * + * @param ClassDefinition $classDefinition + * @param TableBlueprint $tableBlueprint + * @param ColumnBlueprint $uniqueColumn + * + * @return ClassMethodDefinition + */ + private function generateFetchByUniqueColumnMethodDefinition(ClassDefinition $classDefinition, + TableBlueprint $tableBlueprint, + ColumnBlueprint $uniqueColumn): ClassMethodDefinition + { + $logMessageObjectTypeDefinition = new ObjectTypeDefinition('\app\Patterns\Log\LogMessage'); + $logExceptionObjectTypeDefinition = new ObjectTypeDefinition('\app\Patterns\Log\LogException'); + $returnTypeObjectTypeDefinition = new ObjectTypeDefinition('\app\Patterns\MethodResponses\FetchMethodResponse'); + $dtoTypeObjectTypeDefinition + = new ObjectTypeDefinition($this->dataTransportObjectGenerator->getFullyQualifiedClassName($tableBlueprint)); + $modelObjectTypeDefinition + = new ObjectTypeDefinition($this->modelGenerator->getFullyQualifiedClassName($tableBlueprint)); + $modelDataMapTraitObjectTypeDefinition + = new ObjectTypeDefinition($this->modelDataMapGenerator->generateModelDataMapAccessorTrait($this->modelDataMapGenerator->getFullyQualifiedClassName($tableBlueprint)) + ->getFullyQualifiedName()); + $classDefinition->addImport($logMessageObjectTypeDefinition) + ->addImport($logExceptionObjectTypeDefinition) + ->addImport($returnTypeObjectTypeDefinition) + ->addImport($dtoTypeObjectTypeDefinition) + ->addImport($modelObjectTypeDefinition) + ->addImport($modelDataMapTraitObjectTypeDefinition) + ; + + $columnCamelName = Str::studly($uniqueColumn->getColumnName()); + + $modelVariableName = $this->modelGenerator->getClassAsVariableName($tableBlueprint); + + $dtoParameterDefinition = $this->getDtoFunctionParameterDefinition($dtoTypeObjectTypeDefinition); + + $classMethodDefinition = new ClassMethodDefinition($this->getFetchByUniqueColumnFunctionName($uniqueColumn), + PhpTypeEnum::objectOfType($returnTypeObjectTypeDefinition->getFullyQualifiedName()), + [$dtoParameterDefinition]); + + $methodFailedConstantName = sprintf('%s_FETCH_BY_%s_FAILED', + Str::upper($modelObjectTypeDefinition->getImportableName()), + Str::upper(Str::snake($columnCamelName))); + + $classDefinition + # include _FETCH_BY__FAILED constant + ->addConstant(new ClassConstantDefinition($methodFailedConstantName, + $methodFailedConstantName, + VisibilityEnum::protectedEnum())); + + $exceptionVariableName = 'exception'; + + $columnConstantDefinition = $this->modelGenerator->generateColumnConstantDefinition($uniqueColumn); + $classMethodDefinition->appendBodyStatement((new TryBlockDefinition())->addStatementDefinition(# include the Eloquent query to fetch the model by the unique column value + new RawStatementDefinition(sprintf("\$%s = %s::where(%s::%s, \$%s->get%s())->first();", + $modelVariableName, + $modelObjectTypeDefinition->getImportableName(), + $modelObjectTypeDefinition->getImportableName(), + $columnConstantDefinition->getName(), + $dtoParameterDefinition->getParameterName(), + $columnCamelName))) + ->addCatchStatements(PhpTypeEnum::objectOfType(\Exception::class), + $exceptionVariableName, + (new StatementDefinitionCollection())->addStatementDefinition(new RawStatementDefinition(sprintf("return FetchMethodResponse::error([new LogMessage(static::%s), new LogException(\$%s),]);", + $methodFailedConstantName, + $exceptionVariableName))))) + # include the conditional check to determine if it was found + ->appendBodyStatement($this->getModelNotFoundStatementBlock($modelVariableName, + $returnTypeObjectTypeDefinition)) + # include the conditional check to determine if it was mapped successfully + ->appendBodyStatement($this->getMapToDtoStatementBlock($tableBlueprint, + $dtoTypeObjectTypeDefinition, + $modelVariableName, + $dtoParameterDefinition, + $this->getMapToFailedConstantName($modelObjectTypeDefinition), + $returnTypeObjectTypeDefinition)) + ->appendBodyStatement(new RawStatementDefinition("return FetchMethodResponse::found();")) + ; + + return $classMethodDefinition; } private function getAbstractClassName(TableBlueprint $tableBlueprint): string { - return $this->dataAccessGeneratorConfiguration->getParentClassPrefix() - . $this->getClassName($tableBlueprint); + return $this->dataAccessGeneratorConfiguration->getParentClassPrefix() . $this->getClassName($tableBlueprint); } private function getAbstractClassNamespace(TableBlueprint $tableBlueprint): string { - return $this->getClassNamespace($tableBlueprint) .'\\Generated'; + return $this->getClassNamespace($tableBlueprint) . '\\Generated'; } /** * @param ClassDefinition $classDefinition * @param ClassDefinition $abstractClassDefinition */ - private function writeClassFiles( - ClassDefinition $classDefinition, - ClassDefinition $abstractClassDefinition, - ): void + private function writeClassFiles(ClassDefinition $classDefinition, + ClassDefinition $abstractClassDefinition,): void { $classFormatter = new ClassFormatter(); @@ -144,11 +614,170 @@ private function writeClassFiles( } $dtoFilePath = $dtoClassFolder . DIRECTORY_SEPARATOR . $classDefinition->getName() . '.php'; - $abstractDtoFilePath = $abstractDtoClassFolder . DIRECTORY_SEPARATOR . $abstractClassDefinition->getName() . '.php'; + $abstractDtoFilePath = $abstractDtoClassFolder + . DIRECTORY_SEPARATOR + . $abstractClassDefinition->getName() + . '.php'; if (!\file_exists($dtoFilePath)) { \file_put_contents($dtoFilePath, $dtoClassPhpCode); } \file_put_contents($abstractDtoFilePath, $abstractDtoPhpCode); } + + private function getMapToFailedConstantName(ObjectTypeDefinition $modelObjectTypeDefinition) + { + return sprintf('%s_MAP_TO_DTO_FAILED', + Str::upper($modelObjectTypeDefinition->getImportableName())); + } + + private function getMapFromFailedConstantName(ObjectTypeDefinition $modelObjectTypeDefinition) + { + return sprintf('%s_MAP_FROM_DTO_FAILED', + Str::upper($modelObjectTypeDefinition->getImportableName())); + } + + private function getDtoFunctionParameterDefinition(ObjectTypeDefinition $dtoTypeObjectTypeDefinition): FunctionParameterDefinition + { + return new FunctionParameterDefinition($this->getDtoVariableName($dtoTypeObjectTypeDefinition), + PhpTypeEnum::objectOfType($dtoTypeObjectTypeDefinition->getFullyQualifiedName())); + } + + private function getDtoVariableName(ObjectTypeDefinition $dtoTypeObjectTypeDefinition): string + { + $name = $dtoTypeObjectTypeDefinition->getImportableName(); + return strtolower($name[0]) . substr($name, 1); + } + + private function getUniqueKeyViolationValidationMessageMethod(ClassDefinition $classDefinition, + IndexBlueprint $indexBlueprint): ClassMethodDefinition + { + $returnType = new ObjectTypeDefinition(\Symfony\Component\Translation\TranslatableMessage::class); + $classDefinition->addImport($returnType); + + $functionName = sprintf("getUniqueKeyValidationMessageFor%s", + Str::studly($indexBlueprint->getName())); + + return new ClassMethodDefinition($functionName, + PhpTypeEnum::objectOfType($returnType->getFullyQualifiedName()), + [], + VisibilityEnum::protectedEnum(), + InstanceEnum::instanceEnum(), + AbstractEnum::abstractEnum()); + } + + /** + * @param TableBlueprint $tableBlueprint + * @param ObjectTypeDefinition $dtoTypeObjectTypeDefinition + * @param string $modelVariableName + * @param FunctionParameterDefinition $dtoParameterDefinition + * @param string $mapToFailedConstantName + * @param ObjectTypeDefinition $returnObjectTypeDefinition + * + * @return StatementBlockDefinition + */ + private function getMapToDtoStatementBlock(TableBlueprint $tableBlueprint, + ObjectTypeDefinition $dtoTypeObjectTypeDefinition, + string $modelVariableName, + FunctionParameterDefinition $dtoParameterDefinition, + string $mapToFailedConstantName, + ObjectTypeDefinition $returnObjectTypeDefinition): StatementBlockDefinition + { + return (new StatementBlockDefinition(new RawStatementDefinition(sprintf(// "if (!$this->accountMap->toAccountDto($accountModel, $accountDto))" + "if (!\$this->%s()->to%s(\$%s, \$%s))", + $this->modelDataMapGenerator->getModelMapAccessorTraitMethodName($tableBlueprint), + $dtoTypeObjectTypeDefinition->getImportableName(), + $modelVariableName, + $dtoParameterDefinition->getParameterName()))))->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::error([new LogMessage(self::%s)]);", + $returnObjectTypeDefinition->getImportableName(), + $mapToFailedConstantName))); + } + + /** + * Example statement block output + * + * if (!$this->getPersonMap()->fromPersonDto($person, $personDto)) { + * return UpdateMethodResponse::error( + * [new LogMessage(static::PERSON_MAP_FROM_DTO_FAILED), new LogMessage(static::PERSON_UPDATE_FAILED)]); + * } + * + * + * @param TableBlueprint $tableBlueprint + * @param ObjectTypeDefinition $dtoTypeObjectTypeDefinition + * @param string $modelVariableName + * @param FunctionParameterDefinition $dtoParameterDefinition + * @param ObjectTypeDefinition $returnTypeObjectTypeDefinition + * @param ObjectTypeDefinition $logMessageObjectTypeDefinition + * @param ObjectTypeDefinition $modelTypeObjectTypeDefinition + * @param string $methodFailedConstantName + * + * @return StatementBlockDefinition + */ + private function getMapFromDtoStatementBlock(TableBlueprint $tableBlueprint, + ObjectTypeDefinition $dtoTypeObjectTypeDefinition, + string $modelVariableName, + FunctionParameterDefinition $dtoParameterDefinition, + ObjectTypeDefinition $returnTypeObjectTypeDefinition, + ObjectTypeDefinition $logMessageObjectTypeDefinition, + ObjectTypeDefinition $modelTypeObjectTypeDefinition, + string $methodFailedConstantName): StatementBlockDefinition + { + return (new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (!\$this->%s()->from%s(\$%s, \$%s))", + $this->modelDataMapGenerator->getModelMapAccessorTraitMethodName($tableBlueprint), + $dtoTypeObjectTypeDefinition->getImportableName(), + $modelVariableName, + $dtoParameterDefinition->getParameterName()))))->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::error([new %s(static::%s), new %s(static::%s)]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $logMessageObjectTypeDefinition->getImportableName(), + $this->getMapFromFailedConstantName($modelTypeObjectTypeDefinition), + $logMessageObjectTypeDefinition->getImportableName(), + $methodFailedConstantName))); + } + + /** + * @param string $modelVariableName + * @param ObjectTypeDefinition $returnTypeObjectTypeDefinition + * + * @return StatementBlockDefinition + */ + private function getModelNotFoundStatementBlock(string $modelVariableName, + ObjectTypeDefinition $returnTypeObjectTypeDefinition): StatementBlockDefinition + { + return (new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (!\$%s)", + $modelVariableName))))->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::notFound();", + $returnTypeObjectTypeDefinition->getImportableName()))); + } + + /** + * @param string $modelVariableName + * @param ObjectTypeDefinition $returnTypeObjectTypeDefinition + * @param ObjectTypeDefinition $logMessageObjectTypeDefinition + * @param string $methodFailedConstantName + * @param ObjectTypeDefinition $queryExceptionTypeDefinition + * @param string $exceptionVariableName + * @param StatementDefinitionCollection $catchBlockStatements + * + * @return TryBlockDefinition + */ + private function getSaveModelTryBlock(string $modelVariableName, + ObjectTypeDefinition $returnTypeObjectTypeDefinition, + ObjectTypeDefinition $logMessageObjectTypeDefinition, + string $methodFailedConstantName, + ObjectTypeDefinition $queryExceptionTypeDefinition, + string $exceptionVariableName, + StatementDefinitionCollection $catchBlockStatements): TryBlockDefinition + { + return (new TryBlockDefinition()) + // if (!$model->save() + ->addStatementDefinition((new StatementBlockDefinition(new RawStatementDefinition(sprintf("if (!\$%s->save())", + $modelVariableName))))->addStatementDefinition(new RawStatementDefinition(sprintf("return %s::error([new %s(static::%s)]);", + $returnTypeObjectTypeDefinition->getImportableName(), + $logMessageObjectTypeDefinition->getImportableName(), + $methodFailedConstantName)))) + // begin catch block + ->addCatchStatements(PhpTypeEnum::objectOfType($queryExceptionTypeDefinition->getFullyQualifiedName()), + $exceptionVariableName, + $catchBlockStatements) + ; +} }