Compare commits
	
		
			4 Commits
		
	
	
		
			5295a335b3
			...
			26ffecbb6e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 26ffecbb6e | |||
| 
						 | 
					88e9f048db | ||
| 
						 | 
					70021d829d | ||
| 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 = null,
 | 
				
			||||||
 | 
					        public ? string $database = null,
 | 
				
			||||||
 | 
					        public ? string $schema = null,
 | 
				
			||||||
 | 
					        public ? string $adapter = null,
 | 
				
			||||||
 | 
					        public ? string $engine = null,
 | 
				
			||||||
 | 
					    ) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Field {
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = null,
 | 
				
			||||||
 | 
					        public null|int|string $length = null,
 | 
				
			||||||
 | 
					        public ? int $precision = null,
 | 
				
			||||||
 | 
					        public array $attributes = [],
 | 
				
			||||||
 | 
					        public bool $nullable = false,
 | 
				
			||||||
 | 
					        public mixed $default = null,
 | 
				
			||||||
 | 
					        public bool $readonly = false,
 | 
				
			||||||
 | 
					        public null|int $decimal = null,
 | 
				
			||||||
 | 
					    ) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										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 null|int|string $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/Bit.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Bit.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Bit extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = "bit",
 | 
				
			||||||
 | 
					        public null|int|string $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 null|int|string $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,
 | 
				
			||||||
 | 
					    ) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								src/Attribute/Property/Field/Decimal.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Decimal.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Decimal extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = "decimal",
 | 
				
			||||||
 | 
					        public null|int|string $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/Float.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Float.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Float extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = "float",
 | 
				
			||||||
 | 
					        public null|int|string $length = null,
 | 
				
			||||||
 | 
					        public ? int $precision = null,
 | 
				
			||||||
 | 
					        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 null|int|string $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 null|int|string $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 null|int|string $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 null|int|string $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 null|int|string $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/Mediumint.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Mediumint.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Mediumint extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = "mediumint",
 | 
				
			||||||
 | 
					        public null|int|string $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 null|int|string $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/Numeric.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Numeric.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Numeric extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = "numeric",
 | 
				
			||||||
 | 
					        public null|int|string $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 null|int|string $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/Smallint.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Smallint.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Smallint extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = "smallint",
 | 
				
			||||||
 | 
					        public null|int|string $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/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 null|int|string $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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/Attribute/Property/Field/Timestamp.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Attribute/Property/Field/Timestamp.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Timestamp extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(? string $type = "timestamp", ? int $length = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($type, $length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										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 null|int|string $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 null|int|string $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/Tinytext.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/Attribute/Property/Field/Tinytext.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Attribute\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[\Attribute(\Attribute::TARGET_PROPERTY)]
 | 
				
			||||||
 | 
					class Tinytext extends \Ulmus\Attribute\Property\Field
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public function __construct(
 | 
				
			||||||
 | 
					        public ? string $name = null,
 | 
				
			||||||
 | 
					        public ? string $type = "tinytext",
 | 
				
			||||||
 | 
					        public null|int|string $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|array $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,17 +59,31 @@ 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;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    
 | 
					
 | 
				
			||||||
                    switch($fieldKey) {
 | 
					                    switch($fieldKey) {
 | 
				
			||||||
                        case static::KEY_LC_ENTITY_NAME:
 | 
					                        case static::KEY_LC_ENTITY_NAME:
 | 
				
			||||||
                            $key = strtolower($item['name']);
 | 
					                            $key = strtolower($item['name']);
 | 
				
			||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -40,8 +40,8 @@ trait EntityTrait {
 | 
				
			|||||||
        $entityResolver = $this->resolveEntity();
 | 
					        $entityResolver = $this->resolveEntity();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        foreach($dataset as $key => $value) {
 | 
					        foreach($dataset as $key => $value) {
 | 
				
			||||||
            $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null;
 | 
				
			||||||
            $field ??= $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
 | 
					            $field ??= $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ( $field === null ) {
 | 
					            if ( $field === null ) {
 | 
				
			||||||
@ -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,30 @@ 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_merge(array_keys($this->resolveEntity()->fieldList()), [ 'entityLoadedDataset' ] );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __wakeup()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->resetVirtualProperties();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * @Ignore
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function __clone()
 | 
					    public function __clone()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        foreach($this as $prop) {
 | 
					        foreach($this as $prop) {
 | 
				
			||||||
@ -274,33 +253,21 @@ trait EntityTrait {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    public function jsonSerialize() : mixed
 | 
				
			||||||
     * @Ignore
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    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 +276,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'];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -48,7 +48,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function select($field, bool $distinct = false) : self
 | 
					    public function select(string|\Stringable|array $field, bool $distinct = false) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( null !== ( $select = $this->getFragment(Query\Select::class) ) ) {
 | 
					        if ( null !== ( $select = $this->getFragment(Query\Select::class) ) ) {
 | 
				
			||||||
            $select->add($field);
 | 
					            $select->add($field);
 | 
				
			||||||
@ -195,7 +195,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function where(/* stringable*/ $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
 | 
					    public function where(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        # Empty IN case
 | 
					        # Empty IN case
 | 
				
			||||||
        if ( [] === $value ) {
 | 
					        if ( [] === $value ) {
 | 
				
			||||||
@ -217,12 +217,12 @@ class QueryBuilder implements Query\QueryBuilderInterface
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function notWhere($field, $value, string $operator = Query\Where::CONDITION_AND) : self
 | 
					    public function notWhere(string|\Stringable $field, $value, string $operator = Query\Where::CONDITION_AND) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->where($field, $value, $operator, true);
 | 
					        return $this->where($field, $value, $operator, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function having($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
 | 
					    public function having(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( $this->having ?? false ) {
 | 
					        if ( $this->having ?? false ) {
 | 
				
			||||||
            $having = $this->having;
 | 
					            $having = $this->having;
 | 
				
			||||||
@ -266,7 +266,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orderBy(string $field, ? string $direction = null) : self
 | 
					    public function orderBy(string|\Stringable $field, ? string $direction = null) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
 | 
					        if ( null === $orderBy = $this->getFragment(Query\OrderBy::class) ) {
 | 
				
			||||||
            $orderBy = new Query\OrderBy();
 | 
					            $orderBy = new Query\OrderBy();
 | 
				
			||||||
@ -278,7 +278,7 @@ class QueryBuilder implements Query\QueryBuilderInterface
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function groupBy(string $field, ? string $direction = null) : self
 | 
					    public function groupBy(string|\Stringable $field, ? string $direction = null) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) {
 | 
					        if ( null === $groupBy = $this->getFragment(Query\GroupBy::class) ) {
 | 
				
			||||||
            $groupBy = new Query\GroupBy();
 | 
					            $groupBy = new Query\GroupBy();
 | 
				
			||||||
@ -290,14 +290,14 @@ class QueryBuilder implements Query\QueryBuilderInterface
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function join(string $type, /*string | QueryBuilder*/ $table, $field, $value, bool $outer = false, ? string $alias = null) : self
 | 
					    public function join(string $type, /*string | QueryBuilder*/ $table, mixed $field, mixed $value, bool $outer = false, ? string $alias = null) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->withJoin(...func_get_args());
 | 
					        $this->withJoin(...func_get_args());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function withJoin(string $type, $table, $field, $value, bool $outer = false, ? string $alias = null) : Query\Join
 | 
					    public function withJoin(string $type, $table, mixed $field, mixed $value, bool $outer = false, ? string $alias = null) : Query\Join
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $join = new Query\Join($this);
 | 
					        $join = new Query\Join($this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
@ -307,7 +316,7 @@ class Repository
 | 
				
			|||||||
        $array = array_change_key_case($entity->toArray());
 | 
					        $array = array_change_key_case($entity->toArray());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $dataset = array_change_key_case($entity->entityGetDataset(false, true));
 | 
					        $dataset = array_change_key_case($entity->entityGetDataset(false, true));
 | 
				
			||||||
# dump($array, $dataset);
 | 
					
 | 
				
			||||||
        return array_udiff_assoc($oldValues ? $dataset : $array , $oldValues ? $array : $dataset, function($e1, $e2) {
 | 
					        return array_udiff_assoc($oldValues ? $dataset : $array , $oldValues ? $array : $dataset, function($e1, $e2) {
 | 
				
			||||||
            if ( is_array($e1) ) {
 | 
					            if ( is_array($e1) ) {
 | 
				
			||||||
                if (is_array($e2)) {
 | 
					                if (is_array($e2)) {
 | 
				
			||||||
@ -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));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -455,7 +464,7 @@ class Repository
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function join(string $type, $table, $field, $value, ? string $alias = null, ? callable $callback = null) : self
 | 
					    public function join(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, false, $alias ? $this->escapeIdentifier($alias) : null);
 | 
					        $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, false, $alias ? $this->escapeIdentifier($alias) : null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -466,7 +475,7 @@ class Repository
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function outerJoin(string $type, $table, $field, $value, ? string $alias = null, ? callable $callback = null) : self
 | 
					    public function outerJoin(string $type, $table, string|\Stringable $field, mixed $value, ? string $alias = null, ? callable $callback = null) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, true, $alias ? $this->escapeIdentifier($alias) : null);
 | 
					        $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, true, $alias ? $this->escapeIdentifier($alias) : null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -497,7 +506,7 @@ class Repository
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function groupBy($field) : self
 | 
					    public function groupBy(string|\Stringable $field) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->groupBy($field);
 | 
					        $this->queryBuilder->groupBy($field);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -513,7 +522,7 @@ class Repository
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orderBy($field, ? string $direction = null) : self
 | 
					    public function orderBy(string|\Stringable $field, ? string $direction = null) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->orderBy($field, $direction);
 | 
					        $this->queryBuilder->orderBy($field, $direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -563,7 +572,7 @@ class Repository
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function wherePrimaryKey($value) : self
 | 
					    public function wherePrimaryKey(mixed $value) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( null === $primaryKeyField = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField() ) {
 | 
					        if ( null === $primaryKeyField = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField() ) {
 | 
				
			||||||
            throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'");
 | 
					            throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'");
 | 
				
			||||||
@ -574,18 +583,21 @@ 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}.*");
 | 
					            $select = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true);
 | 
				
			||||||
 | 
					            $this->select($this->entityClass::fields(array_map(fn($f) => $f['object']->name ?? $f['name'], $select)));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # @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 +607,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 +618,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 +639,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 +655,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 +681,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 +702,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 +733,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 +746,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));
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -825,28 +836,28 @@ class Repository
 | 
				
			|||||||
        return Ulmus::datasetQueryBuilder($this->queryBuilder, $this->adapter);
 | 
					        return Ulmus::datasetQueryBuilder($this->queryBuilder, $this->adapter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function runQuery() /* : mixed */
 | 
					    public function runQuery() : mixed
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->finalizeQuery();
 | 
					        $this->finalizeQuery();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Ulmus::runQuery($this->queryBuilder, $this->adapter);
 | 
					        return Ulmus::runQuery($this->queryBuilder, $this->adapter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function runInsertQuery() /* : mixed */
 | 
					    public function runInsertQuery() : mixed
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->finalizeQuery();
 | 
					        $this->finalizeQuery();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Ulmus::runInsertQuery($this->queryBuilder, $this->adapter);
 | 
					        return Ulmus::runInsertQuery($this->queryBuilder, $this->adapter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function runUpdateQuery() /* : mixed */
 | 
					    public function runUpdateQuery() : mixed
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->finalizeQuery();
 | 
					        $this->finalizeQuery();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Ulmus::runUpdateQuery($this->queryBuilder, $this->adapter);
 | 
					        return Ulmus::runUpdateQuery($this->queryBuilder, $this->adapter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function runDeleteQuery() /* : mixed */
 | 
					    public function runDeleteQuery() : mixed
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->finalizeQuery();
 | 
					        $this->finalizeQuery();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -888,7 +899,8 @@ class Repository
 | 
				
			|||||||
    protected function selectSqlQuery() : self
 | 
					    protected function selectSqlQuery() : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
 | 
					        if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
 | 
				
			||||||
            $this->select("{$this->alias}.*");
 | 
					            $fields = $this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME, true);
 | 
				
			||||||
 | 
					            $this->select($this->entityClass::fields(array_map(fn($f) => $f['object']->name ?? $f['name'], $fields)));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ( null === $this->queryBuilder->getFragment(Query\From::class) ) {
 | 
					        if ( null === $this->queryBuilder->getFragment(Query\From::class) ) {
 | 
				
			||||||
 | 
				
			|||||||
@ -25,7 +25,7 @@ trait ConditionTrait
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function where($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
 | 
					    public function where(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->where($field, $value, $operator, $condition);
 | 
					        $this->queryBuilder->where($field, $value, $operator, $condition);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -41,101 +41,101 @@ trait ConditionTrait
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public function and($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
					    public function and(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->where($field, $value, $operator);
 | 
					        return $this->where($field, $value, $operator);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function or($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
					    public function or(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
 | 
					        $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function notWhere($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
					    public function notWhere(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true);
 | 
					        $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orNot($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
 | 
					    public function orNot(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->notWhere($field, $value, $operator, Query\Where::CONDITION_OR, true);
 | 
					        $this->queryBuilder->notWhere($field, $value, $operator, Query\Where::CONDITION_OR, true);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function having($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
 | 
					    public function having(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->having($field, $value, $operator, $condition);
 | 
					        $this->queryBuilder->having($field, $value, $operator, $condition);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orHaving($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
					    public function orHaving(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_OR);
 | 
					        $this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_OR);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function notHaving($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
 | 
					    public function notHaving(string|\Stringable $field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_AND, true);
 | 
					        $this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_AND, true);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orNotHaving($field, $value) : self
 | 
					    public function orNotHaving(string|\Stringable $field, $value) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->having($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true);
 | 
					        $this->queryBuilder->having($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public function in($field, $value, string $operator = Query\Where::COMPARISON_IN) : self
 | 
					    public function in(string|\Stringable $field, $value, string $operator = Query\Where::COMPARISON_IN) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->where($field, $value, $operator);
 | 
					        $this->queryBuilder->where($field, $value, $operator);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orIn($field, $value, string $operator = Query\Where::COMPARISON_IN) : self
 | 
					    public function orIn(string|\Stringable $field, $value, string $operator = Query\Where::COMPARISON_IN) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
 | 
					        $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function notIn($field, $value) : self
 | 
					    public function notIn(string|\Stringable $field, $value) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder->where($field, $value, Query\Where::COMPARISON_IN, true);
 | 
					        $this->queryBuilder->where($field, $value, Query\Where::COMPARISON_IN, true);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orNotIn($field, $value) : self
 | 
					    public function orNotIn(string|\Stringable $field, $value) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->orNot($field, $value, Query\Where::COMPARISON_IN, Query\Where::CONDITION_OR, true);
 | 
					        return $this->orNot($field, $value, Query\Where::COMPARISON_IN, Query\Where::CONDITION_OR, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function like($field, $value) : self
 | 
					    public function like(string|\Stringable $field, $value) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->where($field, $value, Query\Where::OPERATOR_LIKE);
 | 
					        $this->where($field, $value, Query\Where::OPERATOR_LIKE);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function orLike($field, $value) : self
 | 
					    public function orLike(string|\Stringable $field, $value) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->or($field, $value, Query\Where::OPERATOR_LIKE);
 | 
					        $this->or($field, $value, Query\Where::OPERATOR_LIKE);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function notLike($field, $value) : self
 | 
					    public function notLike(string|\Stringable $field, $value) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->notWhere($field, $value, Query\Where::OPERATOR_LIKE);
 | 
					        $this->notWhere($field, $value, Query\Where::OPERATOR_LIKE);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
				
			|||||||
@ -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";
 | 
				
			||||||
@ -13,8 +15,10 @@ abstract class Ulmus
 | 
				
			|||||||
    public static array $registeredAdapters = [];
 | 
					    public static array $registeredAdapters = [];
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public static ConnectionAdapter $defaultAdapter;
 | 
					    public static ConnectionAdapter $defaultAdapter;
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    public static Entity\ObjectInstanciator $objectInstanciator;
 | 
					    public static Entity\ObjectInstanciator $objectInstanciator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static CacheInterface $cache;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public static array $resolved = [];
 | 
					    public static array $resolved = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -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