From 2de3139c802b64d16ccbce3d4f522673864c58e7 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Mon, 27 May 2024 18:09:22 +0000 Subject: [PATCH 1/5] - Added description to most attributes --- src/Attribute/Obj/Table.php | 1 + src/Attribute/Property/Field.php | 1 + src/Attribute/Property/Field/Bigint.php | 1 + src/Attribute/Property/Field/Bit.php | 1 + src/Attribute/Property/Field/Blob.php | 1 + src/Attribute/Property/Field/CreatedAt.php | 1 + src/Attribute/Property/Field/Date.php | 1 + src/Attribute/Property/Field/Datetime.php | 1 + src/Attribute/Property/Field/Decimal.php | 1 + src/Attribute/Property/Field/Float.php | 1 + src/Attribute/Property/Field/ForeignKey.php | 1 + src/Attribute/Property/Field/Id.php | 1 + src/Attribute/Property/Field/Longblob.php | 1 + src/Attribute/Property/Field/Longtext.php | 1 + src/Attribute/Property/Field/Mediumblob.php | 1 + src/Attribute/Property/Field/Mediumint.php | 1 + src/Attribute/Property/Field/Mediumtext.php | 1 + src/Attribute/Property/Field/Numeric.php | 1 + src/Attribute/Property/Field/PrimaryKey.php | 1 + src/Attribute/Property/Field/Smallint.php | 1 + src/Attribute/Property/Field/Text.php | 1 + src/Attribute/Property/Field/Time.php | 13 +++++++++---- src/Attribute/Property/Field/Timestamp.php | 13 +++++++++---- src/Attribute/Property/Field/Tinyblob.php | 1 + src/Attribute/Property/Field/Tinyint.php | 1 + src/Attribute/Property/Field/Tinytext.php | 1 + src/Attribute/Property/Field/UpdatedAt.php | 1 + src/SearchRequest/Attribute/SearchGroupBy.php | 1 + src/SearchRequest/Attribute/SearchLike.php | 1 + src/SearchRequest/Attribute/SearchOrderBy.php | 1 + .../Attribute/SearchRequestParameter.php | 1 + src/SearchRequest/Attribute/SearchWhere.php | 1 + 32 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/Attribute/Obj/Table.php b/src/Attribute/Obj/Table.php index 0f5fc26..8a2039e 100644 --- a/src/Attribute/Obj/Table.php +++ b/src/Attribute/Obj/Table.php @@ -10,6 +10,7 @@ class Table implements AdapterAttributeInterface { public ? string $schema = null, public ? string $adapter = null, public ? string $engine = null, + public string $description = "", ) {} public function adapter() : false|string diff --git a/src/Attribute/Property/Field.php b/src/Attribute/Property/Field.php index 187f63b..a9147ef 100644 --- a/src/Attribute/Property/Field.php +++ b/src/Attribute/Property/Field.php @@ -14,5 +14,6 @@ class Field { public mixed $default = null, public bool $readonly = false, public null|int $decimal = null, + public string $description = "", ) {} } diff --git a/src/Attribute/Property/Field/Bigint.php b/src/Attribute/Property/Field/Bigint.php index 8b81688..65eadac 100644 --- a/src/Attribute/Property/Field/Bigint.php +++ b/src/Attribute/Property/Field/Bigint.php @@ -14,5 +14,6 @@ class Bigint extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Bit.php b/src/Attribute/Property/Field/Bit.php index 3fb35c6..7a8db05 100644 --- a/src/Attribute/Property/Field/Bit.php +++ b/src/Attribute/Property/Field/Bit.php @@ -14,5 +14,6 @@ class Bit extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Blob.php b/src/Attribute/Property/Field/Blob.php index 2323310..6a3fb9c 100644 --- a/src/Attribute/Property/Field/Blob.php +++ b/src/Attribute/Property/Field/Blob.php @@ -14,5 +14,6 @@ class Blob extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/CreatedAt.php b/src/Attribute/Property/Field/CreatedAt.php index 642c35b..7ae2844 100644 --- a/src/Attribute/Property/Field/CreatedAt.php +++ b/src/Attribute/Property/Field/CreatedAt.php @@ -13,5 +13,6 @@ class CreatedAt extends \Ulmus\Attribute\Property\Field { public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } diff --git a/src/Attribute/Property/Field/Date.php b/src/Attribute/Property/Field/Date.php index aea7a75..27b9546 100644 --- a/src/Attribute/Property/Field/Date.php +++ b/src/Attribute/Property/Field/Date.php @@ -11,5 +11,6 @@ class Date extends \Ulmus\Attribute\Property\Field { public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } diff --git a/src/Attribute/Property/Field/Datetime.php b/src/Attribute/Property/Field/Datetime.php index ddf7546..f633071 100644 --- a/src/Attribute/Property/Field/Datetime.php +++ b/src/Attribute/Property/Field/Datetime.php @@ -11,5 +11,6 @@ class Datetime extends \Ulmus\Attribute\Property\Field { public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } diff --git a/src/Attribute/Property/Field/Decimal.php b/src/Attribute/Property/Field/Decimal.php index 70e4945..905ad75 100644 --- a/src/Attribute/Property/Field/Decimal.php +++ b/src/Attribute/Property/Field/Decimal.php @@ -14,5 +14,6 @@ class Decimal extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Float.php b/src/Attribute/Property/Field/Float.php index 55a787d..ca27758 100644 --- a/src/Attribute/Property/Field/Float.php +++ b/src/Attribute/Property/Field/Float.php @@ -14,5 +14,6 @@ class Float extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/ForeignKey.php b/src/Attribute/Property/Field/ForeignKey.php index 0c5deeb..c4aad5a 100644 --- a/src/Attribute/Property/Field/ForeignKey.php +++ b/src/Attribute/Property/Field/ForeignKey.php @@ -26,6 +26,7 @@ class ForeignKey extends PrimaryKey { public null|string $relation = null, public ConstrainActionEnum $onDelete = ConstrainActionEnum::NoAction, public ConstrainActionEnum $onUpdate = ConstrainActionEnum::NoAction, + public string $description = "", ) { #$this->references = Attribute::handleArrayField($this->references, false); } diff --git a/src/Attribute/Property/Field/Id.php b/src/Attribute/Property/Field/Id.php index 7ab5bdd..df4f0b9 100644 --- a/src/Attribute/Property/Field/Id.php +++ b/src/Attribute/Property/Field/Id.php @@ -17,5 +17,6 @@ class Id extends \Ulmus\Attribute\Property\Field { public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } diff --git a/src/Attribute/Property/Field/Longblob.php b/src/Attribute/Property/Field/Longblob.php index 6eb340d..26d6da1 100644 --- a/src/Attribute/Property/Field/Longblob.php +++ b/src/Attribute/Property/Field/Longblob.php @@ -14,5 +14,6 @@ class Longblob extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Longtext.php b/src/Attribute/Property/Field/Longtext.php index a78ac82..7ac43e9 100644 --- a/src/Attribute/Property/Field/Longtext.php +++ b/src/Attribute/Property/Field/Longtext.php @@ -14,5 +14,6 @@ class Longtext extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Mediumblob.php b/src/Attribute/Property/Field/Mediumblob.php index c9d272e..a48b1f7 100644 --- a/src/Attribute/Property/Field/Mediumblob.php +++ b/src/Attribute/Property/Field/Mediumblob.php @@ -14,5 +14,6 @@ class Mediumblob extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Mediumint.php b/src/Attribute/Property/Field/Mediumint.php index ad9560d..fb02084 100644 --- a/src/Attribute/Property/Field/Mediumint.php +++ b/src/Attribute/Property/Field/Mediumint.php @@ -14,5 +14,6 @@ class Mediumint extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Mediumtext.php b/src/Attribute/Property/Field/Mediumtext.php index 0511404..d8936c5 100644 --- a/src/Attribute/Property/Field/Mediumtext.php +++ b/src/Attribute/Property/Field/Mediumtext.php @@ -14,5 +14,6 @@ class Mediumtext extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Numeric.php b/src/Attribute/Property/Field/Numeric.php index c428f4f..935d928 100644 --- a/src/Attribute/Property/Field/Numeric.php +++ b/src/Attribute/Property/Field/Numeric.php @@ -14,5 +14,6 @@ class Numeric extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/PrimaryKey.php b/src/Attribute/Property/Field/PrimaryKey.php index c63f36c..c9c0474 100644 --- a/src/Attribute/Property/Field/PrimaryKey.php +++ b/src/Attribute/Property/Field/PrimaryKey.php @@ -16,5 +16,6 @@ class PrimaryKey extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } diff --git a/src/Attribute/Property/Field/Smallint.php b/src/Attribute/Property/Field/Smallint.php index a17f08e..2af62e9 100644 --- a/src/Attribute/Property/Field/Smallint.php +++ b/src/Attribute/Property/Field/Smallint.php @@ -14,5 +14,6 @@ class Smallint extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Text.php b/src/Attribute/Property/Field/Text.php index 1e40434..44cad65 100644 --- a/src/Attribute/Property/Field/Text.php +++ b/src/Attribute/Property/Field/Text.php @@ -14,5 +14,6 @@ class Text extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Time.php b/src/Attribute/Property/Field/Time.php index 3ad821a..00199e5 100644 --- a/src/Attribute/Property/Field/Time.php +++ b/src/Attribute/Property/Field/Time.php @@ -5,8 +5,13 @@ namespace Ulmus\Attribute\Property\Field; #[\Attribute(\Attribute::TARGET_PROPERTY)] class Time extends \Ulmus\Attribute\Property\Field { - public function __construct(? string $type = "time", ? int $length = null) - { - parent::__construct($type, $length); - } + public function __construct( + public ? string $name = null, + public ? string $type = "time", + public array $attributes = [], + public bool $nullable = false, + public mixed $default = null, + public bool $readonly = false, + public string $description = "", + ) {} } diff --git a/src/Attribute/Property/Field/Timestamp.php b/src/Attribute/Property/Field/Timestamp.php index 5436053..0ffa893 100644 --- a/src/Attribute/Property/Field/Timestamp.php +++ b/src/Attribute/Property/Field/Timestamp.php @@ -5,8 +5,13 @@ namespace Ulmus\Attribute\Property\Field; #[\Attribute(\Attribute::TARGET_PROPERTY)] class Timestamp extends \Ulmus\Attribute\Property\Field { - public function __construct(? string $type = "timestamp", ? int $length = null) - { - parent::__construct($type, $length); - } + public function __construct( + public ? string $name = null, + public ? string $type = "timestamp", + public array $attributes = [], + public bool $nullable = false, + public mixed $default = null, + public bool $readonly = false, + public string $description = "", + ) {} } diff --git a/src/Attribute/Property/Field/Tinyblob.php b/src/Attribute/Property/Field/Tinyblob.php index 0ee0190..156a9a5 100644 --- a/src/Attribute/Property/Field/Tinyblob.php +++ b/src/Attribute/Property/Field/Tinyblob.php @@ -14,5 +14,6 @@ class Blob extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Tinyint.php b/src/Attribute/Property/Field/Tinyint.php index dd59fa6..3528b5d 100644 --- a/src/Attribute/Property/Field/Tinyint.php +++ b/src/Attribute/Property/Field/Tinyint.php @@ -14,5 +14,6 @@ class Tinyint extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/Tinytext.php b/src/Attribute/Property/Field/Tinytext.php index 3f78b72..5fb8e6b 100644 --- a/src/Attribute/Property/Field/Tinytext.php +++ b/src/Attribute/Property/Field/Tinytext.php @@ -14,5 +14,6 @@ class Tinytext extends \Ulmus\Attribute\Property\Field public bool $nullable = false, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/Attribute/Property/Field/UpdatedAt.php b/src/Attribute/Property/Field/UpdatedAt.php index 5252d76..6c39f9e 100644 --- a/src/Attribute/Property/Field/UpdatedAt.php +++ b/src/Attribute/Property/Field/UpdatedAt.php @@ -15,5 +15,6 @@ class UpdatedAt extends \Ulmus\Attribute\Property\Field public bool $nullable = true, public mixed $default = null, public bool $readonly = false, + public string $description = "", ) {} } diff --git a/src/SearchRequest/Attribute/SearchGroupBy.php b/src/SearchRequest/Attribute/SearchGroupBy.php index 162022b..0c53b8b 100644 --- a/src/SearchRequest/Attribute/SearchGroupBy.php +++ b/src/SearchRequest/Attribute/SearchGroupBy.php @@ -9,5 +9,6 @@ class SearchGroupBy extends SearchParameter { public function __construct( public null|string|\Stringable|array $field = null, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/SearchRequest/Attribute/SearchLike.php b/src/SearchRequest/Attribute/SearchLike.php index e4a25c4..9424965 100644 --- a/src/SearchRequest/Attribute/SearchLike.php +++ b/src/SearchRequest/Attribute/SearchLike.php @@ -12,5 +12,6 @@ class SearchLike extends SearchParameter public null|string|\Stringable|array $field = null, public bool $toggle = false, public SearchMethodEnum $method = SearchMethodEnum::Like, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/SearchRequest/Attribute/SearchOrderBy.php b/src/SearchRequest/Attribute/SearchOrderBy.php index 96c3e02..171eba5 100644 --- a/src/SearchRequest/Attribute/SearchOrderBy.php +++ b/src/SearchRequest/Attribute/SearchOrderBy.php @@ -15,5 +15,6 @@ class SearchOrderBy extends SearchParameter public ? string $parameter = null, public null|string|\Stringable|array $field = null, public null|SearchMethodEnum $order = null, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/SearchRequest/Attribute/SearchRequestParameter.php b/src/SearchRequest/Attribute/SearchRequestParameter.php index fa430ee..7e87191 100644 --- a/src/SearchRequest/Attribute/SearchRequestParameter.php +++ b/src/SearchRequest/Attribute/SearchRequestParameter.php @@ -10,5 +10,6 @@ class SearchRequestParameter public function __construct( public string $class, public ? string $alias = null, + public string $description = "", ) {} } \ No newline at end of file diff --git a/src/SearchRequest/Attribute/SearchWhere.php b/src/SearchRequest/Attribute/SearchWhere.php index 959672c..a777c11 100644 --- a/src/SearchRequest/Attribute/SearchWhere.php +++ b/src/SearchRequest/Attribute/SearchWhere.php @@ -12,5 +12,6 @@ class SearchWhere extends SearchParameter public null|string|\Stringable|array $field = null, public bool $toggle = false, public SearchMethodEnum $method = SearchMethodEnum::Where, + public string $description = "", ) {} } \ No newline at end of file From f3be11a59021f22c761bcac9fad1b026f78ba0a4 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Tue, 28 May 2024 08:59:12 -0400 Subject: [PATCH 2/5] - WIP on notes 2.x --- src/Annotation/Classes/Collation.php | 7 - src/Annotation/Classes/Method.php | 7 - src/Annotation/Classes/Table.php | 27 --- src/Annotation/Property/Field.php | 33 --- src/Annotation/Property/Field/Bigint.php | 11 - src/Annotation/Property/Field/Blob.php | 11 - src/Annotation/Property/Field/CreatedAt.php | 13 -- src/Annotation/Property/Field/Date.php | 11 - src/Annotation/Property/Field/Datetime.php | 11 - src/Annotation/Property/Field/ForeignKey.php | 20 -- src/Annotation/Property/Field/Id.php | 15 -- src/Annotation/Property/Field/Longblob.php | 11 - src/Annotation/Property/Field/Longtext.php | 11 - src/Annotation/Property/Field/Mediumblob.php | 11 - src/Annotation/Property/Field/Mediumtext.php | 11 - src/Annotation/Property/Field/PrimaryKey.php | 15 -- src/Annotation/Property/Field/Text.php | 11 - src/Annotation/Property/Field/Time.php | 11 - src/Annotation/Property/Field/Tinyblob.php | 11 - src/Annotation/Property/Field/Tinyint.php | 11 - src/Annotation/Property/Field/UpdatedAt.php | 14 -- src/Annotation/Property/Filter.php | 15 -- src/Annotation/Property/FilterJoin.php | 15 -- src/Annotation/Property/GroupBy.php | 15 -- src/Annotation/Property/Having.php | 5 - src/Annotation/Property/Join.php | 31 --- src/Annotation/Property/On.php | 5 - src/Annotation/Property/OrWhere.php | 14 -- src/Annotation/Property/OrderBy.php | 21 -- src/Annotation/Property/Relation.php | 88 -------- src/Annotation/Property/Relation/Ignore.php | 5 - src/Annotation/Property/Virtual.php | 19 -- src/Annotation/Property/Where.php | 30 --- src/Annotation/Property/WithJoin.php | 15 -- src/Attribute/Property/Join.php | 2 +- src/Attribute/Property/Relation.php | 2 +- .../Property/ResettablePropertyInterface.php | 8 + src/Attribute/Property/Virtual.php | 2 +- src/Common/EntityResolver.php | 88 ++------ src/Entity/DatasetHandler.php | 153 +++++++++++++ src/EntityTrait.php | 213 +++++------------- src/Repository/RelationBuilder.php | 61 +++-- 42 files changed, 270 insertions(+), 820 deletions(-) delete mode 100644 src/Annotation/Classes/Collation.php delete mode 100644 src/Annotation/Classes/Method.php delete mode 100644 src/Annotation/Classes/Table.php delete mode 100644 src/Annotation/Property/Field.php delete mode 100644 src/Annotation/Property/Field/Bigint.php delete mode 100644 src/Annotation/Property/Field/Blob.php delete mode 100644 src/Annotation/Property/Field/CreatedAt.php delete mode 100644 src/Annotation/Property/Field/Date.php delete mode 100644 src/Annotation/Property/Field/Datetime.php delete mode 100644 src/Annotation/Property/Field/ForeignKey.php delete mode 100644 src/Annotation/Property/Field/Id.php delete mode 100644 src/Annotation/Property/Field/Longblob.php delete mode 100644 src/Annotation/Property/Field/Longtext.php delete mode 100644 src/Annotation/Property/Field/Mediumblob.php delete mode 100644 src/Annotation/Property/Field/Mediumtext.php delete mode 100644 src/Annotation/Property/Field/PrimaryKey.php delete mode 100644 src/Annotation/Property/Field/Text.php delete mode 100644 src/Annotation/Property/Field/Time.php delete mode 100644 src/Annotation/Property/Field/Tinyblob.php delete mode 100644 src/Annotation/Property/Field/Tinyint.php delete mode 100644 src/Annotation/Property/Field/UpdatedAt.php delete mode 100644 src/Annotation/Property/Filter.php delete mode 100644 src/Annotation/Property/FilterJoin.php delete mode 100644 src/Annotation/Property/GroupBy.php delete mode 100644 src/Annotation/Property/Having.php delete mode 100644 src/Annotation/Property/Join.php delete mode 100644 src/Annotation/Property/On.php delete mode 100644 src/Annotation/Property/OrWhere.php delete mode 100644 src/Annotation/Property/OrderBy.php delete mode 100644 src/Annotation/Property/Relation.php delete mode 100644 src/Annotation/Property/Relation/Ignore.php delete mode 100644 src/Annotation/Property/Virtual.php delete mode 100644 src/Annotation/Property/Where.php delete mode 100644 src/Annotation/Property/WithJoin.php create mode 100644 src/Attribute/Property/ResettablePropertyInterface.php create mode 100644 src/Entity/DatasetHandler.php diff --git a/src/Annotation/Classes/Collation.php b/src/Annotation/Classes/Collation.php deleted file mode 100644 index acb3fb4..0000000 --- a/src/Annotation/Classes/Collation.php +++ /dev/null @@ -1,7 +0,0 @@ -name = $name; - } - - if ( $engine !== null ) { - $this->engine = $engine; - } - } -} diff --git a/src/Annotation/Property/Field.php b/src/Annotation/Property/Field.php deleted file mode 100644 index 7b8dea0..0000000 --- a/src/Annotation/Property/Field.php +++ /dev/null @@ -1,33 +0,0 @@ -type = $type; - } - - if ( $length !== null ) { - $this->length = $length; - } - } -} diff --git a/src/Annotation/Property/Field/Bigint.php b/src/Annotation/Property/Field/Bigint.php deleted file mode 100644 index 01b49ac..0000000 --- a/src/Annotation/Property/Field/Bigint.php +++ /dev/null @@ -1,11 +0,0 @@ -nullable = false; - $this->type = "timestamp"; - $this->attributes['default'] = "CURRENT_TIMESTAMP"; - } -} diff --git a/src/Annotation/Property/Field/Date.php b/src/Annotation/Property/Field/Date.php deleted file mode 100644 index 2bbf061..0000000 --- a/src/Annotation/Property/Field/Date.php +++ /dev/null @@ -1,11 +0,0 @@ -nullable); - $this->attributes['primary_key'] = false; - $this->attributes['auto_increment'] = false; - } - -} diff --git a/src/Annotation/Property/Field/Id.php b/src/Annotation/Property/Field/Id.php deleted file mode 100644 index 5824909..0000000 --- a/src/Annotation/Property/Field/Id.php +++ /dev/null @@ -1,15 +0,0 @@ -attributes['unsigned'] = true; - $this->attributes['auto_increment'] = true; - - parent::__construct('bigint'); - } - -} diff --git a/src/Annotation/Property/Field/Longblob.php b/src/Annotation/Property/Field/Longblob.php deleted file mode 100644 index ef29876..0000000 --- a/src/Annotation/Property/Field/Longblob.php +++ /dev/null @@ -1,11 +0,0 @@ -nullable = false; - $this->attributes['primary_key'] = true; - - parent::__construct($type, $length); - } - -} diff --git a/src/Annotation/Property/Field/Text.php b/src/Annotation/Property/Field/Text.php deleted file mode 100644 index fb7843f..0000000 --- a/src/Annotation/Property/Field/Text.php +++ /dev/null @@ -1,11 +0,0 @@ -nullable = true; - $this->type = "timestamp"; - $this->attributes['update'] = "CURRENT_TIMESTAMP"; - $this->attributes['default'] = null; - } -} diff --git a/src/Annotation/Property/Filter.php b/src/Annotation/Property/Filter.php deleted file mode 100644 index ee8c048..0000000 --- a/src/Annotation/Property/Filter.php +++ /dev/null @@ -1,15 +0,0 @@ -method = $method; - } - } -} \ No newline at end of file diff --git a/src/Annotation/Property/FilterJoin.php b/src/Annotation/Property/FilterJoin.php deleted file mode 100644 index 2f7bac9..0000000 --- a/src/Annotation/Property/FilterJoin.php +++ /dev/null @@ -1,15 +0,0 @@ -method = $method; - } - } -} \ No newline at end of file diff --git a/src/Annotation/Property/GroupBy.php b/src/Annotation/Property/GroupBy.php deleted file mode 100644 index e556a1d..0000000 --- a/src/Annotation/Property/GroupBy.php +++ /dev/null @@ -1,15 +0,0 @@ -fields = $field; - } - } -} diff --git a/src/Annotation/Property/Having.php b/src/Annotation/Property/Having.php deleted file mode 100644 index d2cb5a1..0000000 --- a/src/Annotation/Property/Having.php +++ /dev/null @@ -1,5 +0,0 @@ -type = $type; - } - - if ($key !== null) { - $this->key = $key; - } - - if ($foreignKey !== null) { - $this->foreignKey = $foreignKey; - } - } -} diff --git a/src/Annotation/Property/On.php b/src/Annotation/Property/On.php deleted file mode 100644 index fd7f9b0..0000000 --- a/src/Annotation/Property/On.php +++ /dev/null @@ -1,5 +0,0 @@ -field = $field; - } - - if ( $order !== null ) { - $this->order = $order; - } - } -} diff --git a/src/Annotation/Property/Relation.php b/src/Annotation/Property/Relation.php deleted file mode 100644 index 1749670..0000000 --- a/src/Annotation/Property/Relation.php +++ /dev/null @@ -1,88 +0,0 @@ -type = $type; - } - } - - public function entity() { - try { - $e = $this->entity; - } catch (\Throwable $ex) { - throw new \Exception("Your @Relation annotation seems to be missing an `entity` entry."); - } - - return new $e(); - } - - public function bridge() { - $e = $this->bridge; - - return new $e(); - } - - public function normalizeType() : string - { - return strtolower(str_replace(['-', '_', ' '], '', $this->type)); - } - - public function isOneToOne() : bool - { - return $this->normalizeType() === 'onetoone'; - } - - public function isOneToMany() : bool - { - return $this->normalizeType() === 'onetomany'; - } - - public function isManyToMany() : bool - { - return $this->normalizeType() === 'manytomany'; - } - - public function function() : string - { - if ($this->function) { - return $this->function; - } - elseif ($this->isOneToOne()) { - return 'load'; - } - - return 'loadAll'; - } - - public function hasBridge() : bool - { - return isset($this->bridge); - } -} diff --git a/src/Annotation/Property/Relation/Ignore.php b/src/Annotation/Property/Relation/Ignore.php deleted file mode 100644 index 541fe3c..0000000 --- a/src/Annotation/Property/Relation/Ignore.php +++ /dev/null @@ -1,5 +0,0 @@ -closure = $closure; - } - } -} diff --git a/src/Annotation/Property/Where.php b/src/Annotation/Property/Where.php deleted file mode 100644 index a712a43..0000000 --- a/src/Annotation/Property/Where.php +++ /dev/null @@ -1,30 +0,0 @@ -field = $field; - } - - if ( $value !== null ) { - $this->value = $value; - } - - $this->operator = $operator !== null ? $operator : Query\Where::OPERATOR_EQUAL; - $this->condition = $condition !== null ? $condition : Query\Where::CONDITION_AND; - } -} diff --git a/src/Annotation/Property/WithJoin.php b/src/Annotation/Property/WithJoin.php deleted file mode 100644 index 035fea6..0000000 --- a/src/Annotation/Property/WithJoin.php +++ /dev/null @@ -1,15 +0,0 @@ -joins = (array)$joins; - } - } -} diff --git a/src/Attribute/Property/Join.php b/src/Attribute/Property/Join.php index 9bc8ae5..6d825fd 100644 --- a/src/Attribute/Property/Join.php +++ b/src/Attribute/Property/Join.php @@ -5,7 +5,7 @@ namespace Ulmus\Attribute\Property; use Ulmus\Attribute\Attribute; #[\Attribute] -class Join { +class Join implements ResettablePropertyInterface { public function __construct( public string $type, public null|string|\Stringable|array $key = null, diff --git a/src/Attribute/Property/Relation.php b/src/Attribute/Property/Relation.php index 58e6f0d..083bbf4 100644 --- a/src/Attribute/Property/Relation.php +++ b/src/Attribute/Property/Relation.php @@ -5,7 +5,7 @@ namespace Ulmus\Attribute\Property; use Ulmus\Attribute\Attribute; #[\Attribute(\Attribute::TARGET_PROPERTY)] -class Relation { +class Relation implements ResettablePropertyInterface { public function __construct( public Relation\RelationTypeEnum|string $type, public \Stringable|string|array $key = "", diff --git a/src/Attribute/Property/ResettablePropertyInterface.php b/src/Attribute/Property/ResettablePropertyInterface.php new file mode 100644 index 0000000..650cade --- /dev/null +++ b/src/Attribute/Property/ResettablePropertyInterface.php @@ -0,0 +1,8 @@ +reflectedClass = ObjectReflection::fromClass($entityClass, $cache)->reflectClass(); } - public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : ? ReflectedProperty + public function field($name, $fieldKey = self::KEY_ENTITY_NAME, $throwException = true) : null|ReflectedProperty { try{ return $this->fieldList($fieldKey)[$name] ?? null; @@ -51,7 +49,7 @@ class EntityResolver { return null; } - public function searchField($name) : null|array + public function searchField($name) : null|ReflectedProperty { return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false); } @@ -62,8 +60,8 @@ class EntityResolver { foreach($this->reflectedClass->getProperties(true) as $item) { foreach($item->getAttributes() as $tag) { - if ( $tag->object instanceof Attribute\Property\Field ) { - if ( $skipVirtual && $tag->object instanceof Attribute\Property\Virtual ) { + if ( $tag->object instanceof Field ) { + if ( $skipVirtual && $tag->object instanceof Virtual ) { break; } @@ -102,7 +100,7 @@ class EntityResolver { try{ if ( $property ) { foreach($property->getAttributes() as $tag) { - if ( $tag->object instanceof Relation or $tag->object instanceof Attribute\Property\Relation ) { + if ( $tag->object instanceof Relation ) { return $property; } } @@ -156,7 +154,7 @@ class EntityResolver { return $table->name ?? ""; } - public function tableAnnotation($required = false) : null|Table|Attribute\Obj\Table + public function tableAnnotation($required = false) : null|Table { if ( null === $table = $this->getTableAttribute() ) { if ($required) { @@ -167,7 +165,7 @@ class EntityResolver { return $table; } - public function databaseName() : ? string + public function databaseName() : null|string { return $this->tableAnnotation(false)->database ?? $this->databaseAdapter()->adapter()->databaseName() ?? null; } @@ -196,7 +194,7 @@ class EntityResolver { return $this->sqlAdapter(); } - public function schemaName(bool $required = false) : ? string + public function schemaName(bool $required = false) : null|string { if ( null === $table = $this->getTableAttribute() ) { throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation"); @@ -209,10 +207,10 @@ class EntityResolver { return $table->schema ?? null; } - public function getPrimaryKeyField() : ? array + public function getPrimaryKeyField() : null|array { foreach($this->fieldList() as $key => $value) { - $field = $this->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]); + $field = $this->searchFieldAnnotation($key, [ Field::class ]); if ( null !== $field ) { if ( false !== ( $field->attributes['primary_key'] ?? false ) ) { return [ $key => $field ]; @@ -235,55 +233,15 @@ class EntityResolver { protected function getAdapterInterfaceAttribute() : null|object { - return $this->getAttributeImplementing(Attribute\Obj\AdapterAttributeInterface::class); + return $this->getAttributeImplementing(AdapterAttributeInterface::class); } protected function getTableAttribute() { - return $this->getAttributeImplementing(Attribute\Obj\Table::class) ?: $this->getAnnotationFromClassname( Table::class, false ); + return $this->getAttributeImplementing(Table::class); } - /** - * Transform an annotation into it's object's counterpart - */ - public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object - { - exit(__FILE__); - if ( $name = $this->uses[$className] ?? false ) { - foreach(array_reverse($this->class['tags']) as $item) { - if ( $item['tag'] === $name ) { - return $this->instanciateAnnotationObject($item); - } - - foreach($this->properties as $item) { - foreach(array_reverse($item['tags']) as $item) { - if ( $item['tag'] === $name ) { - return $this->instanciateAnnotationObject($item); - } - } - } - - foreach($this->methods as $item) { - foreach(array_reverse($item['tags']) as $item) { - if ( $item['tag'] === $name ) { - return $this->instanciateAnnotationObject($item); - } - } - } - } - - if ($throwError) { - throw new \TypeError("Annotation `$className` could not be found within your object `{$this->entityClass}`"); - } - } - elseif ($throwError) { - throw new \InvalidArgumentException("Class `$className` was not found within {$this->entityClass} uses statement (or it's children / traits)"); - } - - return null; - } - - public function getAttributeImplementing(string $interface) : ? object + public function getAttributeImplementing(string $interface) : null|object { foreach (array_reverse($this->reflectedClass->getAttributes(true)) as $item) { if ($item->object instanceof $interface) { @@ -293,14 +251,4 @@ class EntityResolver { return null; } - - public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object - { - - if ($tagDefinition instanceof \ReflectionAttribute) { - $obj = $tagDefinition->newInstance(); - } - - return $obj; - } } diff --git a/src/Entity/DatasetHandler.php b/src/Entity/DatasetHandler.php new file mode 100644 index 0000000..fc39230 --- /dev/null +++ b/src/Entity/DatasetHandler.php @@ -0,0 +1,153 @@ +entityResolver->fieldList(EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) { + $annotation = $this->entityResolver->searchFieldAnnotation($key,[ Field::class ]); + + if ( $entity->__isset($key) ) { + yield $annotation->name ?? $key => $entity->$key; + } + elseif ( $field->allowsNull() ) { + yield $annotation->name ?? $key => null; + } + } + } + + public function push(iterable $dataset) : Generator|array + { + $unmatched = []; + + foreach($dataset as $key => $value) { + $field = $this->entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? $this->entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false); + + if ( $field === null ) { + if ($this->entityStrictFieldsDeclaration ) { + throw new \Exception("Field `$key` can not be found within your entity ".static::class); + } + else { + $unmatched[$key] = $value; + } + + continue; + } + + $type = $field->getTypes()[0]; + + if ( is_null($value) ) { + yield $field->name => null; + } + elseif ( $field->expectType('array') ) { + if ( is_string($value)) { + if (substr($value, 0, 1) === "a") { + + yield $field->name => unserialize($value); + } + else { + $data = json_decode($value, true); + + if (json_last_error() !== \JSON_ERROR_NONE) { + throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s", json_last_error_msg(), $value)); + } + + yield $field->name => $data; + } + } + elseif ( is_array($value) ) { + yield $field->name => $value; + } + } + elseif ( EntityField::isScalarType($type->type) ) { + + if ( $type->type === 'string' ) { + $annotation = $this->entityResolver->searchFieldAnnotation($field->name, [ Field::class ] ); + + if ( $annotation->length ?? null ) { + $value = mb_substr($value, 0, $annotation->length); + } + } + elseif ( $type->type === 'bool' ) { + $value = (bool) $value; + } + + yield $field->name => $value; + } + elseif ( $value instanceof \UnitEnum ) { + yield $field->name => $value; + } + elseif (enum_exists($type->type)) { + yield $field->name => $type->type::from($value); + } + elseif ( ! $type->builtIn ) { + try { + yield $field->name => Ulmus::instanciateObject($type->type, [ $value ]); + } + catch(\Error $e) { + throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field->name)); + } + } + } + + return $unmatched; + } + + public function pullRelation(object $entity) : Generator + { + foreach($this->entityResolver->reflectedClass->getProperties(true) as $name => $field){ + $relation = $this->entityResolver->searchFieldAnnotation($name, [ Relation::class ] ); + + if ($relation) { + $ignore = $this->entityResolver->searchFieldAnnotation($name, [ Relation\Ignore::class ] ); + + if ($ignore && $ignore->ignoreExport) { + if ( $relation->isOneToOne() ) { + # @TODO TO INCLUDED INTO getTypes() RETURNED CLASS WHEN DONE ! + yield $name => ( new \ReflectionClass($field->getTypes()[0]) )->newInstanceWithoutConstructor(); + } + else { + # empty collection + yield $name => []; + } + + continue; + } + + # @TODO Must fix recursive bug.. this last check is way too basic to work + if ( $entity->__isset($name) && ($relation->entity ?? $relation->bridge) !== static::class ) { + if ( null !== $value = $entity->__isset($name) ?? null ) { + if ( is_iterable($value) ) { + $list = []; + + foreach($value as $entityObj) { + $list[] = $entityObj->entityGetDataset(false); + } + + yield $name => $list; + } + elseif ( is_object($value) ) { + yield $name => $value->entityGetDataset(false); + } + } + } + } + } + + } +} \ No newline at end of file diff --git a/src/EntityTrait.php b/src/EntityTrait.php index 6d79f16..2cb9005 100644 --- a/src/EntityTrait.php +++ b/src/EntityTrait.php @@ -4,7 +4,15 @@ namespace Ulmus; use Notes\Attribute\Ignore; use Psr\Http\Message\ServerRequestInterface; -use Ulmus\{Common\EntityResolver, Common\EntityField, Entity\EntityInterface, QueryBuilder\QueryBuilderInterface}; +use Ulmus\{Attribute\Property\Join, + Attribute\Property\Relation, + Attribute\Property\ResettablePropertyInterface, + Attribute\Property\Virtual, + Common\EntityResolver, + Common\EntityField, + Entity\DatasetHandler, + Entity\EntityInterface, + QueryBuilder\QueryBuilderInterface}; use Ulmus\SearchRequest\{Attribute\SearchParameter, SearchMethodEnum, SearchRequestInterface, @@ -14,6 +22,9 @@ use Ulmus\SearchRequest\{Attribute\SearchParameter, trait EntityTrait { use EventTrait; + #[Ignore] + public array $entityLoadedDataset = []; + #[Ignore] protected bool $entityStrictFieldsDeclaration = false; @@ -21,14 +32,23 @@ trait EntityTrait { protected array $entityDatasetUnmatchedFields = []; #[Ignore] - public array $entityLoadedDataset = []; + protected DatasetHandler $datasetHandler; #[Ignore] - public function __construct(array $dataset = null) { + public function __construct(iterable|null $dataset = null) + { + $this->initializeEntity($dataset); + } + + #[Ignore] + public function initializeEntity(iterable|null $dataset = null) : void + { if ($dataset) { - $this->entityFillFromDataset($dataset); + $this->fromArray($dataset); } + $this->datasetHandler = new DatasetHandler(static::resolveEntity(), $this->entityStrictFieldsDeclaration); + $this->resetVirtualProperties(); } @@ -37,98 +57,55 @@ trait EntityTrait { { $loaded = $this->isLoaded(); - $entityResolver = $this->resolveEntity(); + $handler = $this->datasetHandler->push($dataset); - foreach($dataset as $key => $value) { - $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false); + foreach($handler as $field => $value) { + $this->$field = $value; + } - # Temp. fix, incoming patch soon - $type = $field->getTypes()[0]; + $this->entityDatasetUnmatchedFields = $handler->getReturn(); - if ( $field === null ) { - if ($this->entityStrictFieldsDeclaration ) { - throw new \Exception("Field `$key` can not be found within your entity ".static::class); - } - else { - $this->entityDatasetUnmatchedFields[$key] = $value; - } - } - elseif ( is_null($value) ) { - $this->{$field->name} = null; - } - elseif ( $field->expectType('array') ) { - if ( is_string($value)) { - if (substr($value, 0, 1) === "a") { - $this->{$field->name} = unserialize($value); - } - else { - $data = json_decode($value, true); - - if (json_last_error() !== \JSON_ERROR_NONE) { - throw new \Exception(sprintf("JSON error while decoding in EntityTrait : '%s' given %s", json_last_error_msg(), $value)); - } - - $this->{$field->name} = $data; - } - } - elseif ( is_array($value) ) { - $this->{$field->name} = $value; - } - } - elseif ( EntityField::isScalarType($type->type) ) { - - if ( $type->type === 'string' ) { - $annotation = $entityResolver->searchFieldAnnotation($field->name, [ Attribute\Property\Field::class ] ); - - if ( $annotation->length ?? null ) { - $value = mb_substr($value, 0, $annotation->length); - } - } - elseif ( $type->type === 'bool' ) { - $value = (bool) $value; - } - - $this->{$field->name} = $value; - } - elseif ( $value instanceof \UnitEnum ) { - $this->{$field->name} = $value; - } - elseif (enum_exists($type->type)) { - $this->{$field->name} = $type->type::from($value); - } - elseif ( ! $type->builtIn ) { - try { - $this->{$field->name} = Ulmus::instanciateObject($type->type, [ $value ]); - } - catch(\Error $e) { - $f = $type->type; - throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field->name)); - } - } - - # Keeping original data to diff on UPDATE query - if ( ! $loaded /* || $isLoadedDataset */ ) { - #if ( $field !== null ) { - # $annotation = $entityResolver->searchFieldAnnotation($field['name'], new Field() ); - # $this->entityLoadedDataset[$annotation ? $annotation->name : $field['name']] = $dataset; # <--------- THIS TO FIX !!!!!! - #} - $this->entityLoadedDataset = array_change_key_case($dataset, \CASE_LOWER); - } - elseif ($overwriteDataset) { - $this->entityLoadedDataset = iterator_to_array(array_change_key_case($dataset, \CASE_LOWER)) + $this->entityLoadedDataset; - } + # Keeping original data to diff on UPDATE query + if ( ! $loaded ) { + $this->entityLoadedDataset = array_change_key_case(is_array($dataset) ? $dataset : iterator_to_array($dataset), \CASE_LOWER); + } + elseif ($overwriteDataset) { + $this->entityLoadedDataset = array_change_key_case(is_array($dataset) ? $dataset : iterator_to_array($dataset), \CASE_LOWER) + $this->entityLoadedDataset; } return $this; } + #[Ignore] + public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false, bool $rewriteValue = true) : array + { + if ( $returnSource ) { + return $this->entityLoadedDataset; + } + + $dataset = []; + + foreach($this->datasetHandler->pull($this) as $field => $value) { + $dataset[$field] = $rewriteValue ? static::repository()->adapter->adapter()->writableValue($value) : $value; + } + + if ($includeRelations) { + foreach($this->datasetHandler->pullRelation($this) as $field => $object) { + $dataset[$field] = $object; + } + } + + return $dataset; + } + #[Ignore] public function resetVirtualProperties() : self { - foreach($this->resolveEntity()->reflectedClass->getProperties(true) as $prop => $property) { + foreach($this->resolveEntity()->reflectedClass->getProperties(true) as $field => $property) { foreach($property->attributes as $tag) { - if ( in_array(strtolower($tag->tag), [ 'relation', 'join', 'virtual' ] ) ) { - unset($this->$prop); + + if ( $tag->object instanceof ResettablePropertyInterface ) { + unset($this->$field); } } } @@ -146,74 +123,6 @@ trait EntityTrait { return $this->entityFillFromDataset($dataset); } - public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false, bool $rewriteValue = true) : array - { - if ( $returnSource ) { - return $this->entityLoadedDataset; - } - - $dataset = []; - - $entityResolver = $this->resolveEntity(); - - foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) { - $annotation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Field::class ]); - - if ( isset($this->$key) ) { - $dataset[$annotation->name ?? $key] = $rewriteValue ? - static::repository()->adapter->adapter()->writableValue($this->$key) - : - $this->$key; - } - elseif ( $field->allowsNull() ) { - $dataset[$annotation->name ?? $key] = null; - } - } - - if ($includeRelations) { - foreach($entityResolver->reflectedClass->getProperties(true) as $name => $field){ - $relation = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] ); - - if ($relation) { - $ignore = $entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation\Ignore::class ] ); - - if ($ignore && $ignore->ignoreExport) { - if ( $relation->isOneToOne() ) { - # empty object - $dataset[$name] = ( new \ReflectionClass($field->getTypes()[0]) )->newInstanceWithoutConstructor(); - } - else { - # empty collection - $dataset[$name] = []; - } - - continue; - } - - # @TODO Must fix recursive bug.. this last check is way too basic to work - if ( isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) { - if ( null !== $value = $this->$name ?? null ) { - if ( is_iterable($value) ) { - $list = []; - - foreach($value as $entity) { - $list[] = $entity->entityGetDataset(false); - } - - $dataset[$name] = $list; - } - elseif ( is_object($value) ) { - $dataset[$name] = $value->entityGetDataset(false); - } - } - } - } - } - } - - return $dataset; - } - #[Ignore] public function toArray($includeRelations = false, array $filterFields = null, bool $rewriteValue = true) : array { diff --git a/src/Repository/RelationBuilder.php b/src/Repository/RelationBuilder.php index ea98938..f5b9805 100644 --- a/src/Repository/RelationBuilder.php +++ b/src/Repository/RelationBuilder.php @@ -2,20 +2,13 @@ namespace Ulmus\Repository; -use Ulmus\{Attribute\Property\Field, - Ulmus, - Annotation, - Attribute, - Query, - Common, - Common\EntityResolver, - Repository, - Event, - EntityCollection}; +use Ulmus\{ + Ulmus, Query, Common\EntityResolver, Repository, Event, +}; -use Ulmus\Annotation\Property\{Filter, OrderBy, Relation, Relation\Ignore as RelationIgnore, Where, WithJoin, }; - -use Closure; +use Ulmus\Attribute\Property\{ + Filter, Join, OrderBy, Relation, Virtual, Where, WithJoin, +}; class RelationBuilder { @@ -64,7 +57,7 @@ class RelationBuilder } else { - if ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class , Relation::class ] ) ) { + if ( $relation = $this->resolver->searchFieldAnnotation($name, [ Relation::class ] ) ) { return $this->instanciateEmptyObject($name, $relation); } elseif ($virtual = $this->resolveVirtual($name)) { @@ -77,7 +70,7 @@ class RelationBuilder protected function resolveVirtual(string $name) : mixed { - if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Virtual::class, Annotation\Property\Virtual::class ]))) { + if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, Virtual::class))) { try { $arguments = [ $this->entity ]; @@ -98,11 +91,11 @@ class RelationBuilder protected function resolveRelation(string $name) : mixed { - if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ) ) ) { - $this->orders = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ] ); - $this->wheres = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ] ); - $this->filters = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Filter::class, Filter::class ] ); - $this->joins = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\WithJoin::class, WithJoin::class ] ); + if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, [ Relation::class ] ) ) ) { + $this->orders = $this->resolver->searchFieldAnnotationList($name, [ OrderBy::class ] ); + $this->wheres = $this->resolver->searchFieldAnnotationList($name, [ Where::class ] ); + $this->filters = $this->resolver->searchFieldAnnotationList($name, [ Filter::class ] ); + $this->joins = $this->resolver->searchFieldAnnotationList($name, [ WithJoin::class ] ); switch( true ) { case $relation->isOneToOne(): @@ -178,22 +171,22 @@ class RelationBuilder } } - protected function instanciateEmptyEntity(string $name, Relation|Attribute\Property\Relation $relation) : object + protected function instanciateEmptyEntity(string $name, Relation $relation) : object { - $class = $relation->entity ?? $this->resolver->properties[$name]['type']; + $class = $relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type; return new $class(); } - protected function instanciateEmptyObject(string $name, Relation|Attribute\Property\Relation $relation) : object + protected function instanciateEmptyObject(string $name, Relation $relation) : object { switch( true ) { case $relation->isOneToOne(): return $this->instanciateEmptyEntity($name, $relation); case $relation->isOneToMany(): - return ($relation->entity ?? $this->resolver->properties[$name]['type'])::entityCollection(); + return ($relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type)::entityCollection(); case $relation->isManyToMany(): extract($this->relationAnnotations($name, $relation)); @@ -206,14 +199,14 @@ class RelationBuilder protected function fetchFromDataset($name, ? array $data = null) : object|bool { - $annotation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Join::class, Annotation\Property\Join::class ]) ?: - $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Annotation\Property\Relation::class ]); + $annotation = $this->resolver->searchFieldAnnotation($name, [ Join::class ]) ?: + $this->resolver->searchFieldAnnotation($name, [ Relation::class ]); if ( $annotation ) { $vars = []; $len = strlen( $name ) + 1; - $isRelation = ( $annotation instanceof Relation ) || ( $annotation instanceof Attribute\Property\Relation ); + $isRelation = $annotation instanceof Relation; if ( $isRelation && $annotation->isManyToMany() ) { $entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity; @@ -259,12 +252,12 @@ class RelationBuilder return false; } - public function oneToOne(string $name, Relation|Attribute\Property\Relation $relation) : Repository + public function oneToOne(string $name, Relation $relation) : Repository { return $this->oneToMany($name, $relation)->limit(1); } - public function oneToMany(string $name, Relation|Attribute\Property\Relation $relation) : Repository + public function oneToMany(string $name, Relation $relation) : Repository { $baseEntity = $relation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type; @@ -290,7 +283,7 @@ class RelationBuilder return $this->applyFilter($this->repository, $name); } - public function manyToMany(string $name, Relation|Attribute\Property\Relation $relation, Relation|Attribute\Property\Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository + public function manyToMany(string $name, Relation $relation, Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository { extract($this->relationAnnotations($name, $relation)); @@ -318,7 +311,7 @@ class RelationBuilder return $this->applyFilter($this->repository, $name); } - public static function relationAnnotations(string $name, Relation|Attribute\Property\Relation $relation) : array + public static function relationAnnotations(string $name, Relation $relation) : array { if ( $relation->isOneToOne() || $relation->isManyToMany() ) { if ( ! $relation->hasBridge() ) { @@ -326,14 +319,14 @@ class RelationBuilder } $bridgeEntity = Ulmus::resolveEntity($relation->bridge); - $bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, [ Attribute\Property\Relation::class, Relation::class ]); - $relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, [ Attribute\Property\Relation::class, Relation::class ]); + $bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, [ Relation::class ]); + $relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, [ Relation::class ]); if ($relationRelation === null) { throw new \Exception("@Relation annotation not found for field `{$relation->foreignField}` in entity {$relation->bridge}"); } - $relationRelation->entity ??= $relation->bridge::resolveEntity()->properties[$relation->foreignField]['type']; + $relationRelation->entity ??= $relation->bridge::resolveEntity()->reflectedClass->getProperties()[$relation->foreignField]->getTypes()[0]->type; return [ 'bridgeEntity' => $bridgeEntity, From bd9078230d0c4a99567b665e8c9c0d1ee29576a2 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Fri, 31 May 2024 12:26:39 +0000 Subject: [PATCH 3/5] - Multiple bug fixes related to notes 2.x --- src/Attribute/Property/Relation.php | 2 +- src/Common/EntityField.php | 6 +- src/Common/EntityResolver.php | 18 ++--- src/Entity/DatasetHandler.php | 12 +-- src/Query/Alter.php | 3 +- src/Query/Create.php | 3 +- src/Repository.php | 80 ++++++++++--------- src/Repository/RelationBuilder.php | 14 ++-- .../SearchRequestFromRequestTrait.php | 4 + 9 files changed, 69 insertions(+), 73 deletions(-) diff --git a/src/Attribute/Property/Relation.php b/src/Attribute/Property/Relation.php index 083bbf4..9aca8cc 100644 --- a/src/Attribute/Property/Relation.php +++ b/src/Attribute/Property/Relation.php @@ -35,7 +35,7 @@ class Relation implements ResettablePropertyInterface { try { $e = $this->entity; } catch (\Throwable $ex) { - throw new \Exception("Your @Relation annotation seems to be missing an `entity` entry."); + throw new \Exception("Your @Relation attribute seems to be missing an `entity` entry."); } return new $e(); diff --git a/src/Common/EntityField.php b/src/Common/EntityField.php index 2cdddb7..0d64c54 100644 --- a/src/Common/EntityField.php +++ b/src/Common/EntityField.php @@ -2,12 +2,10 @@ namespace Ulmus\Common; -use Ulmus\Annotation\Annotation; -use Ulmus\Attribute; +use Ulmus\Attribute\Property\{ Field }; use Ulmus\Migration\FieldDefinition; use Ulmus\Ulmus, Ulmus\Adapter\AdapterInterface, - Ulmus\Annotation\Property\Field, Ulmus\Query\WhereRawParameter; class EntityField implements WhereRawParameter @@ -30,7 +28,7 @@ class EntityField implements WhereRawParameter public function name($useAlias = true) : string { - $name = $this->entityResolver->searchFieldAnnotation($this->name, [ Attribute\Property\Field::class, Field::class ] )->name ?? $this->name; + $name = $this->entityResolver->searchFieldAnnotation($this->name, [ Field::class ] )->name ?? $this->name; $name = $this->entityResolver->databaseAdapter()->adapter()->escapeIdentifier($name, AdapterInterface::IDENTIFIER_FIELD); diff --git a/src/Common/EntityResolver.php b/src/Common/EntityResolver.php index 92bd6dc..2dfb063 100644 --- a/src/Common/EntityResolver.php +++ b/src/Common/EntityResolver.php @@ -12,6 +12,8 @@ use Ulmus\Ulmus, Ulmus\Attribute\Property\Relation, Ulmus\Attribute\Property\Virtual; +use Notes\Common\ReflectedAttribute; + use Notes\ObjectReflection; class EntityResolver { @@ -118,7 +120,7 @@ class EntityResolver { return $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive)[0] ?? null; } - public function searchFieldAnnotationList(string $field, array|object|string $annotationType, bool $caseSensitive = true) : array + public function searchFieldAnnotationList(string $field, array|object|string $attributeType, bool $caseSensitive = true) : false|array { $list = []; @@ -126,19 +128,11 @@ class EntityResolver { $search = $caseSensitive ? $properties : array_change_key_case($properties, \CASE_LOWER); - $annotations = is_array($annotationType) ? $annotationType : [ $annotationType ]; - if ( null !== ( $search[$field] ?? null ) ) { - foreach($search[$field]->getAttributes() as $tag) { - foreach($annotations as $annotation) { - if ( $tag->object instanceof $annotation ) { - $list[] = $tag->object; - } - } - } + return array_map(fn(ReflectedAttribute $e) => $e->object, $search[$field]->getAttributes((array) $attributeType)); } - - return $list; + + return false; } public function tableName($required = false) : string diff --git a/src/Entity/DatasetHandler.php b/src/Entity/DatasetHandler.php index fc39230..f51f9c2 100644 --- a/src/Entity/DatasetHandler.php +++ b/src/Entity/DatasetHandler.php @@ -20,13 +20,13 @@ class DatasetHandler public function pull(object $entity) : Generator { foreach($this->entityResolver->fieldList(EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) { - $annotation = $this->entityResolver->searchFieldAnnotation($key,[ Field::class ]); + $attribute = $this->entityResolver->searchFieldAnnotation($key,[ Field::class ]); if ( $entity->__isset($key) ) { - yield $annotation->name ?? $key => $entity->$key; + yield $attribute->name ?? $key => $entity->$key; } elseif ( $field->allowsNull() ) { - yield $annotation->name ?? $key => null; + yield $attribute->name ?? $key => null; } } } @@ -77,10 +77,10 @@ class DatasetHandler elseif ( EntityField::isScalarType($type->type) ) { if ( $type->type === 'string' ) { - $annotation = $this->entityResolver->searchFieldAnnotation($field->name, [ Field::class ] ); + $attribute = $this->entityResolver->searchFieldAnnotation($field->name, [ Field::class ] ); - if ( $annotation->length ?? null ) { - $value = mb_substr($value, 0, $annotation->length); + if ( $attribute->length ?? null ) { + $value = mb_substr($value, 0, $attribute->length); } } elseif ( $type->type === 'bool' ) { diff --git a/src/Query/Alter.php b/src/Query/Alter.php index 4fa0f9a..d1e5017 100644 --- a/src/Query/Alter.php +++ b/src/Query/Alter.php @@ -3,8 +3,7 @@ namespace Ulmus\Query; use Ulmus\Adapter\AdapterInterface; -use Ulmus\Annotation, - Ulmus\Common\EntityField; +use Ulmus\Common\EntityField; class Alter extends Fragment { diff --git a/src/Query/Create.php b/src/Query/Create.php index 6e95a1d..1911a4c 100644 --- a/src/Query/Create.php +++ b/src/Query/Create.php @@ -3,8 +3,7 @@ namespace Ulmus\Query; use Ulmus\Adapter\AdapterInterface; -use Ulmus\Annotation, - Ulmus\Common\EntityField; +use Ulmus\Common\EntityField; class Create extends Fragment { diff --git a/src/Repository.php b/src/Repository.php index aea8c98..f8a8de9 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -2,16 +2,9 @@ namespace Ulmus; -use Ulmus\Annotation\Property\{Field, - OrderBy, - Where, - Having, - Relation, - Filter, - Join, - FilterJoin, - WithJoin, - Relation\Ignore as RelationIgnore}; +use Ulmus\Attribute\Property\{ + Field, OrderBy, Where, Having, Relation, Filter, Join, FilterJoin, WithJoin +}; use Ulmus\Common\EntityResolver; use Ulmus\Repository\WithOptionEnum; @@ -88,7 +81,16 @@ class Repository $this->select( "DISTINCT COUNT(*) OVER ()" ); } else { - $this->select(Common\Sql::function("COUNT", '*')); + $pk = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField(); + + if (count($pk) === 1) { + $field = key($pk); + + $this->select(Common\Sql::function('COUNT', Common\Sql::raw("DISTINCT " . $this->entityClass::field($field)))); + } + else { + $this->select(Common\Sql::function('COUNT', Common\Sql::raw('*'))); + } } $this->selectSqlQuery(); @@ -362,7 +364,7 @@ class Repository $dataset = $this->generateDatasetDiff($entity, $oldValues); foreach($dataset as $field => $value) { - if ( false === ( $this->entityResolver->searchFieldAnnotation($field, [ Attribute\Property\Field::class, Field::class ], false)->readonly ?? false ) ) { + if ( false === ( $this->entityResolver->searchFieldAnnotation($field, [ Field::class, Field::class ], false)->readonly ?? false ) ) { $intersect[$field] = $field; } } @@ -395,7 +397,7 @@ class Repository $prependField and ($prependField .= "$"); foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { - if (null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) { + if (null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Relation\Ignore::class ])) { $this->select(sprintf("%s.$key as {$prependField}{$field->name}", $this->escapeIdentifier($alias))); } } @@ -408,7 +410,7 @@ class Repository $fieldlist = []; foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { - if (null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) { + if (null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Relation\Ignore::class ])) { $fieldlist[] = $key; $fieldlist[] = $entity::field($field->name, $this->escapeIdentifier($alias)); } @@ -623,26 +625,26 @@ class Repository $this->joined[$item] = true; } - $annotation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Join::class ]) ?: - $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class ]); + $attribute = $this->entityResolver->searchFieldAnnotation($item, [ Join::class ]) ?: + $this->entityResolver->searchFieldAnnotation($item, [ Relation::class ]); - $isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation); + $isRelation = ( $attribute instanceof Relation ) || ($attribute instanceof Relation); - if ($isRelation && ( $annotation->isManyToMany() )) { + if ($isRelation && ( $attribute->isManyToMany() )) { throw new \Exception("Many-to-many relation can not be preloaded within joins."); } - if ( $annotation ) { - $alias = $annotation->alias ?? $item; + if ( $attribute ) { + $alias = $attribute->alias ?? $item; - $entity = $annotation->entity ?? $this->entityResolver->reflectedClass->getProperties(true)[$item]->getTypes()[0]->type; + $entity = $attribute->entity ?? $this->entityResolver->reflectedClass->getProperties(true)[$item]->getTypes()[0]->type; foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { - if ( null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class ]) ) { + if ( null === $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Relation\Ignore::class ]) ) { $escAlias = $this->escapeIdentifier($alias); $fieldName = $this->escapeIdentifier($key); - $name = $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Attribute\Property\Field::class ])->name ?? $field->name; + $name = $entity::resolveEntity()->searchFieldAnnotation($field->name, [ Field::class ])->name ?? $field->name; $this->select("$escAlias.$fieldName as $alias\${$name}"); @@ -652,7 +654,7 @@ class Repository $this->open(); if ( ! in_array(WithOptionEnum::SkipWhere, $options)) { - foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class ] ) as $condition) { + foreach($this->entityResolver->searchFieldAnnotationList($item, [ Where::class ] ) as $condition) { if ( is_object($condition->field) && ( $condition->field->entityClass !== $entity ) ) { $this->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator); } @@ -660,26 +662,26 @@ class Repository } if ( ! in_array(WithOptionEnum::SkipHaving, $options)) { - foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class ]) as $condition) { + foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Having::class ]) as $condition) { $this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator); } } if ( ! in_array(WithOptionEnum::SkipFilter, $options)) { - foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Filter::class ]) as $filter) { + foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Filter::class ]) as $filter) { call_user_func_array([$this->entityClass, $filter->method], [$this, $item, true]); } } $this->close(); - $key = is_string($annotation->key) ? $this->entityClass::field($annotation->key) : $annotation->key; + $key = is_string($attribute->key) ? $this->entityClass::field($attribute->key) : $attribute->key; - $foreignKey = is_string($annotation->foreignKey) ? $entity::field($annotation->foreignKey, $alias) : $annotation->foreignKey; + $foreignKey = is_string($attribute->foreignKey) ? $entity::field($attribute->foreignKey, $alias) : $attribute->foreignKey; $this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias, $options) { if ( ! in_array(WithOptionEnum::SkipJoinWhere, $options)) { - foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class ]) as $condition) { + foreach($this->entityResolver->searchFieldAnnotationList($item, [ Where::class ]) as $condition) { if ( ! is_object($condition->field) ) { $field = $this->entityClass::field($condition->field); } @@ -697,14 +699,14 @@ class Repository } if ( ! in_array(WithOptionEnum::SkipJoinFilter, $options) ) { - foreach ($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\FilterJoin::class ]) as $filter) { + foreach ($this->entityResolver->searchFieldAnnotationList($item, [ FilterJoin::class ]) as $filter) { call_user_func_array([$this->entityClass, $filter->method], [$join, $item, true]); } } }); } else { - throw new \Exception("Referenced field `$item` which do not exist or do not contain a valid @Join or @Relation annotation."); + throw new \Exception("Referenced field `$item` which do not exist or do not contain a valid @Join or @Relation attribute."); } } @@ -724,7 +726,7 @@ class Repository # Apply FILTER annotation to this too ! foreach(array_filter((array) $fields) as $item) { - if ( $relation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class ]) ) { + if ( $relation = $this->entityResolver->searchFieldAnnotation($item, [ Relation::class ]) ) { $alias = $relation->alias ?? $item; if ( $relation->isManyToMany() ) { @@ -745,11 +747,11 @@ class Repository # $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true); - foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class ]) as $condition) { + foreach($this->entityResolver->searchFieldAnnotationList($item, [ Where::class ]) as $condition) { $repository->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator); } - foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class ] ) as $condition) { + foreach($this->entityResolver->searchFieldAnnotationList($item, [ Having::class ] ) as $condition) { $repository->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->getValue(), $condition->operator); } @@ -766,7 +768,7 @@ class Repository $this->select("(" . $r = Common\Sql::raw($repository->queryBuilder->render() . ") as $item\$collection")); } else { - throw new \Exception("You referenced field `$item` which do not exist or do not contain a valid @Join annotation."); + throw new \Exception("You referenced field `$item` which do not exist or do not contain a valid @Join attribute."); } } @@ -776,9 +778,9 @@ class Repository public function loadCollectionRelation(EntityCollection $collection, array|string $fields) : void { foreach ((array)$fields as $name) { - if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class ] ))) { - $order = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class ]); - $where = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class ]); + if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Relation::class ] ))) { + $order = $this->entityResolver->searchFieldAnnotationList($name, [ OrderBy::class ]); + $where = $this->entityResolver->searchFieldAnnotationList($name, [ Where::class ]); $baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type']; $baseEntityResolver = $baseEntity::resolveEntity(); @@ -789,7 +791,7 @@ class Repository $repository = $baseEntity::repository(); foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { - if (null === $baseEntityResolver->searchFieldAnnotation($field->name, [ Attribute\Property\Relation\Ignore::class ])) { + if (null === $baseEntityResolver->searchFieldAnnotation($field->name, [ Relation\Ignore::class ])) { $repository->select($baseEntityResolver->entityClass::field($key)); } } diff --git a/src/Repository/RelationBuilder.php b/src/Repository/RelationBuilder.php index f5b9805..4fa2f1d 100644 --- a/src/Repository/RelationBuilder.php +++ b/src/Repository/RelationBuilder.php @@ -199,20 +199,20 @@ class RelationBuilder protected function fetchFromDataset($name, ? array $data = null) : object|bool { - $annotation = $this->resolver->searchFieldAnnotation($name, [ Join::class ]) ?: + $attribute = $this->resolver->searchFieldAnnotation($name, [ Join::class ]) ?: $this->resolver->searchFieldAnnotation($name, [ Relation::class ]); - if ( $annotation ) { + if ( $attribute ) { $vars = []; $len = strlen( $name ) + 1; - $isRelation = $annotation instanceof Relation; + $isRelation = $attribute instanceof Relation; - if ( $isRelation && $annotation->isManyToMany() ) { - $entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity; + if ( $isRelation && $attribute->isManyToMany() ) { + $entity = $this->relationAnnotations($name, $attribute)['relationRelation']->entity; } else { - $entity = $annotation->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type; + $entity = $attribute->entity ?? $this->resolver->reflectedClass->getProperties()[$name]->getTypes()[0]->type; } $name = strtolower($name); @@ -323,7 +323,7 @@ class RelationBuilder $relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, [ Relation::class ]); if ($relationRelation === null) { - throw new \Exception("@Relation annotation not found for field `{$relation->foreignField}` in entity {$relation->bridge}"); + throw new \Exception("@Relation attribute not found for field `{$relation->foreignField}` in entity {$relation->bridge}"); } $relationRelation->entity ??= $relation->bridge::resolveEntity()->reflectedClass->getProperties()[$relation->foreignField]->getTypes()[0]->type; diff --git a/src/SearchRequest/SearchRequestFromRequestTrait.php b/src/SearchRequest/SearchRequestFromRequestTrait.php index c3f2601..3d67862 100644 --- a/src/SearchRequest/SearchRequestFromRequestTrait.php +++ b/src/SearchRequest/SearchRequestFromRequestTrait.php @@ -18,6 +18,10 @@ trait SearchRequestFromRequestTrait public function fromRequest(ServerRequestInterface $request) { + if (method_exists($this, 'prepare')) { + $this->prepare($request); + } + $queryParams = new \ArrayObject(array_filter($request->getQueryParams(), function($i) { return ! is_null($i) && $i !== ""; })); $this->page = $queryParams->offsetExists('page') ? $queryParams['page'] : 1; From bbfd7c02b4bb6ca7aeb75c23526c312a8459e58b Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Tue, 4 Jun 2024 13:33:48 +0000 Subject: [PATCH 4/5] - WIP on SearchAttributes supporting Request's attributes --- src/Common/EntityResolver.php | 2 +- .../Attribute/PropertyValueSource.php | 14 ++++++ src/SearchRequest/Attribute/SearchLike.php | 1 + .../Attribute/SearchParameter.php | 12 ++++- src/SearchRequest/Attribute/SearchWhere.php | 1 + .../SearchRequestFromRequestTrait.php | 49 ++++++++++++++++--- 6 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 src/SearchRequest/Attribute/PropertyValueSource.php diff --git a/src/Common/EntityResolver.php b/src/Common/EntityResolver.php index 2dfb063..91cf874 100644 --- a/src/Common/EntityResolver.php +++ b/src/Common/EntityResolver.php @@ -237,7 +237,7 @@ class EntityResolver { public function getAttributeImplementing(string $interface) : null|object { - foreach (array_reverse($this->reflectedClass->getAttributes(true)) as $item) { + foreach ($this->reflectedClass->getAttributes(true) as $item) { if ($item->object instanceof $interface) { return $item->object; } diff --git a/src/SearchRequest/Attribute/PropertyValueSource.php b/src/SearchRequest/Attribute/PropertyValueSource.php new file mode 100644 index 0000000..d3f2bdf --- /dev/null +++ b/src/SearchRequest/Attribute/PropertyValueSource.php @@ -0,0 +1,14 @@ +source) ? $this->source : [ $this->source ]; + } } \ No newline at end of file diff --git a/src/SearchRequest/Attribute/SearchWhere.php b/src/SearchRequest/Attribute/SearchWhere.php index a777c11..b14a83e 100644 --- a/src/SearchRequest/Attribute/SearchWhere.php +++ b/src/SearchRequest/Attribute/SearchWhere.php @@ -13,5 +13,6 @@ class SearchWhere extends SearchParameter public bool $toggle = false, public SearchMethodEnum $method = SearchMethodEnum::Where, public string $description = "", + public PropertyValueSource|array $source = PropertyValueSource::QueryParams, ) {} } \ No newline at end of file diff --git a/src/SearchRequest/SearchRequestFromRequestTrait.php b/src/SearchRequest/SearchRequestFromRequestTrait.php index 3d67862..457f324 100644 --- a/src/SearchRequest/SearchRequestFromRequestTrait.php +++ b/src/SearchRequest/SearchRequestFromRequestTrait.php @@ -2,9 +2,16 @@ namespace Ulmus\SearchRequest; +use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; -use Ulmus\SearchRequest\Attribute\{ SearchParameter, SearchWhere, SearchLike, SearchOrderBy, SearchGroupBy, SearchRequestParameter, }; +use Ulmus\SearchRequest\Attribute\{PropertyValueSource, + SearchParameter, + SearchWhere, + SearchLike, + SearchOrderBy, + SearchGroupBy, + SearchRequestParameter}; trait SearchRequestFromRequestTrait { @@ -30,15 +37,12 @@ trait SearchRequestFromRequestTrait foreach($classReflection->getProperties() as $property) { $attributeList = $property->getAttributes(); - $attributeReflection = array_filter($attributeList, fn($e) => $e->newInstance() instanceof Attribute\SearchParameter); if ($attributeReflection) { $attribute = $attributeReflection[0]->newInstance(); - $propertyName = $property->getName(); $fieldName = $attribute->field ?? $propertyName; - $queryParamName = $attribute->parameter ?? $propertyName; # Field could be defined for another entity class if (is_array($fieldName)) { @@ -55,11 +59,15 @@ trait SearchRequestFromRequestTrait $field = $fieldName; } - $value = $queryParams->offsetExists($queryParamName) ? $this->transformValue($attributeList, $queryParams[$queryParamName]) : null; + $value = $this->getValueFromSource($request, $propertyName, $attribute); + + if ($value !== null) { + $value = $this->transformValue($attributeList, $value); + } if ($attribute instanceof SearchWhere || $attribute instanceof SearchLike) { if ($attribute->toggle) { - $this->$propertyName = $queryParams->offsetExists($queryParamName); + $this->$propertyName = ! empty($value); } elseif ($value !== null) { $this->$propertyName = $value; @@ -83,6 +91,35 @@ trait SearchRequestFromRequestTrait return $this; } + protected function getValueFromSource(RequestInterface $request, string $propertyName, SearchParameter $attribute) : mixed + { + $queryParamName = $attribute->parameter ?? $propertyName; + + foreach($attribute->getSources() as $source) { + switch($source) { + case PropertyValueSource::QueryParams: + $queryParams = new \ArrayObject(array_filter($request->getQueryParams(), function($i) { return ! is_null($i) && $i !== ""; })); + + if ($queryParams->offsetExists($queryParamName)) { + return $queryParams[$queryParamName]; + } + + break; + + case PropertyValueSource::RequestAttribute: + $fromAttribute = $request->getAttribute($queryParamName, null); + + if ($fromAttribute !== null) { + return $fromAttribute; + } + + break; + } + } + + return null; + } + protected function transformValue(array $attributeList, mixed $value, ) : mixed { $transforms = array_map(function($e) { From 0c8591f238708486821ce58861bcdfeda7b8397a Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Wed, 5 Jun 2024 17:47:31 +0000 Subject: [PATCH 5/5] - Added multiple parameters on SearchParameter --- src/SearchRequest/Attribute/SearchLike.php | 2 +- src/SearchRequest/Attribute/SearchOrderBy.php | 2 +- src/SearchRequest/Attribute/SearchParameter.php | 5 +++++ src/SearchRequest/Attribute/SearchWhere.php | 2 +- .../SearchRequestFromRequestTrait.php | 16 ++++++++++------ 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/SearchRequest/Attribute/SearchLike.php b/src/SearchRequest/Attribute/SearchLike.php index 13dac5b..459ed9e 100644 --- a/src/SearchRequest/Attribute/SearchLike.php +++ b/src/SearchRequest/Attribute/SearchLike.php @@ -8,7 +8,7 @@ use Ulmus\SearchRequest\SearchMethodEnum; class SearchLike extends SearchParameter { public function __construct( - public ? string $parameter = null, + public null|string|array $parameter = null, public null|string|\Stringable|array $field = null, public bool $toggle = false, public SearchMethodEnum $method = SearchMethodEnum::Like, diff --git a/src/SearchRequest/Attribute/SearchOrderBy.php b/src/SearchRequest/Attribute/SearchOrderBy.php index 171eba5..c23866f 100644 --- a/src/SearchRequest/Attribute/SearchOrderBy.php +++ b/src/SearchRequest/Attribute/SearchOrderBy.php @@ -12,7 +12,7 @@ class SearchOrderBy extends SearchParameter public const DESCENDING = "DESC"; public function __construct( - public ? string $parameter = null, + public null|string|array $parameter = null, public null|string|\Stringable|array $field = null, public null|SearchMethodEnum $order = null, public string $description = "", diff --git a/src/SearchRequest/Attribute/SearchParameter.php b/src/SearchRequest/Attribute/SearchParameter.php index 45eabf1..ebcf943 100644 --- a/src/SearchRequest/Attribute/SearchParameter.php +++ b/src/SearchRequest/Attribute/SearchParameter.php @@ -17,4 +17,9 @@ abstract class SearchParameter { { return is_array($this->source) ? $this->source : [ $this->source ]; } + + public function getParameters() : array + { + return array_filter((array) $this->parameter); + } } \ No newline at end of file diff --git a/src/SearchRequest/Attribute/SearchWhere.php b/src/SearchRequest/Attribute/SearchWhere.php index b14a83e..b5570e2 100644 --- a/src/SearchRequest/Attribute/SearchWhere.php +++ b/src/SearchRequest/Attribute/SearchWhere.php @@ -8,7 +8,7 @@ use Ulmus\SearchRequest\SearchMethodEnum; class SearchWhere extends SearchParameter { public function __construct( - public ? string $parameter = null, + public null|string|array $parameter = null, public null|string|\Stringable|array $field = null, public bool $toggle = false, public SearchMethodEnum $method = SearchMethodEnum::Where, diff --git a/src/SearchRequest/SearchRequestFromRequestTrait.php b/src/SearchRequest/SearchRequestFromRequestTrait.php index 457f324..c74e383 100644 --- a/src/SearchRequest/SearchRequestFromRequestTrait.php +++ b/src/SearchRequest/SearchRequestFromRequestTrait.php @@ -93,24 +93,28 @@ trait SearchRequestFromRequestTrait protected function getValueFromSource(RequestInterface $request, string $propertyName, SearchParameter $attribute) : mixed { - $queryParamName = $attribute->parameter ?? $propertyName; + $queryParamName = $attribute->getParameters() ?? [ $propertyName ]; foreach($attribute->getSources() as $source) { switch($source) { case PropertyValueSource::QueryParams: $queryParams = new \ArrayObject(array_filter($request->getQueryParams(), function($i) { return ! is_null($i) && $i !== ""; })); - if ($queryParams->offsetExists($queryParamName)) { - return $queryParams[$queryParamName]; + foreach($queryParamName as $param) { + if ($queryParams->offsetExists($param)) { + return $queryParams[$param]; + } } break; case PropertyValueSource::RequestAttribute: - $fromAttribute = $request->getAttribute($queryParamName, null); + foreach($queryParamName as $param) { + $fromAttribute = $request->getAttribute($param, null); - if ($fromAttribute !== null) { - return $fromAttribute; + if ($fromAttribute !== null) { + return $fromAttribute; + } } break;