- WIP on attributes ; on testing phase
This commit is contained in:
		
							parent
							
								
									5295a335b3
								
							
						
					
					
						commit
						e6d0279c1a
					
				| @ -6,9 +6,9 @@ class Join implements \Notes\Annotation { | |||||||
| 
 | 
 | ||||||
|     public string $type; |     public string $type; | ||||||
|      |      | ||||||
|     public /*string|Stringable*/ $key; |     public string|Stringable $key; | ||||||
|      |      | ||||||
|     public /*string|Stringable*/ $foreignKey; |     public string|Stringable $foreignKey; | ||||||
|      |      | ||||||
|     public string $entity; |     public string $entity; | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								src/Attribute/Attribute.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Attribute/Attribute.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute; | ||||||
|  | 
 | ||||||
|  | use Ulmus\Common\EntityField; | ||||||
|  | 
 | ||||||
|  | class Attribute | ||||||
|  | { | ||||||
|  |     public static function handleArrayField(null|\Stringable|string|array $field) : mixed | ||||||
|  |     { | ||||||
|  |         if ( is_array($field) ) { | ||||||
|  |             $class = array_shift($field); | ||||||
|  | 
 | ||||||
|  |             return $class::field(...$field); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return $field; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								src/Attribute/Obj/Collation.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Attribute/Obj/Collation.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Obj; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_CLASS)]
 | ||||||
|  | class Collation { | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								src/Attribute/Obj/Method.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Attribute/Obj/Method.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Obj; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_CLASS)]
 | ||||||
|  | class Method { | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								src/Attribute/Obj/Table.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/Attribute/Obj/Table.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Obj; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_CLASS)]
 | ||||||
|  | class Table { | ||||||
|  |     public function __construct( | ||||||
|  |         public string $name, | ||||||
|  |         public ? string $database = null, | ||||||
|  |         public ? string $schema = null, | ||||||
|  |         public ? string $adapter = null, | ||||||
|  |         public ? string $engine = null, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/Attribute/Property/Field.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Attribute/Property/Field.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Field { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = null, | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Bigint.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Bigint.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Bigint extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "bigint", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Blob.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Blob.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Blob extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "blob", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								src/Attribute/Property/Field/CreatedAt.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Attribute/Property/Field/CreatedAt.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class CreatedAt extends \Ulmus\Attribute\Property\Field { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "timestamp", | ||||||
|  |         public array $attributes = [ | ||||||
|  |             'default' => "CURRENT_TIMESTAMP", | ||||||
|  |         ], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								src/Attribute/Property/Field/Date.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/Attribute/Property/Field/Date.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Date extends \Ulmus\Attribute\Property\Field { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "date", | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								src/Attribute/Property/Field/Datetime.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/Attribute/Property/Field/Datetime.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Datetime extends \Ulmus\Attribute\Property\Field { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "datetime", | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/Attribute/Property/Field/ForeignKey.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/Attribute/Property/Field/ForeignKey.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Since we need consistancy between the declaration of our ID and FK fields, it | ||||||
|  |  * was decided to extend the PK class instead of Field for this case. | ||||||
|  |  */ | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class ForeignKey extends PrimaryKey { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = 'bigint', | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [ | ||||||
|  |             'primary_key' => false, | ||||||
|  |             'auto_increment' => false | ||||||
|  |         ], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								src/Attribute/Property/Field/Id.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/Attribute/Property/Field/Id.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Id extends \Ulmus\Attribute\Property\Field { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = 'bigint', | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [ | ||||||
|  |             'unsigned' => true, | ||||||
|  |             'auto_increment' => true, | ||||||
|  |             'primary_key' => true, | ||||||
|  |         ], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Longblob.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Longblob.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Longblob extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "longblob", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | }  | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Longtext.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Longtext.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Longtext extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "longtext", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Mediumblob.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Mediumblob.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Mediumblob extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "mediumblob", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Mediumtext.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Mediumtext.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Mediumtext extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "mediumtext", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								src/Attribute/Property/Field/PrimaryKey.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/Attribute/Property/Field/PrimaryKey.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class PrimaryKey extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = 'bigint', | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [ | ||||||
|  |             'primary_key' => true, | ||||||
|  |         ], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Text.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Text.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Text extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "text", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								src/Attribute/Property/Field/Time.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Attribute/Property/Field/Time.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Tinyblob.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Tinyblob.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Blob extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "tinyblob", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Tinyint.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Tinyint.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Tinyint extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "tinyint", | ||||||
|  |         public ? int $length = null, | ||||||
|  |         public ? int $precision = null, | ||||||
|  |         public array $attributes = [], | ||||||
|  |         public bool $nullable = false, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								src/Attribute/Property/Field/UpdatedAt.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Attribute/Property/Field/UpdatedAt.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Field; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class UpdatedAt extends \Ulmus\Attribute\Property\Field | ||||||
|  | { | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $name = null, | ||||||
|  |         public ? string $type = "timestamp", | ||||||
|  |         public array $attributes = [ | ||||||
|  |             'update' => "CURRENT_TIMESTAMP", | ||||||
|  |             'default' => null, | ||||||
|  |         ], | ||||||
|  |         public bool $nullable = true, | ||||||
|  |         public mixed $default = null, | ||||||
|  |         public bool $readonly = false, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								src/Attribute/Property/Filter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Attribute/Property/Filter.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class Filter { | ||||||
|  |     public function __construct( | ||||||
|  |         public string $method = "" | ||||||
|  |     ) | ||||||
|  |     {} | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/Attribute/Property/FilterJoin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Attribute/Property/FilterJoin.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class FilterJoin { | ||||||
|  |     public function __construct( | ||||||
|  |         public string $method = "" | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								src/Attribute/Property/GroupBy.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Attribute/Property/GroupBy.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class GroupBy { | ||||||
|  | 
 | ||||||
|  |     public array $fields = []; | ||||||
|  | 
 | ||||||
|  |     public function __construct(...$field) | ||||||
|  |     { | ||||||
|  |         if ( $field ) { | ||||||
|  |             $this->fields = $field; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								src/Attribute/Property/Having.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/Attribute/Property/Having.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class Having extends Where {} | ||||||
							
								
								
									
										19
									
								
								src/Attribute/Property/Join.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Attribute/Property/Join.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | use Ulmus\Attribute\Attribute; | ||||||
|  | 
 | ||||||
|  | #[\Attribute]
 | ||||||
|  | class Join { | ||||||
|  |     public function __construct( | ||||||
|  |         public string $type, | ||||||
|  |         public null|string|\Stringable $key  = null, | ||||||
|  |         public null|string|\Stringable $foreignKey = null, | ||||||
|  |         public null|string $entity = null, | ||||||
|  |         public null|string $alias = null, | ||||||
|  |     ) { | ||||||
|  |         $this->key = Attribute::handleArrayField($this->key); | ||||||
|  |         $this->foreignKey = Attribute::handleArrayField($this->foreignKey); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								src/Attribute/Property/On.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/Attribute/Property/On.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class On extends Where {} | ||||||
							
								
								
									
										19
									
								
								src/Attribute/Property/OrWhere.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Attribute/Property/OrWhere.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | use Ulmus\Attribute\Attribute; | ||||||
|  | use Ulmus\Query; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class OrWhere extends Where { | ||||||
|  |     public function __construct( | ||||||
|  |         public string|\Stringable|array $field, | ||||||
|  |         public mixed $value = null, | ||||||
|  |         public null|string $operator = null, | ||||||
|  |         public null|string $condition = Query\Where::CONDITION_OR, | ||||||
|  |     ) { | ||||||
|  | 
 | ||||||
|  |         $this->key = Attribute::handleArrayField($this->key); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								src/Attribute/Property/OrderBy.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Attribute/Property/OrderBy.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | use Ulmus\Attribute\Attribute; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class OrderBy { | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         public string|\Stringable|array $field, | ||||||
|  |         public string $order = "ASC", | ||||||
|  |     ) { | ||||||
|  |         $this->field = Attribute::handleArrayField($this->field); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								src/Attribute/Property/Relation.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/Attribute/Property/Relation.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | use Ulmus\Attribute\Attribute; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Relation { | ||||||
|  |     public function __construct( | ||||||
|  |         public string $type, | ||||||
|  |         public \Stringable|string|array $key = "", | ||||||
|  |         public null|\Closure $generateKey = null, | ||||||
|  |         public null|\Stringable|string|array $foreignKey = null, | ||||||
|  |         public null|\Stringable|string|array $foreignField = null, | ||||||
|  |         public array $foreignKeys = [], | ||||||
|  |         public null|string $bridge = null, | ||||||
|  |         public null|\Stringable|string|array $bridgeKey = null, | ||||||
|  |         public null|\Stringable|string|array $bridgeField = null, | ||||||
|  |         public null|\Stringable|string|array $bridgeForeignKey = null, | ||||||
|  |         public null|\Stringable|string|array $field = null, | ||||||
|  |         public null|string $entity = null, | ||||||
|  |         public null|string $join = null, | ||||||
|  |         public string $function = "loadAll", | ||||||
|  |     ) { | ||||||
|  |         $this->key = Attribute::handleArrayField($this->key); | ||||||
|  |         $this->foreignKey = Attribute::handleArrayField($this->foreignKey); | ||||||
|  |         $this->foreignField = Attribute::handleArrayField($this->foreignField); | ||||||
|  |         $this->bridgeKey = Attribute::handleArrayField($this->bridgeKey); | ||||||
|  |         $this->bridgeField = Attribute::handleArrayField($this->bridgeField); | ||||||
|  |         $this->bridgeForeignKey = Attribute::handleArrayField($this->bridgeForeignKey); | ||||||
|  |         $this->field = Attribute::handleArrayField($this->field); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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 (bool) $this->bridge; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								src/Attribute/Property/Relation/Ignore.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/Attribute/Property/Relation/Ignore.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property\Relation; | ||||||
|  | 
 | ||||||
|  | #[\Attribute]
 | ||||||
|  | class Ignore {} | ||||||
							
								
								
									
										13
									
								
								src/Attribute/Property/Virtual.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/Attribute/Property/Virtual.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY)]
 | ||||||
|  | class Virtual extends Field { | ||||||
|  | 
 | ||||||
|  |     public bool $readonly = true; | ||||||
|  | 
 | ||||||
|  |     public function __construct( | ||||||
|  |         public ? string $method = null, | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Where.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Where.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | use Ulmus\Attribute\Attribute; | ||||||
|  | use Ulmus\Query; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class Where { | ||||||
|  |     public function __construct( | ||||||
|  |         public string|\Stringable|array $field, | ||||||
|  |         public mixed $value = null, | ||||||
|  |         public string $operator = Query\Where::OPERATOR_EQUAL, | ||||||
|  |         public string $condition = Query\Where::CONDITION_AND, | ||||||
|  |     ) { | ||||||
|  |         $this->field = Attribute::handleArrayField($field); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								src/Attribute/Property/WithJoin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Attribute/Property/WithJoin.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace Ulmus\Attribute\Property; | ||||||
|  | 
 | ||||||
|  | #[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
 | ||||||
|  | class WithJoin { | ||||||
|  |     public function __construct( | ||||||
|  |         array $joins = [] | ||||||
|  |     ) {} | ||||||
|  | } | ||||||
| @ -3,6 +3,7 @@ | |||||||
| namespace Ulmus\Common; | namespace Ulmus\Common; | ||||||
| 
 | 
 | ||||||
| use Ulmus\Annotation\Annotation; | use Ulmus\Annotation\Annotation; | ||||||
|  | use Ulmus\Attribute; | ||||||
| use Ulmus\Migration\FieldDefinition; | use Ulmus\Migration\FieldDefinition; | ||||||
| use Ulmus\Ulmus, | use Ulmus\Ulmus, | ||||||
|     Ulmus\Adapter\AdapterInterface, |     Ulmus\Adapter\AdapterInterface, | ||||||
| @ -29,7 +30,7 @@ class EntityField implements WhereRawParameter | |||||||
| 
 | 
 | ||||||
|     public function name($useAlias = true) : string |     public function name($useAlias = true) : string | ||||||
|     { |     { | ||||||
|         $name = $this->entityResolver->searchFieldAnnotation($this->name, new Field() )->name ?? $this->name; |         $name = $this->entityResolver->searchFieldAnnotation($this->name, [ Attribute\Property\Field::class, Field::class ] )->name ?? $this->name; | ||||||
|          |          | ||||||
|         $name = $this->entityResolver->databaseAdapter()->adapter()->escapeIdentifier($name, AdapterInterface::IDENTIFIER_FIELD); |         $name = $this->entityResolver->databaseAdapter()->adapter()->escapeIdentifier($name, AdapterInterface::IDENTIFIER_FIELD); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,11 +2,13 @@ | |||||||
| 
 | 
 | ||||||
| namespace Ulmus\Common; | namespace Ulmus\Common; | ||||||
| 
 | 
 | ||||||
|  | use Psr\SimpleCache\CacheInterface; | ||||||
| use Ulmus\Ulmus, | use Ulmus\Ulmus, | ||||||
|     Ulmus\Annotation\Classes\Table, |     Ulmus\Annotation\Classes\Table, | ||||||
|     Ulmus\Annotation\Property\Field, |     Ulmus\Annotation\Property\Field, | ||||||
|     Ulmus\Annotation\Property\Virtual, |     Ulmus\Annotation\Property\Virtual, | ||||||
|     Ulmus\Annotation\Property\Relation; |     Ulmus\Annotation\Property\Relation, | ||||||
|  |     Ulmus\Attribute; | ||||||
| 
 | 
 | ||||||
| use Notes\Annotation; | use Notes\Annotation; | ||||||
| 
 | 
 | ||||||
| @ -32,12 +34,12 @@ class EntityResolver { | |||||||
|      |      | ||||||
|     protected array $fieldList = []; |     protected array $fieldList = []; | ||||||
| 
 | 
 | ||||||
|     public function __construct(string $entityClass) |     public function __construct(string $entityClass, ? CacheInterface $cache = null) | ||||||
|     { |     { | ||||||
|         $this->entityClass = $entityClass; |         $this->entityClass = $entityClass; | ||||||
| 
 | 
 | ||||||
|         list($this->uses, $this->class, $this->methods, $this->properties) = array_values( |         list($this->uses, $this->class, $this->methods, $this->properties) = array_values( | ||||||
|             ObjectReflection::fromClass($entityClass)->read() |             ObjectReflection::fromClass($entityClass, $cache)->read() | ||||||
|         ); |         ); | ||||||
|          |          | ||||||
|         $this->resolveAnnotations(); |         $this->resolveAnnotations(); | ||||||
| @ -57,14 +59,28 @@ class EntityResolver { | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function searchField($name) : null|array | ||||||
|  |     { | ||||||
|  |         try{ | ||||||
|  |             return $this->field($name, self::KEY_ENTITY_NAME, false) ?: $this->field($name, self::KEY_COLUMN_NAME, false); | ||||||
|  |         } | ||||||
|  |         catch(\Throwable $e) { | ||||||
|  |             if ( $throwException) { | ||||||
|  |                 throw new \InvalidArgumentException("Can't find entity field's column named `$name` from entity {$this->entityClass}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function fieldList($fieldKey = self::KEY_ENTITY_NAME, bool $skipVirtual = false) : array |     public function fieldList($fieldKey = self::KEY_ENTITY_NAME, bool $skipVirtual = false) : array | ||||||
|     { |     { | ||||||
|         $fieldList = []; |         $fieldList = []; | ||||||
|          |          | ||||||
|         foreach($this->properties as $item) { |         foreach($this->properties as $item) { | ||||||
|             foreach($item['tags'] ?? [] as $tag) { |             foreach($item['tags'] ?? [] as $tag) { | ||||||
|                 if ( $tag['object'] instanceof Field ) { |                 if ( $tag['object'] instanceof Field or $tag['object'] instanceof Attribute\Property\Field ) { | ||||||
|                     if ( $skipVirtual && ($tag['object'] instanceof Virtual )) { |                     if ( $skipVirtual && ($tag['object'] instanceof Virtual or $tag['object'] instanceof Attribute\Property\Virtual )) { | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -101,7 +117,7 @@ class EntityResolver { | |||||||
|         try{ |         try{ | ||||||
|             if ( null !== ( $this->properties[$name] ?? null ) ) { |             if ( null !== ( $this->properties[$name] ?? null ) ) { | ||||||
|                 foreach($this->properties[$name]['tags'] ?? [] as $tag) { |                 foreach($this->properties[$name]['tags'] ?? [] as $tag) { | ||||||
|                     if ( $tag['object'] instanceof Relation ) { |                     if ( $tag['object'] instanceof Relation or $tag['object'] instanceof Attribute\Property\Relation ) { | ||||||
|                         return $this->properties[$name]; |                         return $this->properties[$name]; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -118,22 +134,25 @@ class EntityResolver { | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     public function searchFieldAnnotation(string $field, Annotation $annotationType, bool $caseSensitive = true) : ? Annotation |     public function searchFieldAnnotation(string $field, array|object|string $annotationType, bool $caseSensitive = true) : ? object | ||||||
|     { |     { | ||||||
|         $found = $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive); |         return $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive)[0] ?? null; | ||||||
|         return $found ? $found[0] : null; |  | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     public function searchFieldAnnotationList(string $field, Annotation $annotationType, bool $caseSensitive = true) : array |     public function searchFieldAnnotationList(string $field, array|object|string $annotationType, bool $caseSensitive = true) : array | ||||||
|     { |     { | ||||||
|         $list = []; |         $list = []; | ||||||
| 
 | 
 | ||||||
|         $search = $caseSensitive ? $this->properties : array_change_key_case($this->properties, \CASE_LOWER); |         $search = $caseSensitive ? $this->properties : array_change_key_case($this->properties, \CASE_LOWER); | ||||||
| 
 | 
 | ||||||
|  |         $annotations = is_array($annotationType) ? $annotationType : [ $annotationType ]; | ||||||
|  | 
 | ||||||
|         if ( null !== ( $search[$field] ?? null ) ) { |         if ( null !== ( $search[$field] ?? null ) ) { | ||||||
|             foreach($search[$field]['tags'] ?? [] as $tag) { |             foreach($search[$field]['tags'] ?? [] as $tag) { | ||||||
|                 if ( $tag['object'] instanceof $annotationType ) { |                 foreach($annotations as $annotation) { | ||||||
|                     $list[] = $tag['object']; |                     if ( $tag['object'] instanceof $annotation ) { | ||||||
|  |                         $list[] = $tag['object']; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -154,9 +173,9 @@ class EntityResolver { | |||||||
|         return $table->name ?? ""; |         return $table->name ?? ""; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function tableAnnotation($required = false) : Table |     public function tableAnnotation($required = false) : Table|Attribute\Obj\Table | ||||||
|     { |     { | ||||||
|         if ( null === $table = $this->getAnnotationFromClassname( Table::class ) ) { |         if ( null === $table = $this->getTableAttribute() ) { | ||||||
|             if ($required) { |             if ($required) { | ||||||
|                 throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation"); |                 throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation"); | ||||||
|             } |             } | ||||||
| @ -172,7 +191,7 @@ class EntityResolver { | |||||||
| 
 | 
 | ||||||
|     public function sqlAdapter() : \Ulmus\ConnectionAdapter |     public function sqlAdapter() : \Ulmus\ConnectionAdapter | ||||||
|     { |     { | ||||||
|         if ( null !== $table = $this->getAnnotationFromClassname( Table::class ) ) { |         if ( null !== $table = $this->getTableAttribute() ) { | ||||||
|             if ( $table->adapter ?? null ) { |             if ( $table->adapter ?? null ) { | ||||||
|                 if ( null === ( $adapter = \Ulmus\Ulmus::$registeredAdapters[$table->adapter] ?? null ) ) { |                 if ( null === ( $adapter = \Ulmus\Ulmus::$registeredAdapters[$table->adapter] ?? null ) ) { | ||||||
|                     throw new \Exception("Requested database adapter `{$table->adapter}` is not registered."); |                     throw new \Exception("Requested database adapter `{$table->adapter}` is not registered."); | ||||||
| @ -196,7 +215,7 @@ class EntityResolver { | |||||||
| 
 | 
 | ||||||
|     public function schemaName(bool $required = false) : ? string |     public function schemaName(bool $required = false) : ? string | ||||||
|     { |     { | ||||||
|         if ( null === $table = $this->getAnnotationFromClassname( Table::class ) ) { |         if ( null === $table = $this->getTableAttribute() ) { | ||||||
|             throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation"); |             throw new \LogicException("Your entity {$this->entityClass} seems to be missing a @Table() annotation"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -210,7 +229,8 @@ class EntityResolver { | |||||||
|     public function getPrimaryKeyField() : ? array |     public function getPrimaryKeyField() : ? array | ||||||
|     { |     { | ||||||
|         foreach($this->fieldList() as $key => $value) { |         foreach($this->fieldList() as $key => $value) { | ||||||
|             if ( null !== ( $field = $this->searchFieldAnnotation($key, new Field() ) ) ) { |             $field = $this->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]); | ||||||
|  |             if ( null !== $field ) { | ||||||
|                 if ( false !== ( $field->attributes['primary_key'] ?? false ) ) { |                 if ( false !== ( $field->attributes['primary_key'] ?? false ) ) { | ||||||
|                     return [ $key => $field ]; |                     return [ $key => $field ]; | ||||||
|                 } |                 } | ||||||
| @ -230,13 +250,17 @@ class EntityResolver { | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     protected function getTableAttribute() | ||||||
|  |     { | ||||||
|  |         return $this->getAnnotationFromClassname(Attribute\Obj\Table::class, false) ?: $this->getAnnotationFromClassname( Table::class ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Transform an annotation into it's object's counterpart |      * Transform an annotation into it's object's counterpart | ||||||
|      */ |      */ | ||||||
|     public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object |     public function getAnnotationFromClassname(string $className, bool $throwError = true) : ? object | ||||||
|     { |     { | ||||||
|         if ( $name = $this->uses[$className] ?? false ) { |         if ( $name = $this->uses[$className] ?? false ) { | ||||||
| 
 |  | ||||||
|             foreach(array_reverse($this->class['tags']) as $item) { |             foreach(array_reverse($this->class['tags']) as $item) { | ||||||
|                 if ( $item['tag'] === $name ) { |                 if ( $item['tag'] === $name ) { | ||||||
|                     return $this->instanciateAnnotationObject($item); |                     return $this->instanciateAnnotationObject($item); | ||||||
| @ -270,18 +294,23 @@ class EntityResolver { | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function instanciateAnnotationObject(array $tagDefinition) : Annotation |     public function instanciateAnnotationObject(array|\ReflectionAttribute $tagDefinition) : object | ||||||
|     { |     { | ||||||
|         $arguments = $this->extractArguments($tagDefinition['arguments']); |         if ($tagDefinition instanceof \ReflectionAttribute) { | ||||||
| 
 |             $obj = $tagDefinition->newInstance(); | ||||||
|         if ( false === $class = array_search($tagDefinition['tag'], $this->uses) ) { |  | ||||||
|             throw new \InvalidArgumentException("Annotation class `{$tagDefinition['tag']}` was not found within {$this->entityClass} uses statement (or it's children / traits)"); |  | ||||||
|         } |         } | ||||||
|  |         else { | ||||||
|  |             $arguments = $this->extractArguments($tagDefinition['arguments']); | ||||||
| 
 | 
 | ||||||
|         $obj = new $class(... $arguments['constructor']); |             if (false === $class = array_search($tagDefinition['tag'], $this->uses)) { | ||||||
|  |                 throw new \InvalidArgumentException("Annotation class `{$tagDefinition['tag']}` was not found within {$this->entityClass} uses statement (or it's children / traits)"); | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|         foreach($arguments['setter'] as $key => $value) { |             $obj = new $class(... $arguments['constructor']); | ||||||
|             $obj->$key = $value; | 
 | ||||||
|  |             foreach ($arguments['setter'] as $key => $value) { | ||||||
|  |                 $obj->$key = $value; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $obj; |         return $obj; | ||||||
| @ -309,18 +338,18 @@ class EntityResolver { | |||||||
|     protected function resolveAnnotations() |     protected function resolveAnnotations() | ||||||
|     { |     { | ||||||
|         foreach($this->class['tags'] as &$tag) { |         foreach($this->class['tags'] as &$tag) { | ||||||
|             $tag['object'] = $this->instanciateAnnotationObject($tag); |             $tag['object'] ??= $this->instanciateAnnotationObject($tag); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         foreach($this->properties as &$property) { |         foreach($this->properties as &$property) { | ||||||
|             foreach($property['tags'] as &$tag){ |             foreach($property['tags'] as &$tag){ | ||||||
|                 $tag['object'] = $this->instanciateAnnotationObject($tag); |                 $tag['object'] ??= $this->instanciateAnnotationObject($tag); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         foreach($this->methods as &$method) { |         foreach($this->methods as &$method) { | ||||||
|             foreach($method['tags'] as &$tag){ |             foreach($method['tags'] as &$tag){ | ||||||
|                 $tag['object'] = $this->instanciateAnnotationObject($tag); |                 $tag['object'] ??= $this->instanciateAnnotationObject($tag); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -64,7 +64,7 @@ class ConnectionAdapter | |||||||
|      |      | ||||||
|     public function pdo() : PdoObject |     public function pdo() : PdoObject | ||||||
|     { |     { | ||||||
|         return $this->pdo ?? $this->pdo = $this->connect()->pdo; |         return $this->pdo ?? $this->connect()->pdo; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function connector() : object |     public function connector() : object | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ trait EntityTrait { | |||||||
|             elseif ( EntityField::isScalarType($field['type']) ) { |             elseif ( EntityField::isScalarType($field['type']) ) { | ||||||
| 
 | 
 | ||||||
|                 if ( $field['type'] === 'string' ) { |                 if ( $field['type'] === 'string' ) { | ||||||
|                     $annotation = $entityResolver->searchFieldAnnotation($field['name'], new Field() ); |                     $annotation = $entityResolver->searchFieldAnnotation($field['name'], [ Attribute\Property\Field::class, Field::class ] ); | ||||||
| 
 | 
 | ||||||
|                     if ( $annotation->length ?? null ) { |                     if ( $annotation->length ?? null ) { | ||||||
|                         $value = mb_substr($value, 0, $annotation->length); |                         $value = mb_substr($value, 0, $annotation->length); | ||||||
| @ -90,7 +90,6 @@ trait EntityTrait { | |||||||
|                 } |                 } | ||||||
|                 catch(\Error $e) { |                 catch(\Error $e) { | ||||||
|                     $f = $field['type']; |                     $f = $field['type']; | ||||||
|                     dump($f, $f::from($value)); |  | ||||||
|                     throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field['name'])); |                     throw new \Error(sprintf("%s for class '%s' on field '%s'", $e->getMessage(), get_class($this), $field['name'])); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @ -126,17 +125,11 @@ trait EntityTrait { | |||||||
|         return $this; |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function fromArray(iterable $dataset) : self |     public function fromArray(iterable $dataset) : self | ||||||
|     { |     { | ||||||
|         return $this->entityFillFromDataset($dataset); |         return $this->entityFillFromDataset($dataset); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array |     public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array | ||||||
|     { |     { | ||||||
|         if ( $returnSource ) { |         if ( $returnSource ) { | ||||||
| @ -148,7 +141,7 @@ trait EntityTrait { | |||||||
|         $entityResolver = $this->resolveEntity(); |         $entityResolver = $this->resolveEntity(); | ||||||
| 
 | 
 | ||||||
|         foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) { |         foreach($entityResolver->fieldList(Common\EntityResolver::KEY_ENTITY_NAME, true) as $key => $field) { | ||||||
|             $annotation = $entityResolver->searchFieldAnnotation($key, new Field() ); |             $annotation = $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Field::class, Field::class ]); | ||||||
| 
 | 
 | ||||||
|             if ( isset($this->$key) ) { |             if ( isset($this->$key) ) { | ||||||
|                 $dataset[$annotation->name ?? $key] = static::repository()->adapter->adapter()->writableValue($this->$key); |                 $dataset[$annotation->name ?? $key] = static::repository()->adapter->adapter()->writableValue($this->$key); | ||||||
| @ -161,7 +154,7 @@ trait EntityTrait { | |||||||
|         # @TODO Must fix recursive bug !
 |         # @TODO Must fix recursive bug !
 | ||||||
|         if ($includeRelations) { |         if ($includeRelations) { | ||||||
|             foreach($entityResolver->properties as $name => $field){ |             foreach($entityResolver->properties as $name => $field){ | ||||||
|                 $relation = $entityResolver->searchFieldAnnotation($name, new Relation() ); |                 $relation =  $entityResolver->searchFieldAnnotation($key, [ Attribute\Property\Relation::class. Relation::class ] ); | ||||||
| 
 | 
 | ||||||
|                 if ( $relation && isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) { |                 if ( $relation && isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) { | ||||||
|                     if ( null !== $value = $this->$name ?? null ) { |                     if ( null !== $value = $this->$name ?? null ) { | ||||||
| @ -185,9 +178,6 @@ trait EntityTrait { | |||||||
|         return $dataset; |         return $dataset; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function toArray($includeRelations = false, array $filterFields = null) : array |     public function toArray($includeRelations = false, array $filterFields = null) : array | ||||||
|     { |     { | ||||||
|         $dataset = $this->entityGetDataset($includeRelations); |         $dataset = $this->entityGetDataset($includeRelations); | ||||||
| @ -195,17 +185,11 @@ trait EntityTrait { | |||||||
|         return $filterFields ? array_intersect_key($dataset, array_flip($filterFields)) : $dataset; |         return $filterFields ? array_intersect_key($dataset, array_flip($filterFields)) : $dataset; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function toCollection() : EntityCollection |     public function toCollection() : EntityCollection | ||||||
|     { |     { | ||||||
|         return static::entityCollection([ $this ]); |         return static::entityCollection([ $this ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function isLoaded() : bool |     public function isLoaded() : bool | ||||||
|     { |     { | ||||||
|         if (empty($this->entityLoadedDataset)) { |         if (empty($this->entityLoadedDataset)) { | ||||||
| @ -221,9 +205,6 @@ trait EntityTrait { | |||||||
|         return isset($this->$key); |         return isset($this->$key); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function __get(string $name) |     public function __get(string $name) | ||||||
|     { |     { | ||||||
|         $relation = new Repository\RelationBuilder($this); |         $relation = new Repository\RelationBuilder($this); | ||||||
| @ -235,32 +216,25 @@ trait EntityTrait { | |||||||
|         throw new \Exception(sprintf("[%s] - Undefined variable: %s", static::class, $name)); |         throw new \Exception(sprintf("[%s] - Undefined variable: %s", static::class, $name)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function __isset(string $name) : bool |     public function __isset(string $name) : bool | ||||||
|     { |     { | ||||||
|         #if ( null !== $relation = static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
 |         #if ( null !== $relation = static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
 | ||||||
|         #    return isset($this->{$relation->key});
 |         #    return isset($this->{$relation->key});
 | ||||||
|         #}
 |         #}
 | ||||||
|         if ( $this->isLoaded() && static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) { |         $rel = static::resolveEntity()->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ]); | ||||||
|  | 
 | ||||||
|  |         if ( $this->isLoaded() && $rel ) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return isset($this->$name); |         return isset($this->$name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function __sleep() |     public function __sleep() | ||||||
|     { |     { | ||||||
|         return array_keys($this->resolveEntity()->fieldList()); |         return array_keys($this->resolveEntity()->fieldList()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function __clone() |     public function __clone() | ||||||
|     { |     { | ||||||
|         foreach($this as $prop) { |         foreach($this as $prop) { | ||||||
| @ -274,33 +248,21 @@ trait EntityTrait { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public function jsonSerialize() |     public function jsonSerialize() | ||||||
|     { |     { | ||||||
|         return $this->entityGetDataset(); |         return $this->entityGetDataset(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public static function resolveEntity() : EntityResolver |     public static function resolveEntity() : EntityResolver | ||||||
|     { |     { | ||||||
|         return Ulmus::resolveEntity(static::class); |         return Ulmus::resolveEntity(static::class); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public static function repository(string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository |     public static function repository(string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository | ||||||
|     { |     { | ||||||
|         return Ulmus::repository(static::class, $alias, $adapter); |         return Ulmus::repository(static::class, $alias, $adapter); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public static function entityCollection(...$arguments) : EntityCollection |     public static function entityCollection(...$arguments) : EntityCollection | ||||||
|     { |     { | ||||||
|         $collection = new EntityCollection(...$arguments); |         $collection = new EntityCollection(...$arguments); | ||||||
| @ -309,26 +271,16 @@ trait EntityTrait { | |||||||
|         return $collection; |         return $collection; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public static function queryBuilder() : QueryBuilder |     public static function queryBuilder() : QueryBuilder | ||||||
|     { |     { | ||||||
|         return Ulmus::queryBuilder(static::class); |         return Ulmus::queryBuilder(static::class); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public static function field($name, ? string $alias = Repository::DEFAULT_ALIAS) : EntityField |     public static function field($name, ? string $alias = Repository::DEFAULT_ALIAS) : EntityField | ||||||
|     { |     { | ||||||
| 
 |  | ||||||
|         return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : Repository::DEFAULT_ALIAS, Ulmus::resolveEntity(static::class)); |         return new EntityField(static::class, $name, $alias ? Ulmus::repository(static::class)->adapter->adapter()->escapeIdentifier($alias, Adapter\AdapterInterface::IDENTIFIER_FIELD) : Repository::DEFAULT_ALIAS, Ulmus::resolveEntity(static::class)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * @Ignore |  | ||||||
|      */ |  | ||||||
|     public static function fields(array $fields, ? string $alias = Repository::DEFAULT_ALIAS) : string |     public static function fields(array $fields, ? string $alias = Repository::DEFAULT_ALIAS) : string | ||||||
|     { |     { | ||||||
|         return implode(', ', array_map(function($item) use ($alias){ |         return implode(', ', array_map(function($item) use ($alias){ | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ namespace Ulmus\Migration; | |||||||
| 
 | 
 | ||||||
| use Ulmus\Adapter\AdapterInterface; | use Ulmus\Adapter\AdapterInterface; | ||||||
| use Ulmus\Annotation\Property\Field; | use Ulmus\Annotation\Property\Field; | ||||||
|  | use Ulmus\Attribute; | ||||||
| use Ulmus\Entity; | use Ulmus\Entity; | ||||||
| 
 | 
 | ||||||
| class FieldDefinition { | class FieldDefinition { | ||||||
| @ -40,7 +41,7 @@ class FieldDefinition { | |||||||
|         $this->type = $field->type ?? $data['type']; |         $this->type = $field->type ?? $data['type']; | ||||||
|         $this->length = $field->length ?? null; |         $this->length = $field->length ?? null; | ||||||
|         $this->precision = $field->precision ?? null; |         $this->precision = $field->precision ?? null; | ||||||
|         $this->nullable = isset($field->nullable) ? $field->nullable : $data['nullable']; |         $this->nullable = $data['nullable'] ?: $field->nullable; | ||||||
|         $this->update = $field->attributes['update'] ?? null; |         $this->update = $field->attributes['update'] ?? null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -69,9 +70,9 @@ class FieldDefinition { | |||||||
|         ])); |         ])); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function getFieldTag() : ? Field |     public function getFieldTag() : Field|Attribute\Property\Field|null | ||||||
|     { |     { | ||||||
|         $field = array_filter($this->tags, fn($item) => $item['object'] instanceof Field); |         $field = array_filter($this->tags, fn($item) => $item['object'] instanceof Field || $item['object'] instanceof Attribute\Property\Field); | ||||||
| 
 | 
 | ||||||
|         return array_pop($field)['object']; |         return array_pop($field)['object']; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -2,7 +2,16 @@ | |||||||
| 
 | 
 | ||||||
| namespace Ulmus; | namespace Ulmus; | ||||||
| 
 | 
 | ||||||
| use Ulmus\Annotation\Property\{Field, Where, Having, Relation, Filter, Join, FilterJoin, WithJoin, Relation\Ignore as RelationIgnore}; | use Ulmus\Annotation\Property\{Field, | ||||||
|  |     OrderBy, | ||||||
|  |     Where, | ||||||
|  |     Having, | ||||||
|  |     Relation, | ||||||
|  |     Filter, | ||||||
|  |     Join, | ||||||
|  |     FilterJoin, | ||||||
|  |     WithJoin, | ||||||
|  |     Relation\Ignore as RelationIgnore}; | ||||||
| use Ulmus\Common\EntityResolver; | use Ulmus\Common\EntityResolver; | ||||||
| 
 | 
 | ||||||
| class Repository | class Repository | ||||||
| @ -332,7 +341,7 @@ class Repository | |||||||
|         $dataset = $this->generateDatasetDiff($entity, $oldValues); |         $dataset = $this->generateDatasetDiff($entity, $oldValues); | ||||||
| 
 | 
 | ||||||
|         foreach($dataset as $field => $value) { |         foreach($dataset as $field => $value) { | ||||||
|             if ( false === ( $this->entityResolver->searchFieldAnnotation($field, new Field, false)->readonly ?? false ) ) { |             if ( false === ( $this->entityResolver->searchFieldAnnotation($field, [ Attribute\Property\Field::class, Field::class ], false)->readonly ?? false ) ) { | ||||||
|                 $intersect[$field] = $field; |                 $intersect[$field] = $field; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -367,7 +376,7 @@ class Repository | |||||||
|         $prependField and ($prependField .= "$"); |         $prependField and ($prependField .= "$"); | ||||||
| 
 | 
 | ||||||
|         foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { |         foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { | ||||||
|             if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], new RelationIgnore)) { |             if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) { | ||||||
|                 $this->select(sprintf("%s.$key as {$prependField}{$field['name']}", $this->escapeIdentifier($alias))); |                 $this->select(sprintf("%s.$key as {$prependField}{$field['name']}", $this->escapeIdentifier($alias))); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -380,7 +389,7 @@ class Repository | |||||||
|         $fieldlist = []; |         $fieldlist = []; | ||||||
| 
 | 
 | ||||||
|         foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { |         foreach ($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { | ||||||
|             if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], new RelationIgnore)) { |             if (null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) { | ||||||
|                 $fieldlist[] = $key; |                 $fieldlist[] = $key; | ||||||
|                 $fieldlist[] = $entity::field($field['name'], $this->escapeIdentifier($alias)); |                 $fieldlist[] = $entity::field($field['name'], $this->escapeIdentifier($alias)); | ||||||
|             } |             } | ||||||
| @ -574,7 +583,7 @@ class Repository | |||||||
|         return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value); |         return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function withJoin(/*string|array*/ $fields) : self |     public function withJoin(string|array $fields) : self | ||||||
|     { |     { | ||||||
|         if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) { |         if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) { | ||||||
|             $this->select("{$this->alias}.*"); |             $this->select("{$this->alias}.*"); | ||||||
| @ -582,10 +591,12 @@ class Repository | |||||||
| 
 | 
 | ||||||
|         # @TODO Apply FILTER annotation to this too !
 |         # @TODO Apply FILTER annotation to this too !
 | ||||||
|         foreach(array_filter((array) $fields) as $item) { |         foreach(array_filter((array) $fields) as $item) { | ||||||
|             $annotation = $this->entityResolver->searchFieldAnnotation($item, new Join) ?: |             $annotation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Join::class, Join::class ]) ?: | ||||||
|                 $this->entityResolver->searchFieldAnnotation($item, new Relation); |                 $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class, Relation::class ]); | ||||||
| 
 | 
 | ||||||
|             if (( $annotation instanceof Relation ) && ( $annotation->normalizeType() === 'manytomany' )) { |             $isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation); | ||||||
|  | 
 | ||||||
|  |             if ($isRelation && ( $annotation->normalizeType() === 'manytomany' )) { | ||||||
|                 throw new Exception("Many-to-many relation can not be preloaded within joins."); |                 throw new Exception("Many-to-many relation can not be preloaded within joins."); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -595,10 +606,10 @@ class Repository | |||||||
|                 $entity = $annotation->entity ?? $this->entityResolver->properties[$item]['type']; |                 $entity = $annotation->entity ?? $this->entityResolver->properties[$item]['type']; | ||||||
| 
 | 
 | ||||||
|                 foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { |                 foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { | ||||||
|                     if ( null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], new RelationIgnore) ) { |                     if ( null === $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ]) ) { | ||||||
|                         $escAlias = $this->escapeIdentifier($alias); |                         $escAlias = $this->escapeIdentifier($alias); | ||||||
| 
 | 
 | ||||||
|                         $name = $entity::resolveEntity()->searchFieldAnnotation($field['name'], new Field())->name ?? $field['name']; |                         $name = $entity::resolveEntity()->searchFieldAnnotation($field['name'], [ Attribute\Property\Field::class, Field::class ])->name ?? $field['name']; | ||||||
| 
 | 
 | ||||||
|                         $this->select("$escAlias.$key as $alias\${$name}"); |                         $this->select("$escAlias.$key as $alias\${$name}"); | ||||||
|                     } |                     } | ||||||
| @ -606,17 +617,17 @@ class Repository | |||||||
| 
 | 
 | ||||||
|                 $this->open(); |                 $this->open(); | ||||||
| 
 | 
 | ||||||
|                 foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) { |                 foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ] ) as $condition) { | ||||||
|                     if ( is_object($condition->field) && ( $condition->field->entityClass !== $entity ) ) { |                     if ( is_object($condition->field) && ( $condition->field->entityClass !== $entity ) ) { | ||||||
|                         $this->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); |                         $this->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 foreach($this->entityResolver->searchFieldAnnotationList($item, new Having() ) as $condition) { |                 foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class, Having::class ] ) as $condition) { | ||||||
|                     $this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); |                     $this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 foreach($this->entityResolver->searchFieldAnnotationList($item, new Filter() ) as $filter) { |                 foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Filter::class, Filter::class ] ) as $filter) { | ||||||
|                     call_user_func_array([ $this->entityClass, $filter->method ], [ $this, $item, true ]); |                     call_user_func_array([ $this->entityClass, $filter->method ], [ $this, $item, true ]); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -627,8 +638,7 @@ class Repository | |||||||
|                 $foreignKey = is_string($annotation->foreignKey) ? $entity::field($annotation->foreignKey, $alias) : $annotation->foreignKey; |                 $foreignKey = is_string($annotation->foreignKey) ? $entity::field($annotation->foreignKey, $alias) : $annotation->foreignKey; | ||||||
| 
 | 
 | ||||||
|                 $this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias) { |                 $this->join("LEFT", $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias, function($join) use ($item, $entity, $alias) { | ||||||
| 
 |                     foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ]) as $condition) { | ||||||
|                     foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) { |  | ||||||
|                         if ( ! is_object($condition->field) ) { |                         if ( ! is_object($condition->field) ) { | ||||||
|                             $field = $this->entityClass::field($condition->field); |                             $field = $this->entityClass::field($condition->field); | ||||||
|                         } |                         } | ||||||
| @ -644,7 +654,7 @@ class Repository | |||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     foreach($this->entityResolver->searchFieldAnnotationList($item, new FilterJoin() ) as $filter) { |                     foreach($this->entityResolver->searchFieldAnnotationList($item,  [ Attribute\Property\FilterJoin::class, FilterJoin::class ]) as $filter) { | ||||||
|                         call_user_func_array([ $this->entityClass, $filter->method ], [ $join, $item, true ]); |                         call_user_func_array([ $this->entityClass, $filter->method ], [ $join, $item, true ]); | ||||||
|                     } |                     } | ||||||
|                 }); |                 }); | ||||||
| @ -670,7 +680,7 @@ class Repository | |||||||
| 
 | 
 | ||||||
|         # Apply FILTER annotation to this too !
 |         # Apply FILTER annotation to this too !
 | ||||||
|         foreach(array_filter((array) $fields) as $item) { |         foreach(array_filter((array) $fields) as $item) { | ||||||
|             if ( $relation = $this->entityResolver->searchFieldAnnotation($item, new Relation) ) { |             if ( $relation = $this->entityResolver->searchFieldAnnotation($item, [ Attribute\Property\Relation::class, Relation::class ]) ) { | ||||||
|                 $alias = $relation->alias ?? $item; |                 $alias = $relation->alias ?? $item; | ||||||
| 
 | 
 | ||||||
|                 if ( $relation->isManyToMany() ) { |                 if ( $relation->isManyToMany() ) { | ||||||
| @ -691,11 +701,11 @@ class Repository | |||||||
| 
 | 
 | ||||||
|                 #  $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true);
 |                 #  $relation->isManyToMany() and $repository->selectJsonEntity($relation->bridge, $relation->bridgeField, true);
 | ||||||
| 
 | 
 | ||||||
|                 foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) { |                 foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Where::class, Where::class ]) as $condition) { | ||||||
|                     $repository->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); |                     $repository->where(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 foreach($this->entityResolver->searchFieldAnnotationList($item, new Having() ) as $condition) { |                 foreach($this->entityResolver->searchFieldAnnotationList($item, [ Attribute\Property\Having::class, Having::class ] ) as $condition) { | ||||||
|                     $repository->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); |                     $repository->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -722,9 +732,9 @@ class Repository | |||||||
|     public function loadCollectionRelation(EntityCollection $collection, array|string $fields) : void |     public function loadCollectionRelation(EntityCollection $collection, array|string $fields) : void | ||||||
|     { |     { | ||||||
|         foreach ((array)$fields as $name) { |         foreach ((array)$fields as $name) { | ||||||
|             if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, new Annotation\Property\Relation()))) { |             if (null !== ($relation = $this->entityResolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ))) { | ||||||
|                 $order = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\OrderBy()); |                 $order = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ]); | ||||||
|                 $where = $this->entityResolver->searchFieldAnnotationList($name, new Annotation\Property\Where()); |                 $where = $this->entityResolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ]); | ||||||
| 
 | 
 | ||||||
|                 $baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type']; |                 $baseEntity = $relation->entity ?? $relation->bridge ?? $this->entityResolver->properties[$name]['type']; | ||||||
|                 $baseEntityResolver = $baseEntity::resolveEntity(); |                 $baseEntityResolver = $baseEntity::resolveEntity(); | ||||||
| @ -735,7 +745,7 @@ class Repository | |||||||
|                 $repository = $baseEntity::repository(); |                 $repository = $baseEntity::repository(); | ||||||
| 
 | 
 | ||||||
|                 foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { |                 foreach ($baseEntityResolver->fieldList(Common\EntityResolver::KEY_COLUMN_NAME, true) as $key => $field) { | ||||||
|                     if (null === $baseEntityResolver->searchFieldAnnotation($field['name'], new RelationIgnore)) { |                     if (null === $baseEntityResolver->searchFieldAnnotation($field['name'], [ Attribute\Property\Relation\Ignore::class, RelationIgnore::class ])) { | ||||||
|                         $repository->select($baseEntityResolver->entityClass::field($key)); |                         $repository->select($baseEntityResolver->entityClass::field($key)); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -2,7 +2,17 @@ | |||||||
| 
 | 
 | ||||||
| namespace Ulmus\Repository; | namespace Ulmus\Repository; | ||||||
| 
 | 
 | ||||||
| use Ulmus\{ Ulmus, Annotation, Query, Common, Common\EntityResolver, Repository, Event, EntityCollection, }; | use Ulmus\{Attribute\Property\Field, | ||||||
|  |     Ulmus, | ||||||
|  |     Annotation, | ||||||
|  |     Attribute, | ||||||
|  |     Query, | ||||||
|  |     Common, | ||||||
|  |     Common\EntityResolver, | ||||||
|  |     Repository, | ||||||
|  |     Event, | ||||||
|  |     EntityCollection}; | ||||||
|  | 
 | ||||||
| use Ulmus\Annotation\Property\{Filter, OrderBy, Relation, Relation\Ignore as RelationIgnore, Where, WithJoin, }; | use Ulmus\Annotation\Property\{Filter, OrderBy, Relation, Relation\Ignore as RelationIgnore, Where, WithJoin, }; | ||||||
| 
 | 
 | ||||||
| use Closure; | use Closure; | ||||||
| @ -15,7 +25,7 @@ class RelationBuilder | |||||||
| 
 | 
 | ||||||
|     protected Repository $repository; |     protected Repository $repository; | ||||||
| 
 | 
 | ||||||
|     protected /*object|string*/ $entity; |     protected object|string $entity; | ||||||
| 
 | 
 | ||||||
|     protected EntityResolver $resolver; |     protected EntityResolver $resolver; | ||||||
| 
 | 
 | ||||||
| @ -27,7 +37,7 @@ class RelationBuilder | |||||||
| 
 | 
 | ||||||
|     protected array $joins; |     protected array $joins; | ||||||
| 
 | 
 | ||||||
|     public function __construct(/*string|object*/ $entity, ? Repository $repository = null) |     public function __construct(string|object $entity, ? Repository $repository = null) | ||||||
|     { |     { | ||||||
|         $this->entity = $entity; |         $this->entity = $entity; | ||||||
|         $this->resolver = $entity::resolveEntity(); |         $this->resolver = $entity::resolveEntity(); | ||||||
| @ -48,7 +58,7 @@ class RelationBuilder | |||||||
|             return $this->resolveRelation($name) ?: $this->resolveVirtual($name) ?: false; |             return $this->resolveRelation($name) ?: $this->resolveVirtual($name) ?: false; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             if ( $relation = $this->resolver->searchFieldAnnotation($name, new Relation() ) ) { |             if ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class , Relation::class ] ) ) { | ||||||
|                 return $this->instanciateEmptyObject($name, $relation); |                 return $this->instanciateEmptyObject($name, $relation); | ||||||
|             } |             } | ||||||
|             elseif ($virtual = $this->resolveVirtual($name)) { |             elseif ($virtual = $this->resolveVirtual($name)) { | ||||||
| @ -59,9 +69,9 @@ class RelationBuilder | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function resolveVirtual(string $name) /* : bool|object|EntityCollection */ |     protected function resolveVirtual(string $name) : bool|object | ||||||
|     { |     { | ||||||
|         if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, new Annotation\Property\Virtual()))) { |         if (null !== ($virtual = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Virtual::class, Annotation\Property\Virtual::class ]))) { | ||||||
|             if ($virtual->closure ?? false) { |             if ($virtual->closure ?? false) { | ||||||
|                 return call_user_func_array($virtual->closure, [ $this->entity ]); |                 return call_user_func_array($virtual->closure, [ $this->entity ]); | ||||||
|             } |             } | ||||||
| @ -72,17 +82,18 @@ class RelationBuilder | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function resolveRelation(string $name) /* : bool|object|EntityCollection */ |     protected function resolveRelation(string $name) : bool|object | ||||||
|     { |     { | ||||||
|         if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, new Relation() ) ) ) { |         if ( null !== ( $relation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Relation::class ] ) ) ) { | ||||||
|             $this->orders = $this->resolver->searchFieldAnnotationList($name, new OrderBy() ); |             $this->orders = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\OrderBy::class, OrderBy::class ] ); | ||||||
|             $this->wheres = $this->resolver->searchFieldAnnotationList($name, new Where() ); |             $this->wheres = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Where::class, Where::class ] ); | ||||||
|             $this->filters = $this->resolver->searchFieldAnnotationList($name, new Filter() ); |             $this->filters = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\Filter::class, Filter::class ] ); | ||||||
|             $this->joins = $this->resolver->searchFieldAnnotationList($name, new WithJoin() ); |             $this->joins = $this->resolver->searchFieldAnnotationList($name, [ Attribute\Property\WithJoin::class, WithJoin::class ] ); | ||||||
| 
 | 
 | ||||||
|             switch( true ) { |             switch( true ) { | ||||||
|                 case $relation->isOneToOne(): |                 case $relation->isOneToOne(): | ||||||
|                     if ( $relation->hasBridge() ) { |                     if ( $relation->hasBridge() ) { | ||||||
|  |                         #dump($name, $relation);
 | ||||||
|                         # @TODO ! dump($this->relationAnnotations($name, $relation));
 |                         # @TODO ! dump($this->relationAnnotations($name, $relation));
 | ||||||
|                     } |                     } | ||||||
|                     else { |                     else { | ||||||
| @ -155,7 +166,7 @@ class RelationBuilder | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function instanciateEmptyEntity(string $name, Relation $relation) : object |     protected function instanciateEmptyEntity(string $name, Relation|Attribute\Property\Relation $relation) : object | ||||||
|     { |     { | ||||||
|         $class = $relation->entity ?? $this->resolver->properties[$name]['type']; |         $class = $relation->entity ?? $this->resolver->properties[$name]['type']; | ||||||
| 
 | 
 | ||||||
| @ -163,7 +174,7 @@ class RelationBuilder | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     protected function instanciateEmptyObject(string $name, Relation $relation) : object |     protected function instanciateEmptyObject(string $name, Relation|Attribute\Property\Relation $relation) : object | ||||||
|     { |     { | ||||||
|         switch( true ) { |         switch( true ) { | ||||||
|             case $relation->isOneToOne(): |             case $relation->isOneToOne(): | ||||||
| @ -181,16 +192,18 @@ class RelationBuilder | |||||||
|         return new $class(); |         return new $class(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected function fetchFromDataset($name, ? array $data = null) /* object|bool */ |     protected function fetchFromDataset($name, ? array $data = null) : object|bool | ||||||
|     { |     { | ||||||
|         $annotation = $this->resolver->searchFieldAnnotation($name, new Annotation\Property\Join) ?: |         $annotation = $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Join::class, Annotation\Property\Join::class ]) ?: | ||||||
|             $this->resolver->searchFieldAnnotation($name, new Annotation\Property\Relation); |             $this->resolver->searchFieldAnnotation($name, [ Attribute\Property\Relation::class, Annotation\Property\Relation::class ]); | ||||||
| 
 | 
 | ||||||
|         if ( $annotation ) { |         if ( $annotation ) { | ||||||
|             $vars = []; |             $vars = []; | ||||||
|             $len = strlen( $name ) + 1; |             $len = strlen( $name ) + 1; | ||||||
| 
 | 
 | ||||||
|             if ( ( $annotation instanceof Relation ) && $annotation->isManyToMany() ) { |             $isRelation = ( $annotation instanceof Relation ) || ($annotation instanceof Attribute\Property\Relation); | ||||||
|  | 
 | ||||||
|  |             if ( $isRelation && $annotation->isManyToMany() ) { | ||||||
|                 $entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity; |                 $entity = $this->relationAnnotations($name, $annotation)['relationRelation']->entity; | ||||||
|             } |             } | ||||||
|             else { |             else { | ||||||
| @ -231,12 +244,12 @@ class RelationBuilder | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function oneToOne(string $name, Relation $relation) : Repository |     public function oneToOne(string $name, Relation|Attribute\Property\Relation $relation) : Repository | ||||||
|     { |     { | ||||||
|         return $this->oneToMany($name, $relation)->limit(1); |         return $this->oneToMany($name, $relation)->limit(1); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function oneToMany(string $name, Relation $relation) : Repository |     public function oneToMany(string $name, Relation|Attribute\Property\Relation $relation) : Repository | ||||||
|     { |     { | ||||||
|         $baseEntity = $relation->entity ?? $this->resolver->properties[$name]['type']; |         $baseEntity = $relation->entity ?? $this->resolver->properties[$name]['type']; | ||||||
| 
 | 
 | ||||||
| @ -249,13 +262,17 @@ class RelationBuilder | |||||||
|         $field = $relation->key; |         $field = $relation->key; | ||||||
| 
 | 
 | ||||||
|         if ($relation->foreignKey) { |         if ($relation->foreignKey) { | ||||||
|             $this->repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity::field($relation->foreignKey), ! is_string($field) && is_callable($field) ? $field($this->entity) : $this->entity->$field ); |            # dump($baseEntity::resolveEntity()->searchField($field));
 | ||||||
|  | 
 | ||||||
|  | #            dump($this->resolver->properties[$name], $field);
 | ||||||
|  |             $value = ! is_string($field) && is_callable($field) ? $field($this->entity) : $this->entity->$field; | ||||||
|  |             $this->repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity::field($relation->foreignKey), $value ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->applyFilter($this->repository, $name); |         return $this->applyFilter($this->repository, $name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function manyToMany(string $name, Relation $relation, ? Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository |     public function manyToMany(string $name, Relation|Attribute\Property\Relation $relation, Relation|Attribute\Property\Relation & $relationRelation = null, bool $selectBridgeField = true) : Repository | ||||||
|     { |     { | ||||||
|         extract($this->relationAnnotations($name, $relation)); |         extract($this->relationAnnotations($name, $relation)); | ||||||
| 
 | 
 | ||||||
| @ -272,7 +289,6 @@ class RelationBuilder | |||||||
| 
 | 
 | ||||||
|             })->where( $this->entity::field($bridgeRelation->foreignKey, $relationAlias), is_string($this->entity) ? $this->entity::field($bridgeRelation->foreignKey) : $this->entity->{$bridgeRelation->foreignKey} ); |             })->where( $this->entity::field($bridgeRelation->foreignKey, $relationAlias), is_string($this->entity) ? $this->entity::field($bridgeRelation->foreignKey) : $this->entity->{$bridgeRelation->foreignKey} ); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         $this->applyWhere(); |         $this->applyWhere(); | ||||||
| 
 | 
 | ||||||
|         $this->applyOrderBy(); |         $this->applyOrderBy(); | ||||||
| @ -284,7 +300,7 @@ class RelationBuilder | |||||||
|         return $this->applyFilter($this->repository, $name); |         return $this->applyFilter($this->repository, $name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static function relationAnnotations(string $name, Relation $relation) : array |     public static function relationAnnotations(string $name, Relation|Attribute\Property\Relation $relation) : array | ||||||
|     { |     { | ||||||
|         if ( $relation->isOneToOne() || $relation->isManyToMany() ) { |         if ( $relation->isOneToOne() || $relation->isManyToMany() ) { | ||||||
|             if ( ! $relation->hasBridge() ) { |             if ( ! $relation->hasBridge() ) { | ||||||
| @ -292,8 +308,8 @@ class RelationBuilder | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             $bridgeEntity = Ulmus::resolveEntity($relation->bridge); |             $bridgeEntity = Ulmus::resolveEntity($relation->bridge); | ||||||
|             $bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, new Relation() ); |             $bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, [ Attribute\Property\Relation::class, Relation::class ]); | ||||||
|             $relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, new Relation() ); |             $relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, [ Attribute\Property\Relation::class, Relation::class ]); | ||||||
| 
 | 
 | ||||||
|             if ($relationRelation === null) { |             if ($relationRelation === null) { | ||||||
|                 throw new \Exception("@Relation annotation not found for field `{$relation->foreignField}` in entity {$relation->bridge}"); |                 throw new \Exception("@Relation annotation not found for field `{$relation->foreignField}` in entity {$relation->bridge}"); | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ namespace Ulmus; | |||||||
| 
 | 
 | ||||||
| use Generator; | use Generator; | ||||||
| 
 | 
 | ||||||
|  | use Psr\SimpleCache\CacheInterface; | ||||||
|  | 
 | ||||||
| abstract class Ulmus | abstract class Ulmus | ||||||
| { | { | ||||||
|     public static string $repositoryClass = "\\Ulmus\\Repository"; |     public static string $repositoryClass = "\\Ulmus\\Repository"; | ||||||
| @ -16,6 +18,8 @@ abstract class Ulmus | |||||||
| 
 | 
 | ||||||
|     public static Entity\ObjectInstanciator $objectInstanciator; |     public static Entity\ObjectInstanciator $objectInstanciator; | ||||||
| 
 | 
 | ||||||
|  |     public static CacheInterface $cache; | ||||||
|  |      | ||||||
|     public static array $resolved = []; |     public static array $resolved = []; | ||||||
| 
 | 
 | ||||||
|     public static function iterateQueryBuilder(Query\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) : Generator |     public static function iterateQueryBuilder(Query\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) : Generator | ||||||
| @ -104,7 +108,7 @@ abstract class Ulmus | |||||||
| 
 | 
 | ||||||
|     public static function resolveEntity(string $entityClass) : Common\EntityResolver |     public static function resolveEntity(string $entityClass) : Common\EntityResolver | ||||||
|     { |     { | ||||||
|         return static::$resolved[$entityClass] ?? static::$resolved[$entityClass] = new Common\EntityResolver($entityClass); |         return static::$resolved[$entityClass] ?? static::$resolved[$entityClass] = new Common\EntityResolver($entityClass, static::$cache); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static function repository(string $entityClass, string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository |     public static function repository(string $entityClass, string $alias = Repository::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) : Repository | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user