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/composer.json b/composer.json
index 81731254..0028702e 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.3",
+ "php-libs/value-states": "^1.3"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
diff --git a/composer.lock b/composer.lock
index 6da42dcb..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": "811e4566886ac6e2a5a71c710bd3c214",
+ "content-hash": "42ab9c20c5e6de27e9fab27a0869a8ef",
"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,20 +1066,20 @@
"type": "tidelift"
}
],
- "time": "2021-02-24T17:30:44+00:00"
+ "time": "2021-05-07T10:08:30+00:00"
},
{
"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": {
@@ -1059,9 +1098,44 @@
"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-19T07:15:17+00:00"
+ },
+ {
+ "name": "php-libs/value-states",
+ "version": "1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-libs/value-state.git",
+ "reference": "d9dcc44c5826dfbd7e7350bf5b217654151bf773"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-libs/value-state/zipball/d9dcc44c5826dfbd7e7350bf5b217654151bf773",
+ "reference": "d9dcc44c5826dfbd7e7350bf5b217654151bf773",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^8.0",
+ "php-libs/observable": "^1.3"
+ },
+ "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.3"
},
- "time": "2021-05-06T20:42:12+00:00"
+ "time": "2021-05-19T07:16:58+00:00"
},
{
"name": "psr/container",
@@ -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",
diff --git a/config/reliese.php b/config/reliese.php
index 4a45859c..f7bcf0de 100644
--- a/config/reliese.php
+++ b/config/reliese.php
@@ -1,10 +1,12 @@
['information_schema', 'performance_schema', 'mysql', 'sys']],
// 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']]
],
],
/*
@@ -527,24 +529,59 @@
],
],
// 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',
+ 'Namespace' => 'App\DataAttribute\Objects',
+ 'ClassPrefix' => 'With',
+ 'ClassSuffix' => 'Trait',
+ 'ParentClassPrefix' => 'Abstract',
+ ],
+ // endregion Data Attribute Generator Config
+
// region Data Transport Generator Config
- DataTransportGeneratorConfiguration::class => [
+
+ DataTransportObjectGeneratorConfiguration::class => [
'Path' => app_path().'/DataTransportObjects',
'Namespace' => 'App\DataTransportObjects',
'ClassSuffix' => 'Dto',
'ParentClassPrefix' => 'Abstract',
+ 'UseValueStateTracking' => true,
'ObservableProperties' => [
'BeforeChange' => false,
'AfterChange' => false,
],
],
// 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::class => [
'Path' => app_path().'/DataMaps/PrimaryDatabase',
'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/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..f29f96cb 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);
}
@@ -258,7 +282,7 @@ private function analyseIndex(TableBlueprint $tableBlueprint, Index $indexDefini
$indexDefinition->getName(),
$columnBlueprints,
$indexDefinition->isPrimary(),
- false
+ $indexDefinition->isUnique()
);
}
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/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/Blueprint/IndexBlueprint.php b/src/Blueprint/IndexBlueprint.php
index 20312ef9..29ffd83e 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,14 @@ public function isUnique(): bool
{
return $this->isUnique || $this->isPrimaryKey();
}
+
+ public function getSchemaMemberType(): SchemaMemberType
+ {
+ return SchemaMemberType::Index();
+ }
+
+ public function getName(): string
+ {
+ return $this->indexName;
+ }
}
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..5e7ee474 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[]
*/
@@ -126,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
new file mode 100644
index 00000000..82658701
--- /dev/null
+++ b/src/Command/DataAccess/DataAccessGenerateCommand.php
@@ -0,0 +1,140 @@
+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);
+
+ /*
+ * Allow the $databaseAnalyser to create the Database Blueprint
+ */
+ $databaseBlueprint = $databaseAnalyser->analyseDatabase($relieseConfiguration->getDatabaseBlueprintConfiguration());
+
+ /*
+ * Generate class files
+ */
+ $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
+ */
+ 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/Command/DataAttribute/DataAttributeGenerateCommand.php b/src/Command/DataAttribute/DataAttributeGenerateCommand.php
new file mode 100644
index 00000000..9478957e
--- /dev/null
+++ b/src/Command/DataAttribute/DataAttributeGenerateCommand.php
@@ -0,0 +1,131 @@
+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);
+
+ /*
+ * Allow the $databaseAnalyser to create the Database Blueprint
+ */
+ $databaseBlueprint = $databaseAnalyser->analyseDatabase($relieseConfiguration->getDatabaseBlueprintConfiguration());
+
+ /*
+ * Generate class files
+ */
+ $dataAttributeGenerator = new DataAttributeGenerator($relieseConfiguration);
+
+ $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/Command/DataMap/ModelDataMapGenerateCommand.php b/src/Command/DataMap/ModelDataMapGenerateCommand.php
index b7808cba..b1a4b21e 100644
--- a/src/Command/DataMap/ModelDataMapGenerateCommand.php
+++ b/src/Command/DataMap/ModelDataMapGenerateCommand.php
@@ -9,8 +9,9 @@
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\DataTransport\DataTransportObjectGenerator;
use Reliese\Generator\Model\ModelGenerator;
/**
@@ -86,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
@@ -102,11 +101,7 @@ public function handle(
/*
* Create a ModelDataMapGenerator
*/
- $modelDataMapGenerator = new ModelDataMapGenerator(
- $relieseConfiguration->getModelDataMapGeneratorConfiguration(),
- new ModelGenerator($relieseConfiguration->getModelGeneratorConfiguration()),
- new DataTransportGenerator($relieseConfiguration->getDataTransportGeneratorConfiguration()),
- );
+ $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 e5e8a9e9..42e2c77a 100644
--- a/src/Command/DataTransport/DataTransportGenerateCommand.php
+++ b/src/Command/DataTransport/DataTransportGenerateCommand.php
@@ -9,7 +9,8 @@
use Reliese\Coders\Model\Factory;
use Reliese\Command\ConfigurationProfileOptionTrait;
use Reliese\Configuration\RelieseConfigurationFactory;
-use Reliese\Generator\DataTransport\DataTransportGenerator;
+use Reliese\Generator\DataAttribute\DataAttributeGenerator;
+use Reliese\Generator\DataTransport\DataTransportObjectGenerator;
/**
* Class DataTransportGenerateCommand
@@ -94,9 +95,7 @@ public function handle(
/*
* Generate class files
*/
- $dataTransportGenerator = new DataTransportGenerator(
- $relieseConfiguration->getDataTransportGeneratorConfiguration()
- );
+ $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/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/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..663212e7
--- /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/DataTransportGeneratorConfiguration.php
index 007b99b3..34aaac17 100644
--- a/src/Configuration/DataTransportGeneratorConfiguration.php
+++ b/src/Configuration/DataTransportGeneratorConfiguration.php
@@ -3,109 +3,10 @@
namespace Reliese\Configuration;
/**
- * Class DataTransportGeneratorConfiguration
+ * Class DataTransportObjectGeneratorConfiguration
*
* @deprecated Please use DataTransportObjectGeneratorConfiguration
*/
-class DataTransportGeneratorConfiguration
+class DataTransportGeneratorConfiguration extends DataTransportObjectGeneratorConfiguration
{
- /**
- * @var string
- */
- private string $classSuffix;
-
- /**
- * @var string
- */
- private string $namespace;
-
- /**
- * @var string
- */
- private string $parentClassPrefix;
-
- /**
- * @var string
- */
- private string $path;
-
- /**
- * @var bool
- */
- private bool $useBeforeChangeObservableProperties = false;
-
- /**
- * @var bool
- */
- private bool $useAfterChangeObservableProperties = false;
-
- /**
- * DataTransportGeneratorConfiguration constructor.
- *
- * @param array $configuration
- */
- public function __construct(array $configuration)
- {
- $this->path = $configuration['Path'];
- $this->namespace = $configuration['Namespace'];
- $this->classSuffix = $configuration['ClassSuffix'];
- $this->parentClassPrefix = $configuration['ParentClassPrefix'];
- if (\array_key_exists('ObservableProperties', $configuration)) {
- $observableConfig = $configuration['ObservableProperties'];
- if (\array_key_exists('BeforeChange', $observableConfig)) {
- $this->useBeforeChangeObservableProperties = $observableConfig['BeforeChange'];
- }
- if (\array_key_exists('AfterChange', $observableConfig)) {
- $this->useBeforeChangeObservableProperties = $observableConfig['AfterChange'];
- }
- }
- }
-
- /**
- * @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;
- }
-
- /**
- * @return bool
- */
- public function useAfterChangeObservableProperties(): bool
- {
- return $this->useAfterChangeObservableProperties;
- }
-
- /**
- * @return bool
- */
- public function useBeforeChangeObservableProperties(): bool
- {
- return $this->useBeforeChangeObservableProperties;
- }
-}
+}
\ No newline at end of file
diff --git a/src/Configuration/DataTransportObjectGeneratorConfiguration.php b/src/Configuration/DataTransportObjectGeneratorConfiguration.php
index 27f39613..f8c70841 100644
--- a/src/Configuration/DataTransportObjectGeneratorConfiguration.php
+++ b/src/Configuration/DataTransportObjectGeneratorConfiguration.php
@@ -3,10 +3,118 @@
namespace Reliese\Configuration;
/**
- * Class DataTransportObjectGeneratorConfiguration
- * This class was created to facilitate renaming of DataTransportGeneratorConfiguration to
- * DataTransportObjectGeneratorConfiguration
+ * Class DataTransportGeneratorConfiguration
*/
-class DataTransportObjectGeneratorConfiguration extends DataTransportGeneratorConfiguration
+class DataTransportObjectGeneratorConfiguration
{
-}
\ No newline at end of file
+ /**
+ * @var string
+ */
+ private string $classSuffix;
+
+ /**
+ * @var string
+ */
+ private string $namespace;
+
+ /**
+ * @var string
+ */
+ private string $parentClassPrefix;
+
+ /**
+ * @var string
+ */
+ private string $path;
+
+ /**
+ * DataTransportObjectGeneratorConfiguration constructor.
+ * @var bool
+ */
+ private bool $useBeforeChangeObservableProperties = false;
+
+ /**
+ * @var bool
+ */
+ private bool $useAfterChangeObservableProperties = false;
+
+ private $useValueStateTracking;
+
+ /**
+ * DataTransportGeneratorConfiguration constructor.
+ *
+ * @param array $configuration
+ */
+ 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'];
+ $this->useValueStateTracking = $configuration['UseValueStateTracking'] ?? false;
+ if (\array_key_exists('ObservableProperties', $configuration)) {
+ $observableConfig = $configuration['ObservableProperties'];
+ if (\array_key_exists('BeforeChange', $observableConfig)) {
+ $this->useBeforeChangeObservableProperties = true === $observableConfig['BeforeChange'];
+ }
+ if (\array_key_exists('AfterChange', $observableConfig)) {
+ $this->useAfterChangeObservableProperties = true === $observableConfig['AfterChange'];
+ }
+ }
+ }
+
+ /**
+ * @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;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getUseAfterChangeObservableProperties(): bool
+ {
+ return $this->useAfterChangeObservableProperties;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getUseBeforeChangeObservableProperties(): bool
+ {
+ return $this->useBeforeChangeObservableProperties;
+ }
+
+ public function getUseValueStateTracking(): bool
+ {
+ return $this->useValueStateTracking;
+ }
+}
diff --git a/src/Configuration/ModelDataMapGeneratorConfiguration.php b/src/Configuration/ModelDataMapGeneratorConfiguration.php
index fa425366..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
*/
@@ -28,17 +38,18 @@ class ModelDataMapGeneratorConfiguration
private string $path;
/**
- * DataTransportGeneratorConfiguration constructor.
+ * DataTransportObjectGeneratorConfiguration constructor.
*
* @param array $configuration
*/
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'] ?? '';
+ $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/Configuration/RelieseConfiguration.php b/src/Configuration/RelieseConfiguration.php
index 669af714..e673f465 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,29 +37,45 @@ class RelieseConfiguration
*/
private string $configurationProfileName;
+ /**
+ * @var DataAccessGeneratorConfiguration
+ */
+ private DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration;
+
+ /**
+ * @var DataAttributeGeneratorConfiguration
+ */
+ private DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration;
+
/**
* RelieseConfiguration constructor.
*
* @param string $configurationProfileName
* @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration
- * @param DataTransportGeneratorConfiguration $dataTransportGeneratorConfiguration
+ * @param DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration
+ * @param DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration
* @param DatabaseAnalyserConfiguration $databaseAnalyserConfiguration
+ * @param DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration
* @param DatabaseBlueprintConfiguration $databaseBlueprintConfiguration
* @param ModelGeneratorConfiguration $modelGeneratorConfiguration
*/
public function __construct(string $configurationProfileName,
ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration,
- DataTransportGeneratorConfiguration $dataTransportGeneratorConfiguration,
+ DataAccessGeneratorConfiguration $dataAccessGeneratorConfiguration,
+ DataTransportObjectGeneratorConfiguration $dataTransportGeneratorConfiguration,
DatabaseAnalyserConfiguration $databaseAnalyserConfiguration,
+ DataAttributeGeneratorConfiguration $dataAttributeGeneratorConfiguration,
DatabaseBlueprintConfiguration $databaseBlueprintConfiguration,
ModelGeneratorConfiguration $modelGeneratorConfiguration,)
{
$this->configurationProfileName = $configurationProfileName;
$this->modelDataMapGeneratorConfiguration = $modelDataMapGeneratorConfiguration;
+ $this->dataAccessGeneratorConfiguration = $dataAccessGeneratorConfiguration;
$this->dataTransportGeneratorConfiguration = $dataTransportGeneratorConfiguration;
$this->databaseAnalyserConfiguration = $databaseAnalyserConfiguration;
$this->databaseBlueprintConfiguration = $databaseBlueprintConfiguration;
$this->modelGeneratorConfiguration = $modelGeneratorConfiguration;
+ $this->dataAttributeGeneratorConfiguration = $dataAttributeGeneratorConfiguration;
}
/**
@@ -70,6 +86,19 @@ public function getConfigurationProfileName(): string
return $this->configurationProfileName;
}
+ public function getDataAccessGeneratorConfiguration()
+ {
+ return $this->dataAccessGeneratorConfiguration;
+ }
+
+ /**
+ * @return DataAttributeGeneratorConfiguration
+ */
+ public function getDataAttributeGeneratorConfiguration(): DataAttributeGeneratorConfiguration
+ {
+ return $this->dataAttributeGeneratorConfiguration;
+ }
+
/**
* @return ModelDataMapGeneratorConfiguration
*/
@@ -79,9 +108,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 b007d531..3323d040 100644
--- a/src/Configuration/RelieseConfigurationFactory.php
+++ b/src/Configuration/RelieseConfigurationFactory.php
@@ -2,7 +2,6 @@
namespace Reliese\Configuration;
-use Illuminate\Support\Facades\Log;
use InvalidArgumentException;
use Reliese\PackagePaths;
use function array_key_exists;
@@ -54,6 +53,11 @@ public function __construct(
$this->relieseConfigurationProfiles = $relieseConfigurationProfiles ?? include(PackagePaths::getExampleConfigFilePath());
}
+ /**
+ * @param string $configurationProfileName
+ *
+ * @return RelieseConfiguration
+ */
public function getRelieseConfiguration(string $configurationProfileName): RelieseConfiguration
{
// TODO: figure out how to make logging work w/ tests as well
@@ -67,36 +71,54 @@ public function getRelieseConfiguration(string $configurationProfileName): Relie
return new RelieseConfiguration(
$configurationProfileName,
- $this->getDataMapGeneratorConfiguration($configurationProfile),
- $this->getDataTransportGeneratorConfiguration($configurationProfile),
+ $this->getModelDataMapGeneratorConfiguration($configurationProfile),
+ $this->getDataAccessGeneratorConfiguration($configurationProfile),
+ $this->getDataTransportObjectGeneratorConfiguration($configurationProfile),
$this->getDatabaseAnalyserConfiguration($configurationProfile),
+ $this->getDataAttributeGeneratorConfiguration($configurationProfile),
$this->getDatabaseBlueprintConfiguration($configurationProfile),
$this->getModelGeneratorConfiguration($configurationProfile)
);
}
- protected function getDataMapGeneratorConfiguration(array $configurationProfile): ModelDataMapGeneratorConfiguration
+ /**
+ * @param array $configurationProfile
+ *
+ * @return DataAttributeGeneratorConfiguration
+ */
+ protected function getDataAttributeGeneratorConfiguration(array $configurationProfile): DataAttributeGeneratorConfiguration
{
- $key = ModelDataMapGeneratorConfiguration::class;
+ $key = DataAttributeGeneratorConfiguration::class;
if (!array_key_exists($key, $configurationProfile)) {
throw new InvalidArgumentException("Unable to locate configuration block for \"{$key}\"");
}
- return new ModelDataMapGeneratorConfiguration($configurationProfile[$key]);
+ return new DataAttributeGeneratorConfiguration($configurationProfile[$key]);
}
- protected function getDataTransportGeneratorConfiguration(array $configurationProfile): DataTransportGeneratorConfiguration
+ /**
+ * @param array $configurationProfile
+ *
+ * @return DataTransportObjectGeneratorConfiguration
+ */
+ protected function getDataTransportObjectGeneratorConfiguration(array $configurationProfile): DataTransportObjectGeneratorConfiguration
{
- $key = DataTransportGeneratorConfiguration::class;
+
+ $key = DataTransportObjectGeneratorConfiguration::class;
if (!array_key_exists($key, $configurationProfile)) {
throw new InvalidArgumentException("Unable to locate configuration block for \"{$key}\"");
}
- return new DataTransportGeneratorConfiguration($configurationProfile[$key]);
+ return new DataTransportObjectGeneratorConfiguration($configurationProfile[$key]);
}
+ /**
+ * @param array $configurationProfile
+ *
+ * @return DatabaseAnalyserConfiguration
+ */
protected function getDatabaseAnalyserConfiguration(array $configurationProfile): DatabaseAnalyserConfiguration
{
$key = DatabaseAnalyserConfiguration::class;
@@ -108,6 +130,11 @@ protected function getDatabaseAnalyserConfiguration(array $configurationProfile)
return new DatabaseAnalyserConfiguration($configurationProfile[$key]);
}
+ /**
+ * @param array $configurationProfile
+ *
+ * @return DatabaseBlueprintConfiguration
+ */
protected function getDatabaseBlueprintConfiguration(array $configurationProfile): DatabaseBlueprintConfiguration
{
$key = DatabaseBlueprintConfiguration::class;
@@ -119,6 +146,26 @@ protected function getDatabaseBlueprintConfiguration(array $configurationProfile
return new DatabaseBlueprintConfiguration($configurationProfile[$key]);
}
+ /**
+ * @param array $configurationProfile
+ *
+ * @return ModelDataMapGeneratorConfiguration
+ */
+ protected function getModelDataMapGeneratorConfiguration(array $configurationProfile): ModelDataMapGeneratorConfiguration
+ {
+ $key = ModelDataMapGeneratorConfiguration::class;
+ if (!array_key_exists($key, $configurationProfile)) {
+ throw new InvalidArgumentException("Unable to locate configuration block for \"$key\"");
+ }
+
+ return new ModelDataMapGeneratorConfiguration($configurationProfile[$key]);
+ }
+
+ /**
+ * @param array $configurationProfile
+ *
+ * @return ModelGeneratorConfiguration
+ */
protected function getModelGeneratorConfiguration(array $configurationProfile): ModelGeneratorConfiguration
{
$key = ModelGeneratorConfiguration::class;
@@ -129,4 +176,19 @@ protected function getModelGeneratorConfiguration(array $configurationProfile):
return new ModelGeneratorConfiguration($configurationProfile[$key]);
}
+
+ /**
+ * @param mixed $configurationProfile
+ *
+ * @return DataAccessGeneratorConfiguration
+ */
+ private function getDataAccessGeneratorConfiguration(mixed $configurationProfile): DataAccessGeneratorConfiguration
+ {
+ $key = DataAccessGeneratorConfiguration::class;
+ if (!array_key_exists($key, $configurationProfile)) {
+ throw new InvalidArgumentException("Unable to locate configuration block for \"$key\"");
+ }
+
+ return new DataAccessGeneratorConfiguration($configurationProfile[$key]);
+ }
}
diff --git a/src/Generator/DataAccess/DataAccessGenerator.php b/src/Generator/DataAccess/DataAccessGenerator.php
new file mode 100644
index 00000000..19cf2d90
--- /dev/null
+++ b/src/Generator/DataAccess/DataAccessGenerator.php
@@ -0,0 +1,783 @@
+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)
+ {
+ $classDefinition = $this->generateClassDefinition($tableBlueprint);
+ $abstractClassDefinition = $this->generateAbstractClassDefinition($tableBlueprint);
+
+ /*
+ * TODO: Add generic methods like "get by id"
+ */
+
+ /*
+ * 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());
+
+ $modelObjectTypeDefinition
+ = new ObjectTypeDefinition($this->modelGenerator->getFullyQualifiedClassName($tableBlueprint));
+
+ $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()))
+ ;
+
+ $this->addFetchByUniqueColumnMethods($tableBlueprint, $abstractClassDefinition);
+
+ $abstractClassDefinition->addMethodDefinition($this->generateCreateMethod($tableBlueprint,
+ $abstractClassDefinition));
+
+ $abstractClassDefinition->addMethodDefinition($this->generateUpdateMethod($tableBlueprint,
+ $abstractClassDefinition));
+
+ return $abstractClassDefinition;
+ }
+
+ /**
+ * @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());
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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)
+ ;
+}
+}
diff --git a/src/Generator/DataAttribute/DataAttributeGenerator.php b/src/Generator/DataAttribute/DataAttributeGenerator.php
new file mode 100644
index 00000000..75256080
--- /dev/null
+++ b/src/Generator/DataAttribute/DataAttributeGenerator.php
@@ -0,0 +1,155 @@
+dataAttributeGeneratorConfiguration = $relieseConfiguration->getDataAttributeGeneratorConfiguration();
+ /*
+ * 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) {
+
+ $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 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();
+ $namespaceParts = \explode('\\', $traitDefinition->getNamespace());
+ $traitDirectory .= '/'.\array_pop($namespaceParts);
+ 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 7f7dd0ae..cde2fe08 100644
--- a/src/Generator/DataMap/ModelDataMapGenerator.php
+++ b/src/Generator/DataMap/ModelDataMapGenerator.php
@@ -2,20 +2,33 @@
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\DataTransportObjectGeneratorConfiguration;
use Reliese\Configuration\ModelDataMapGeneratorConfiguration;
-use Reliese\Generator\DataTransport\DataTransportGenerator;
+use Reliese\Configuration\RelieseConfiguration;
+use Reliese\Generator\DataTransport\DataTransportObjectGenerator;
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\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;
@@ -27,9 +40,24 @@
class ModelDataMapGenerator
{
/**
- * @var DataTransportGenerator
+ * @var DataTransportObjectGenerator
*/
- private DataTransportGenerator $dataTransportGenerator;
+ private DataTransportObjectGenerator $dataTransportObjectGenerator;
+
+ /**
+ * @var DataTransportObjectGeneratorConfiguration
+ */
+ private DataTransportObjectGeneratorConfiguration $dataTransportObjectGeneratorConfiguration;
+
+ /**
+ * @var ClassDefinition[]
+ */
+ private array $generatedAbstractModelDataMapClassDefinitions = [];
+
+ /**
+ * @var ClassDefinition[]
+ */
+ private array $generatedModelDataMapClassDefinitions = [];
/**
* @var ModelDataMapGeneratorConfiguration
@@ -54,23 +82,19 @@ class ModelDataMapGenerator
/**
* ModelDataMapGenerator constructor.
*
- * @param ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration
- * @param ModelGenerator $modelGenerator
- * @param DataTransportGenerator $dataTransportGenerator
+ * @param RelieseConfiguration $relieseConfiguration
*/
- public function __construct(
- ModelDataMapGeneratorConfiguration $modelDataMapGeneratorConfiguration,
- ModelGenerator $modelGenerator,
- DataTransportGenerator $dataTransportGenerator
- ) {
- $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->dataTransportGenerator = $dataTransportGenerator;
+ $this->modelGenerator = new ModelGenerator($relieseConfiguration);
+ $this->dataTransportObjectGenerator = new DataTransportObjectGenerator($relieseConfiguration);
+ $this->dataTransportObjectGeneratorConfiguration = $relieseConfiguration->getDataTransportGeneratorConfiguration();
}
/**
@@ -104,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);
@@ -147,6 +171,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->dataTransportObjectGenerator->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);
@@ -165,10 +295,26 @@ 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->getValueWasInitialized(%s::%s))",
+ $dtoParameterName,
+ $dtoClassName,
+ $propertyConstant)));
+ $conditionalAssignmentBlock->addStatementDefinition($dtoPropertyAssignmentStatement);
+ $mapToDtoMethodDefinition->appendBodyStatement($conditionalAssignmentBlock);
+ } else {
+ $mapToDtoMethodDefinition->appendBodyStatement($dtoPropertyAssignmentStatement);
+ }
}
$mapToDtoMethodDefinition->appendBodyStatement(new RawStatementDefinition("return true;"));
@@ -177,9 +323,68 @@ 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);
+ }
+
+ $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);
}
+ 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
*
@@ -235,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
@@ -252,10 +462,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->getClassName() . '.php';
@@ -266,4 +476,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/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;
+ public function __construct(
+ RelieseConfiguration $relieseConfiguration
+ ) {
+ $this->dataTransportGeneratorConfiguration = $relieseConfiguration->getDataTransportGeneratorConfiguration();
/*
* TODO: inject a MySql / Postgress or other DataType mapping as needed
*/
$this->dataTypeMap = new MySqlDataTypeMap();
+ $this->dataAttributeGenerator = new DataAttributeGenerator($relieseConfiguration);
}
/**
@@ -57,17 +88,69 @@ public function __construct(DataTransportGeneratorConfiguration $dataTransportGe
*/
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();
+ }
- $dtoAbstractClassDefinition = new ClassDefinition($abstractClassName, $abstractNamespace);
+ 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)
+ );
+
+ if ($this->dataTransportGeneratorConfiguration->getUseValueStateTracking()) {
+ /*
+ * Add interface:
+ * ValueStateProviderInterface
+ * include:
+ * use WithValueStateManager;
+ * And bind the tracking in the constructor:
+ * $this->bindValueChangeStateTracking();
+ */
+ $dtoAbstractClassDefinition
+ ->addInterface(ValueStateProviderInterface::class)
+ ->addTrait(new ClassTraitDefinition(WithValueStateManager::class))
+ ->addConstructorStatement(new RawStatementDefinition("\$this->bindValueChangeStateTracking();"))
+ ;
+ }
- if ($this->dataTransportGeneratorConfiguration->useBeforeChangeObservableProperties()) {
+ if ($this->dataTransportGeneratorConfiguration->getUseBeforeChangeObservableProperties()) {
$dtoAbstractClassDefinition->addInterface(
\PhpLibs\Observable\BeforeValueChangeObservableInterface::class
);
@@ -76,7 +159,7 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint)
);
}
- if ($this->dataTransportGeneratorConfiguration->useAfterChangeObservableProperties()) {
+ if ($this->dataTransportGeneratorConfiguration->getUseAfterChangeObservableProperties()) {
$dtoAbstractClassDefinition->addInterface(
\PhpLibs\Observable\AfterValueChangeObservableInterface::class
);
@@ -84,9 +167,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) {
@@ -97,12 +177,21 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint)
$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()
);
+ /*
+ * 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()
;
@@ -110,34 +199,29 @@ public function fromTableBlueprint(TableBlueprint $tableBlueprint)
$dtoAbstractClassDefinition->addProperty($columnClassProperty);
}
- /*
- * Write the Class Files
- */
- $this->writeClassFiles($dtoClassDefinition, $dtoAbstractClassDefinition);
- }
+ foreach ($this->getForeignKeyDtoPropertyDefinitions($tableBlueprint) as $fkDtoProperty) {
+ $dtoAbstractClassDefinition->addProperty($fkDtoProperty);
+ }
- /**
- * @param TableBlueprint $tableBlueprint
- *
- * @return string
- */
- public function getFullyQualifiedClassName(TableBlueprint $tableBlueprint): string
- {
- return $this->getClassNamespace($tableBlueprint).'\\'.$this->getClassName($tableBlueprint);
+ return $dtoAbstractClassDefinition;
}
- public function getClassNamespace(TableBlueprint $tableBlueprint): string
+ public function generateDataTransportObjectClassDefinition(TableBlueprint $tableBlueprint): ClassDefinition
{
- 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
@@ -168,10 +252,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->getClassName() . '.php';
@@ -183,5 +267,178 @@ 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
+ * @return ClassPropertyDefinition[]
+ */
+ public function getForeignKeyDtoPropertyDefinitions(TableBlueprint $tableBlueprint): array
+ {
+ $results = [];
+
+ if (empty($tableBlueprint->getForeignKeyBlueprints())) {
+ return $results;
+ }
+
+ foreach ($tableBlueprint->getForeignKeyBlueprints() as $foreignKeyBlueprint) {
+ $fkDtoProperty = $this->generateForeignKeyDtoPropertyDefinition($tableBlueprint, $foreignKeyBlueprint);
+ $results[] = $fkDtoProperty;
+ }
+ 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/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 @@
-modelGeneratorConfiguration = $modelGeneratorConfiguration;
+ $this->modelGeneratorConfiguration = $relieseConfiguration->getModelGeneratorConfiguration();
/*
* TODO: inject a MySql / Postgress or other DataType mapping as needed
*/
@@ -136,6 +138,26 @@ 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()
+ );
+ }
+
+ public function getClassAsVariableName(TableBlueprint $tableBlueprint): string
+ {
+ $name = $this->getClassName($tableBlueprint);
+ return strtolower($name[0]).substr($name, 1);
+ }
+
/**
* @return string
*/
diff --git a/src/MetaCode/Definition/ClassDefinition.php b/src/MetaCode/Definition/ClassDefinition.php
index 657496d0..ab227156 100644
--- a/src/MetaCode/Definition/ClassDefinition.php
+++ b/src/MetaCode/Definition/ClassDefinition.php
@@ -2,6 +2,8 @@
namespace Reliese\MetaCode\Definition;
+use Reliese\MetaCode\Enum\AbstractEnum;
+use Reliese\MetaCode\Tool\ClassNameTool;
use RuntimeException;
/**
@@ -9,6 +11,11 @@
*/
class ClassDefinition implements ImportableInterface, CodeDefinitionInterface
{
+ /**
+ * @var AbstractEnum
+ */
+ private ?AbstractEnum $abstractEnumType;
+
/**
* @var bool[] Array keys are fully qualified interface names
*/
@@ -19,6 +26,26 @@ class ClassDefinition implements ImportableInterface, CodeDefinitionInterface
*/
private string $className;
+ /**
+ * @var string[]
+ */
+ private array $classComments = [];
+
+ /**
+ * @var ClassConstantDefinition[]
+ */
+ private array $constants = [];
+
+ /**
+ * @var ImportableInterface[]
+ */
+ private array $imports = [];
+
+ /**
+ * @var ClassMethodDefinition[]
+ */
+ private array $methods = [];
+
/**
* @var string
*/
@@ -40,9 +67,9 @@ class ClassDefinition implements ImportableInterface, CodeDefinitionInterface
private string $filePath;
/**
- * @var ImportableInterface[]
+ * @var ClassPropertyDefinition[]
*/
- private array $imports = [];
+ private array $properties = [];
/**
* @var ClassTraitDefinition[]
@@ -50,40 +77,55 @@ class ClassDefinition implements ImportableInterface, CodeDefinitionInterface
private array $traits = [];
/**
- * @var ClassConstantDefinition[]
- */
- private array $constants = [];
-
- /**
- * @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;
+ }
/**
* ClassDefinition constructor.
*
- * @param string $name
- * @param string $namespace
+ * @param string $className
+ * @param string $namespace
+ * @param ?AbstractEnum $abstractEnumType
*/
public function __construct(
- string $name,
- string $namespace
+ string $className,
+ string $namespace,
+ ?AbstractEnum $abstractEnumType = null
) {
- $this->className = $name;
+ $this->className = $className;
$this->namespace = trim($namespace, '\\');
+ $this->constructorStatementsCollection = new StatementDefinitionCollection();
+ $this->abstractEnumType = $abstractEnumType ?? AbstractEnum::concreteEnum();
}
/**
* @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;
}
/*
@@ -97,12 +139,31 @@ public function setFilePath(string $filePath): ClassDefinition
return $this;
}
+ /**
+ * @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
+ *
+ * @return $this
*/
- public function addMethodDefinition(ClassMethodDefinition $classMethodDefinition)
+ public function addMethodDefinition(ClassMethodDefinition $classMethodDefinition) : static
{
$this->methods[$classMethodDefinition->getFunctionName()] = $classMethodDefinition;
+ return $this;
}
/**
@@ -119,13 +180,27 @@ public function hasInterfaces(): bool
}
/**
- * @param string $fullyQualifiedClassName
+ * @param ClassPropertyDefinition $classPropertyDefinition
*
* @return $this
*/
- public function setParentClass(string $fullyQualifiedClassName): ClassDefinition
+ public function addProperty(ClassPropertyDefinition $classPropertyDefinition): ClassDefinition
{
- $this->parentClassName = $fullyQualifiedClassName;
+ $this->properties[$classPropertyDefinition->getVariableName()] = $classPropertyDefinition;
+
+ if ($classPropertyDefinition->getIsBeforeChangeObservable()
+ || $classPropertyDefinition->getIsAfterChangeObservable()) {
+
+ $this->addConstant(
+ new ClassConstantDefinition(
+ ClassPropertyDefinition::getPropertyNameConstantName(
+ $classPropertyDefinition->getVariableName()
+ ),
+ $classPropertyDefinition->getVariableName()
+ )
+ );
+ }
+
return $this;
}
@@ -134,15 +209,12 @@ public function setParentClass(string $fullyQualifiedClassName): ClassDefinition
*/
public function hasParentClass(): bool
{
- return !is_null($this->parentClassName);
+ return !empty($this->parentClassName);
}
- /**
- * @return string
- */
- public function getParentClassName() : string
+ public function getClassComments(): array
{
- return $this->parentClassName;
+ return $this->classComments;
}
/**
@@ -153,6 +225,12 @@ public function getClassName(): string
return $this->className;
}
+ /**
+ * @deprecated use getClassName instead
+ * @return string
+ */
+ public function getName(): string { return $this->getClassName(); }
+
/**
* @return string
*/
@@ -170,14 +248,16 @@ public function getNamespace(): string
}
/**
- * @param ClassPropertyDefinition $classPropertyDefinition
- *
- * @return $this
+ * @return ClassConstantDefinition[]
*/
- public function addProperty(ClassPropertyDefinition $classPropertyDefinition): ClassDefinition
+ public function getConstants(): array
{
- $this->properties[$classPropertyDefinition->getVariableName()] = $classPropertyDefinition;
- return $this;
+ return $this->constants;
+ }
+
+ public function getFullyQualifiedImportableName(): string
+ {
+ return trim($this->getFullyQualifiedName(), '\\');
}
/**
@@ -194,14 +274,6 @@ public function addProperties(array $classPropertyDefinitions): ClassDefinition
return $this;
}
- /**
- * @return ClassPropertyDefinition[]
- */
- public function getProperties(): array
- {
- return $this->properties;
- }
-
/**
* @param string $propertyName
*
@@ -234,18 +306,17 @@ public function getMethods(): array
return $this->methods;
}
- public function addConstant(ClassConstantDefinition $constant): static
+ public function getParentClassName(): string
{
- $this->constants[$constant->getName()] = $constant;
- return $this;
+ return $this->parentClassName;
}
/**
- * @return ClassConstantDefinition[]
+ * @return ClassPropertyDefinition[]
*/
- public function getConstants(): array
+ public function getProperties(): array
{
- return $this->constants;
+ return $this->properties;
}
/**
@@ -273,6 +344,14 @@ public function addTraits(array $traitDefinitions): static
return $this;
}
+ /**
+ * @return string
+ */
+ public function getStructureType(): string
+ {
+ return 'class';
+ }
+
/**
* @return ClassTraitDefinition[]
*/
@@ -297,19 +376,9 @@ public function hasTrait(string $fullyQualifiedTraitName): bool
return false;
}
- /**
- * @param ImportableInterface $import
- *
- * @return $this
- */
- public function addImport(ImportableInterface $import): static
+ public function setParentClass(string $fullyQualifiedClassName): ClassDefinition
{
- // 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;
+ $this->parentClassName = $fullyQualifiedClassName;
return $this;
}
@@ -351,6 +420,20 @@ public function addConstants(array $constants): static
return $this;
}
+ private StatementDefinitionCollection $constructorStatementsCollection;
+
+ public function getConstructorStatementsCollection(): StatementDefinitionCollection
+ {
+ return $this->constructorStatementsCollection;
+ }
+
+ public function addConstructorStatement(StatementDefinitionInterface $statementDefinition): static
+ {
+ $this->getConstructorStatementsCollection()
+ ->addStatementDefinition($statementDefinition);
+ return $this;
+ }
+
/**
* @todo: Put this on a helper class
*
@@ -372,14 +455,6 @@ public function getImports(): array
return $this->imports;
}
- /**
- * @return string
- */
- public function getFullyQualifiedImportableName(): string
- {
- return trim($this->getFullyQualifiedName(), '\\');
- }
-
/**
* @return string
*/
@@ -414,4 +489,12 @@ public function getFilePath(): string
{
return $this->filePath;
}
+
+ /**
+ * @return AbstractEnum
+ */
+ public function getAbstractEnumType(): AbstractEnum
+ {
+ return $this->abstractEnumType;
+ }
}
diff --git a/src/MetaCode/Definition/ClassPropertyDefinition.php b/src/MetaCode/Definition/ClassPropertyDefinition.php
index 79bc2d39..1d123a01 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,11 +18,21 @@ class ClassPropertyDefinition
*/
private ?InstanceEnum $getterInstanceEnum = null;
+ /**
+ * @var StatementDefinitionInterface|null
+ */
+ private ?StatementDefinitionInterface $getterMethodBody;
+
/**
* @var VisibilityEnum|null
*/
private ?VisibilityEnum $getterVisibilityEnum = null;
+ /**
+ * @var StatementDefinitionInterface[]
+ */
+ private array $additionalSetterOperations = [];
+
/**
* @var InstanceEnum|null
*/
@@ -134,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(),
@@ -145,20 +159,30 @@ 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",
- $this->getVariableName(),
+ if ($this->getIsBeforeChangeObservable() ) {
+ $setter->appendBodyStatement(
+ new RawStatementDefinition(
+ \sprintf(
+ "\$this->raiseBeforeValueChange(static::%s, \$this->%s, \$%s);\n",
+ ClassPropertyDefinition::getPropertyNameConstantName($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(),
+ $setter->appendBodyStatement(new RawStatementDefinition(\sprintf("\$this->raiseAfterValueChange(static::%s, \$this->%s);\n",
+ ClassPropertyDefinition::getPropertyNameConstantName($this->getVariableName()),
$this->getVariableName())));
}
@@ -230,16 +254,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;
}
@@ -289,4 +317,48 @@ public function setValue(mixed $value): static
return $this;
}
+ /**
+ * @param StatementDefinitionInterface $statementDefinition
+ *
+ * @return $this
+ */
+ public function addAdditionalSetterOperation(StatementDefinitionInterface $statementDefinition): static
+ {
+ $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;
+ }
+
+ public static function getPropertyNameConstantName(string $propertyName): string
+ {
+ return ClassNameTool::identifierNameToConstantName($propertyName)."_PROPERTY";
+ }
}
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/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
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..883ee6ea
--- /dev/null
+++ b/src/MetaCode/Definition/StatementBlockDefinition.php
@@ -0,0 +1,82 @@
+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
+ */
+ 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,
+ $this->statementDefinitionCollection->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..66005d2e
--- /dev/null
+++ b/src/MetaCode/Definition/StatementDefinitionCollection.php
@@ -0,0 +1,43 @@
+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);
+ }
+
+ public function hasStatements(): bool
+ {
+ return !empty($this->statementDefinitions);
+ }
+}
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 @@
+toDeclarationType()),
+ $exceptionVariableName
+ )
+ );
+
+ $this->setBlockSuffixStatement(
+ (new StatementBlockDefinition(
+ $catchStatement,
+ $catchStatementDefinitionCollection
+ ))
+ );
+
+ return $this;
+ }
+}
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';
diff --git a/src/MetaCode/Enum/PhpTypeEnum.php b/src/MetaCode/Enum/PhpTypeEnum.php
index 5b9826d3..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;
@@ -73,12 +80,25 @@ class PhpTypeEnum
*/
private bool $isNullable = false;
- private function __construct($phpTypeId, $isNullable = false)
+ private function __construct($phpTypeId, $isNullable)
{
$this->phpTypeId = $phpTypeId;
$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;
@@ -195,7 +215,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 +231,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 +239,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 +247,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 +255,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 +263,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 +271,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 +279,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 +288,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 +298,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 +307,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 +315,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 +323,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
@@ -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.");
}
@@ -437,6 +465,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 3cc2b907..c287b247 100644
--- a/src/MetaCode/Format/ClassFormatter.php
+++ b/src/MetaCode/Format/ClassFormatter.php
@@ -16,8 +16,13 @@
/**
* Class ClassFormatter
*/
-class ClassFormatter
+class ClassFormatter implements IndentationProviderInterface
{
+ /**
+ * @param ClassDefinition $classDefinition
+ *
+ * @return string
+ */
public function format(ClassDefinition $classDefinition): string
{
$depth = 0;
@@ -32,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[] = "getClassName() . "\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->getClassName();
+ $lines[] = $classDefinition->getAbstractEnumType()->toReservedWord(true)
+ . Str::lower($classDefinition->getStructureType())
+ . ' '
+ . $classDefinition->getClassName();
if (!empty($parent)) {
$lines[] = ' extends ' . $parent;
@@ -73,7 +85,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);
}
@@ -81,7 +93,7 @@ private function getIndentation(int $depth): string
/**
* @return string
*/
- private function getIndentationSymbol(): string
+ public function getIndentationSymbol(): string
{
return ' ';
}
@@ -99,7 +111,9 @@ private function prepareGettersAndSetters(ClassDefinition $classDefinition): voi
);
}
if ($property->hasGetter()) {
- $this->appendGetter($property, $classDefinition);
+ $classDefinition->addMethodDefinition(
+ $property->getGetterMethodDefinition($classDefinition)
+ );
}
}
}
@@ -198,19 +212,21 @@ private function formatProperties(ClassDefinition $classDefinition, int $depth):
private function formatProperty(ClassDefinition $classDefinition, ClassPropertyDefinition $property, int $depth): string
{
- $statement = $this->getIndentation($depth)
- . $property->getVisibilityEnum()->toReservedWord()
- . ' '
- . $this->shortenTypeHint($classDefinition, $property->getPhpTypeEnum())
- . ' $'
- . $property->getVariableName()
- ;
-
+ $defaultValueString = '';
if ($property->hasValue()) {
- $statement .= ' = ' . var_export($property->getValue(), true);
+ $defaultValueString = ' = '. var_export($property->getValue(), true);
+ } elseif ($property->getPhpTypeEnum()->isNullable()) {
+ $defaultValueString = ' = null';
}
- return $statement . ';';
+ return $this->getIndentation($depth)
+ . $property->getVisibilityEnum()->toReservedWord()
+ . ' '
+ . $this->shortenTypeHint($classDefinition, $property->getPhpTypeEnum())
+ . ' $'
+ . $property->getVariableName()
+ . $defaultValueString
+ . ';';
}
/**
@@ -238,19 +254,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
@@ -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 = [];
@@ -291,16 +294,23 @@ private function formatMethod(ClassDefinition $classDefinition, ClassMethodDefin
$signature .= implode(', ', $parameters);
- $signature .= '): ';
- $signature .= $this->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());
+ }
+ if ($method->getAbstractEnum()->isAbstract()) {
+ return $signature . ";\n";
+ }
$signature .= "\n";
$signature .= $this->getIndentation($depth) . "{\n";
$blockDepth = $depth + 1;
foreach ($method->getBlockStatements() as $statement) {
- $signature .= $this->getIndentation($blockDepth)
- . $statement->toPhpCode()
+ $signature .= $statement->toPhpCode($this, $blockDepth)
. "\n";
}
@@ -357,4 +367,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/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 @@
+ ['information_schema', 'performance_schema', 'mysql', 'sys']],
// 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']]
],
],
/*
@@ -126,7 +128,7 @@
|
*/
- 'Path' => $appRoot.'Models',
+ 'Path' => $appRoot.'/Models',
/*
|--------------------------------------------------------------------------
@@ -527,18 +529,50 @@
],
],
// endregion Model Generator Config
+
+ // region Data Access Generator Config
+ DataAccessGeneratorConfiguration::class => [
+ 'Path' => $appRoot.'/DataAccess/PrimaryDatabase',
+ 'Namespace' => 'app\DataAccess\PrimaryDatabase',
+ //'ClassPrefix' => '',
+ 'ClassSuffix' => 'DataAccess',
+ 'ParentClassPrefix' => 'Abstract',
+ ],
+ // endregion Data Access Generator Config
+
+ // region Data Attribute Generator Config
+ DataAttributeGeneratorConfiguration::class => [
+ 'Path' => $appRoot.'/DataAttribute/PrimaryDatabase',
+ 'Namespace' => 'App\DataAttribute\Objects',
+ 'ClassPrefix' => 'With',
+ 'ClassSuffix' => 'Trait',
+ 'ParentClassPrefix' => 'Abstract',
+ ],
+ // endregion Data Attribute Generator Config
+
// region Data Transport Generator Config
- DataTransportGeneratorConfiguration::class => [
+ DataTransportObjectGeneratorConfiguration::class => [
'Path' => $appRoot.'/DataTransportObjects',
'Namespace' => 'App\DataTransportObjects',
'ClassSuffix' => 'Dto',
'ParentClassPrefix' => 'Abstract',
+ 'UseValueStateTracking' => true,
'ObservableProperties' => [
'BeforeChange' => false,
'AfterChange' => false,
],
],
// endregion Data Transport Generator Config
+
+ // region Data Transport Collection Generator Config
+ DataTransportCollectionGeneratorConfiguration::class => [
+ 'Path' => $appRoot.'/DataTransport/Collections',
+ 'Namespace' => 'App\DataTransport\Collections',
+ 'ClassSuffix' => 'Dto',
+ 'ParentClassPrefix' => 'Abstract',
+ ],
+ // endregion Data Transport Collection Generator Config
+
// region Data Map Generator Config
ModelDataMapGeneratorConfiguration::class => [
'Path' => $appRoot.'/DataMaps/PrimaryDatabase',
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 "([^"]*)"$/
*/
diff --git a/tests/MetaCode/Format/ClassFormatterTest.php b/tests/MetaCode/Format/ClassFormatterTest.php
index 9189a467..eacb37fb 100644
--- a/tests/MetaCode/Format/ClassFormatterTest.php
+++ b/tests/MetaCode/Format/ClassFormatterTest.php
@@ -356,7 +356,7 @@ public function it_formats_a_class_with_one_property_of_type_nullable_global_obj
*/
class OneClass
{
- private ?DateTime \$aProperty;
+ private ?DateTime \$aProperty = null;
}
PHP;
@@ -393,8 +393,8 @@ public function it_formats_a_class_with_two_properties_of_type_nullable_global_o
*/
class OneClass
{
- private ?DateTime \$aProperty;
- private ?DateTime \$anotherProperty;
+ private ?DateTime \$aProperty = null;
+ private ?DateTime \$anotherProperty = null;
}
PHP;
@@ -431,7 +431,7 @@ public function it_formats_a_class_with_one_nullable_property()
*/
class OneClass
{
- private ?string \$aProperty;
+ private ?string \$aProperty = null;
}
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");
}
}