- Work done on Join and using the @Relation annotation in case there is no join.
- Added some field type (date, Datetime, Time) - Added a new @Filter annotation which allows to filter repository from relation into a method.
This commit is contained in:
		
							parent
							
								
									65de1dd849
								
							
						
					
					
						commit
						e465ecdf32
					
				@ -14,7 +14,7 @@ class Field implements \Ulmus\Annotation\Annotation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public array $attributes = [];
 | 
					    public array $attributes = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public bool $nullable = false;
 | 
					    public bool $nullable;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    public function __construct(? string $type = null, ? int $length = null)
 | 
					    public function __construct(? string $type = null, ? int $length = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/Annotation/Property/Field/Date.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Annotation/Property/Field/Date.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Annotation\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Date extends \Ulmus\Annotation\Property\Field {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(? string $type = "date", ? int $length = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($type, $length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/Annotation/Property/Field/Datetime.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Annotation/Property/Field/Datetime.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Annotation\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Datetime extends \Ulmus\Annotation\Property\Field {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(? string $type = "datetime", ? int $length = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($type, $length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/Annotation/Property/Field/Time.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Annotation/Property/Field/Time.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Annotation\Property\Field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Time extends \Ulmus\Annotation\Property\Field {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(? string $type = "time", ? int $length = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($type, $length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								src/Annotation/Property/Filter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/Annotation/Property/Filter.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Annotation\Property;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Filter implements \Ulmus\Annotation\Annotation {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string $method;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function __construct(string $method = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ( $method !== null ) {
 | 
				
			||||||
 | 
					            $this->method = $method;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/Annotation/Property/Having.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/Annotation/Property/Having.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Annotation\Property;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Having extends Where {}
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/Annotation/Property/On.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/Annotation/Property/On.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Ulmus\Annotation\Property;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class On extends Where {}
 | 
				
			||||||
@ -20,6 +20,8 @@ class Relation implements \Ulmus\Annotation\Annotation {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    public string $entity;
 | 
					    public string $entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public string $join;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public string $function = "loadAll";
 | 
					    public string $function = "loadAll";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct(string $type = null)
 | 
					    public function __construct(string $type = null)
 | 
				
			||||||
@ -44,4 +46,9 @@ class Relation implements \Ulmus\Annotation\Annotation {
 | 
				
			|||||||
        
 | 
					        
 | 
				
			||||||
        return new $e();
 | 
					        return new $e();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function normalizeType() : string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return strtolower(str_replace(['-', '_', ' '], '', $this->type));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,13 +6,13 @@ use Ulmus\Query;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Where implements \Ulmus\Annotation\Annotation {
 | 
					class Where implements \Ulmus\Annotation\Annotation {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public string $field;
 | 
					    public /* stringable */ $field;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public $value;
 | 
					    public $value;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public string $operator;
 | 
					    public string $operator;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public function __construct(? string $field = null, $value = null, ? string $operator = null)
 | 
					    public function __construct(/* stringable */ $field = null, $value = null, ? string $operator = null)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( $field !== null ) {
 | 
					        if ( $field !== null ) {
 | 
				
			||||||
            $this->field = $field;
 | 
					            $this->field = $field;
 | 
				
			||||||
 | 
				
			|||||||
@ -64,7 +64,7 @@ class EntityField
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public static function isObjectType($type) : bool
 | 
					    public static function isObjectType($type) : bool
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        # @ Should be fixed with isBuiltIn() instead, it won't be correct based only on name
 | 
					        # @Should be fixed with isBuiltIn() instead, it won't be correct based only on name
 | 
				
			||||||
        # return strpos($type, "\\") !== false;
 | 
					        # return strpos($type, "\\") !== false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -5,5 +5,4 @@ namespace Ulmus\Entity\Field;
 | 
				
			|||||||
class Time extends Datetime {
 | 
					class Time extends Datetime {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public string $format = "H:i:s";
 | 
					    public string $format = "H:i:s";
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,8 +8,8 @@ use Ulmus\Repository,
 | 
				
			|||||||
    Ulmus\Common\EntityField;
 | 
					    Ulmus\Common\EntityField;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Ulmus\Annotation\Classes\{ Method, Table, Collation, };
 | 
					use Ulmus\Annotation\Classes\{ Method, Table, Collation, };
 | 
				
			||||||
use Ulmus\Annotation\Property\{ Field, Relation, OrderBy, Where, Join, Virtual };
 | 
					use Ulmus\Annotation\Property\{ Field, Relation, OrderBy, Where, Join, Filter, On };
 | 
				
			||||||
use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, };
 | 
					use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, Datetime as DateTime, Date, Time, };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
trait EntityTrait {
 | 
					trait EntityTrait {
 | 
				
			||||||
    use EventTrait;
 | 
					    use EventTrait;
 | 
				
			||||||
@ -40,50 +40,62 @@ trait EntityTrait {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # @TODO REFACTOR THIS CODE ASAP !
 | 
					        # @TODO REFACTOR THIS CODE ASAP !
 | 
				
			||||||
        if ( $this->isLoaded() ) {
 | 
					        if ( $this->isLoaded() ) {
 | 
				
			||||||
            if ( null !== ( $join= $entityResolver->searchFieldAnnotation($name, new Join() ) ) ) {
 | 
					            $annotation = $entityResolver->searchFieldAnnotation($name, new Annotation\Property\Join) ?:
 | 
				
			||||||
 | 
					                $entityResolver->searchFieldAnnotation($name, new Annotation\Property\Relation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ( $annotation ) {
 | 
				
			||||||
                $vars = [];
 | 
					                $vars = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $entity = $join->entity ?? $entityResolver->properties[$name]['type'];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                foreach($this->entityDatasetUnmatchedFields as $key => $value) {
 | 
					 | 
				
			||||||
                $len = strlen( $name ) + 1;
 | 
					                $len = strlen( $name ) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach($this->entityDatasetUnmatchedFields as $key => $value) {
 | 
				
			||||||
                    if ( substr($key, 0, $len ) === "{$name}$" ) {
 | 
					                    if ( substr($key, 0, $len ) === "{$name}$" ) {
 | 
				
			||||||
                        $vars[substr($key, $len)] = $value;
 | 
					                        $vars[substr($key, $len)] = $value;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if ( [] !== $data = (array_values(array_unique($vars)) !== [ null ] ? $vars : []) ) {
 | 
					                if ( [] !== $data = (array_values(array_unique($vars)) !== [ null ] ? $vars : []) ) {
 | 
				
			||||||
                    return ( new $entity() )->fromArray($data);    
 | 
					                    $entity = $annotation->entity ?? $entityResolver->properties[$name]['type'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return $this->$name = ( new $entity() )->fromArray($data)->resetVirtualProperties();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            if ( null !== ( $relation = $entityResolver->searchFieldAnnotation($name, new Relation() ) ) ) {
 | 
					            if ( null !== ( $relation = $entityResolver->searchFieldAnnotation($name, new Relation() ) ) ) {
 | 
				
			||||||
                $relationType = strtolower(str_replace(['-', '_', ' '], '', $relation->type));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $order = $entityResolver->searchFieldAnnotationList($name, new OrderBy() );
 | 
					                $order = $entityResolver->searchFieldAnnotationList($name, new OrderBy() );
 | 
				
			||||||
                $where = $entityResolver->searchFieldAnnotationList($name, new Where() );
 | 
					                $where = $entityResolver->searchFieldAnnotationList($name, new Where() );
 | 
				
			||||||
 | 
					                $filters = $entityResolver->searchFieldAnnotationList($name, new Filter() );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if ( $relation->entity ?? false ) {
 | 
					                $baseEntity = $relation->entity ?? $relation->bridge ?? $entityResolver->properties[$name]['type'];
 | 
				
			||||||
                    $baseEntity = $relation->entity();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    $repository = $baseEntity->repository();
 | 
					                $repository = $baseEntity::repository()->open();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    foreach($where as $condition) {
 | 
					                foreach ($where as $condition) {
 | 
				
			||||||
                        $repository->where($condition->field, is_callable($condition->value) ? $f = call_user_func_array($condition->value, [ $this ]) : $condition->value, $condition->operator);
 | 
					                    $repository->where($condition->field, is_callable($condition->value) ? call_user_func_array($condition->value, [$this]) : $condition->value, $condition->operator, $condition->condition);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    foreach($order as $item) {
 | 
					                $repository->close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach ($order as $item) {
 | 
				
			||||||
                    $repository->orderBy($item->field, $item->order);
 | 
					                    $repository->orderBy($item->field, $item->order);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $field = $relation->key;
 | 
					                $field = $relation->key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $applyFilter = function($repository) use ($filters, $name) {
 | 
				
			||||||
 | 
					                    foreach($filters as $filter) {
 | 
				
			||||||
 | 
					                        $repository = call_user_func_array([ $this, $filter->method ], [ $repository, $name ]);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                switch( $relationType ) {
 | 
					                    return $repository;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                switch( $relation->normalizeType() ) {
 | 
				
			||||||
                    case 'onetoone':
 | 
					                    case 'onetoone':
 | 
				
			||||||
 | 
					                        $repository->limit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if ($relation->foreignKey) {
 | 
					                        if ($relation->foreignKey) {
 | 
				
			||||||
                            $repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity->field($relation->foreignKey), is_callable($field) ? $field($this) : $this->$field );
 | 
					                            $repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity::field($relation->foreignKey), is_callable($field) ? $field($this) : $this->$field );
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository);
 | 
					                        $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository);
 | 
				
			||||||
@ -91,18 +103,18 @@ trait EntityTrait {
 | 
				
			|||||||
                        $result = call_user_func([$repository, $relation->function]);
 | 
					                        $result = call_user_func([$repository, $relation->function]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if ( count($result) === 0 ) {
 | 
					                        if ( count($result) === 0 ) {
 | 
				
			||||||
                            return $baseEntity;
 | 
					                            return new $baseEntity();
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        return $this->$name = $result[0];
 | 
					                        return $this->$name = $result[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case 'onetomany':
 | 
					                    case 'onetomany':
 | 
				
			||||||
                        if ($relation->foreignKey) {
 | 
					                        if ($relation->foreignKey) {
 | 
				
			||||||
                            $repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity->field($relation->foreignKey), is_callable($field) ? $field($this) : $this->$field );
 | 
					                            $repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity::field($relation->foreignKey), is_callable($field) ? $field($this) : $this->$field );
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository);
 | 
					                        $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        return $this->$name = call_user_func([$repository, $relation->function]);
 | 
					                        return $this->$name = call_user_func([$applyFilter($repository), $relation->function]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    case 'manytomany':
 | 
					                    case 'manytomany':
 | 
				
			||||||
                        if ( false === $relation->bridge ?? false ) {
 | 
					                        if ( false === $relation->bridge ?? false ) {
 | 
				
			||||||
@ -128,17 +140,21 @@ trait EntityTrait {
 | 
				
			|||||||
                            ->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName(), $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias), $relationAlias)
 | 
					                            ->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName(), $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias), $relationAlias)
 | 
				
			||||||
                            ->where( static::field($bridgeRelation->foreignKey, $relationAlias), $this->{$bridgeRelation->foreignKey} );
 | 
					                            ->where( static::field($bridgeRelation->foreignKey, $relationAlias), $this->{$bridgeRelation->foreignKey} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        $repository->open();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        foreach($where as $condition) {
 | 
					                        foreach($where as $condition) {
 | 
				
			||||||
                            $repository->where($condition->field, $condition->value, $condition->operator);
 | 
					                            $repository->where($condition->field, $condition->value, $condition->operator);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        $repository->close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        foreach($order as $item) {
 | 
					                        foreach($order as $item) {
 | 
				
			||||||
                            $repository->orderBy($item->field, $item->order);
 | 
					                            $repository->orderBy($item->field, $item->order);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository);
 | 
					                        $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository);
 | 
				
			||||||
                        
 | 
					                        
 | 
				
			||||||
                        $this->$name = call_user_func([ $repository, $relationRelation->function ]);
 | 
					                        $this->$name = call_user_func([ $applyFilter($repository), $relationRelation->function ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if ($relation->bridgeField ?? false) {
 | 
					                        if ($relation->bridgeField ?? false) {
 | 
				
			||||||
                            $repository = $relationRelation->entity::repository();
 | 
					                            $repository = $relationRelation->entity::repository();
 | 
				
			||||||
@ -148,10 +164,14 @@ trait EntityTrait {
 | 
				
			|||||||
                                ->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName(), $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias), $relationAlias)
 | 
					                                ->join(Query\Join::TYPE_INNER, $this->resolveEntity()->tableName(), $relation->bridge::field($bridgeRelation->key, $bridgeAlias), static::field($bridgeRelation->foreignKey, $relationAlias), $relationAlias)
 | 
				
			||||||
                                ->where( static::field($bridgeRelation->foreignKey, $relationAlias), $this->{$bridgeRelation->foreignKey} );
 | 
					                                ->where( static::field($bridgeRelation->foreignKey, $relationAlias), $this->{$bridgeRelation->foreignKey} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            $repository->open();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            foreach($where as $condition) {
 | 
					                            foreach($where as $condition) {
 | 
				
			||||||
                                $repository->where($condition->field, $condition->value, $condition->operator);
 | 
					                                $repository->where($condition->field, $condition->value, $condition->operator);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            $repository->close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            foreach($order as $item) {
 | 
					                            foreach($order as $item) {
 | 
				
			||||||
                                $repository->orderBy($item->field, $item->order);
 | 
					                                $repository->orderBy($item->field, $item->order);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
@ -176,6 +196,9 @@ trait EntityTrait {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __isset(string $name) : bool
 | 
					    public function __isset(string $name) : bool
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        #if ( null !== $relation = static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
 | 
				
			||||||
 | 
					        #    return isset($this->{$relation->key});
 | 
				
			||||||
 | 
					        #}
 | 
				
			||||||
        if ( $this->isLoaded() && static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
 | 
					        if ( $this->isLoaded() && static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) {
 | 
				
			||||||
           return true;
 | 
					           return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -186,7 +209,7 @@ trait EntityTrait {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @Ignore
 | 
					     * @Ignore
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function entityFillFromDataset(iterable $dataset, bool $isLoadedDataset = false) : self
 | 
					    public function entityFillFromDataset(iterable $dataset) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $loaded = $this->isLoaded();
 | 
					        $loaded = $this->isLoaded();
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@ -227,6 +250,9 @@ trait EntityTrait {
 | 
				
			|||||||
                        $value = substr($value, 0, $annotation->length);
 | 
					                        $value = substr($value, 0, $annotation->length);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                elseif ( $field['type'] === 'bool' ) {
 | 
				
			||||||
 | 
					                    $this->{$field['name']} = (bool) $value;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
                $this->{$field['name']} = $value;
 | 
					                $this->{$field['name']} = $value;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -298,6 +324,10 @@ trait EntityTrait {
 | 
				
			|||||||
                        $dataset[$realKey] = Ulmus::encodeArray($this->$key);
 | 
					                        $dataset[$realKey] = Ulmus::encodeArray($this->$key);
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    case is_bool($this->$key):
 | 
				
			||||||
 | 
					                        $dataset[$realKey] = (int) $this->$key;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
                    default:
 | 
					                    default:
 | 
				
			||||||
                       $dataset[$realKey] = $this->$key;
 | 
					                       $dataset[$realKey] = $this->$key;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -307,6 +337,7 @@ trait EntityTrait {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					        # @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($name, new Relation() );
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
namespace Ulmus\Migration;
 | 
					namespace Ulmus\Migration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Ulmus\Annotation\Property\Field;
 | 
					use Ulmus\Annotation\Property\Field;
 | 
				
			||||||
 | 
					use Ulmus\Entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FieldDefinition {
 | 
					class FieldDefinition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -28,7 +29,6 @@ class FieldDefinition {
 | 
				
			|||||||
        $this->builtIn = $data['builtin'];
 | 
					        $this->builtIn = $data['builtin'];
 | 
				
			||||||
        $this->tags = $data['tags'];
 | 
					        $this->tags = $data['tags'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        $field = $this->getFieldTag();
 | 
					        $field = $this->getFieldTag();
 | 
				
			||||||
        $this->type = $field->type ?? $data['type'];
 | 
					        $this->type = $field->type ?? $data['type'];
 | 
				
			||||||
        $this->length = $field->length ?? null;
 | 
					        $this->length = $field->length ?? null;
 | 
				
			||||||
@ -45,8 +45,19 @@ class FieldDefinition {
 | 
				
			|||||||
    public function getSqlType(bool $typeOnly = false) : string
 | 
					    public function getSqlType(bool $typeOnly = false) : string
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $type = $this->type;
 | 
					        $type = $this->type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $length = $this->length;
 | 
					        $length = $this->length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ( is_a($type, Entity\Field\Date::class, true) ) {
 | 
				
			||||||
 | 
					            $type = "DATE";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        elseif ( is_a($type, Entity\Field\Time::class, true) ) {
 | 
				
			||||||
 | 
					            $type = "TIME";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        elseif ( is_a($type, \DateTime::class, true) ) {
 | 
				
			||||||
 | 
					            $type = "DATETIME";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch($type) {
 | 
					        switch($type) {
 | 
				
			||||||
            case "bool":
 | 
					            case "bool":
 | 
				
			||||||
                $type = "TINYINT";
 | 
					                $type = "TINYINT";
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,7 @@ class Create extends Fragment {
 | 
				
			|||||||
    public function renderFields() : string
 | 
					    public function renderFields() : string
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return "(" . PHP_EOL . implode(",".PHP_EOL, array_map(function($field) {
 | 
					        return "(" . PHP_EOL . implode(",".PHP_EOL, array_map(function($field) {
 | 
				
			||||||
            return "    ".EntityField::generateCreateColumn($field);
 | 
					            return "    " . EntityField::generateCreateColumn($field);
 | 
				
			||||||
        }, $this->fieldList)) . PHP_EOL . ")";
 | 
					        }, $this->fieldList)) . PHP_EOL . ")";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,8 @@ class Join extends Fragment
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    public /* QueryBuilder */ $queryBuilder;
 | 
					    public /* QueryBuilder */ $queryBuilder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int $order = 40;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct(QueryBuilder $queryBuilder) 
 | 
					    public function __construct(QueryBuilder $queryBuilder) 
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->queryBuilder = new QueryBuilder();
 | 
					        $this->queryBuilder = new QueryBuilder();
 | 
				
			||||||
@ -47,18 +49,14 @@ class Join extends Fragment
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->side = $side;
 | 
					        $this->side = $side;
 | 
				
			||||||
        $this->table = $table;
 | 
					        $this->table = $table;
 | 
				
			||||||
        $this->field = $field;
 | 
					
 | 
				
			||||||
        $this->value = $value;
 | 
					        $this->where($this->field = $field, $this->value = $value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function render() : string
 | 
					    public function render() : string
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->queryBuilder->where ?? false ) {
 | 
					 | 
				
			||||||
            $where = $this->renderSegments([Where::CONDITION_AND, $this->queryBuilder->render(true)]);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        return $this->renderSegments([ 
 | 
					        return $this->renderSegments([ 
 | 
				
			||||||
            strtoupper($this->side), $this->outer ? static::SQL_OUTER : "", static::SQL_TOKEN, $this->table, $this->alias ?? "", $this->attachment, $this->field, "=", $this->value, $where ?? ""
 | 
					            strtoupper($this->side), $this->outer ? static::SQL_OUTER : "", static::SQL_TOKEN, $this->table, $this->alias ?? "", $this->attachment, $this->queryBuilder->render(true) ?? ""
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -191,7 +191,7 @@ class QueryBuilder
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function where($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self
 | 
					    public function where(/* 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 ) {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Ulmus;
 | 
					namespace Ulmus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Ulmus\Annotation\Property\{ Where, Having, Relation, Join };
 | 
				
			||||||
use Ulmus\Common\EntityResolver;
 | 
					use Ulmus\Common\EntityResolver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Repository
 | 
					class Repository
 | 
				
			||||||
@ -379,27 +380,59 @@ class Repository
 | 
				
			|||||||
        return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value);
 | 
					        return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function withJoin(/*string|array*/ $fields) : self
 | 
					    public function withJoin(/*string|array*/ $fields) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
 | 
					        if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
 | 
				
			||||||
            $this->select("{$this->alias}.*");
 | 
					            $this->select("{$this->alias}.*");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Apply FILTER annotation to this too !
 | 
				
			||||||
        foreach((array) $fields as $item) {
 | 
					        foreach((array) $fields as $item) {
 | 
				
			||||||
            if ( null !== $join = $this->entityResolver->searchFieldAnnotation($item, new Annotation\Property\Join) ) {
 | 
					            $annotation = $this->entityResolver->searchFieldAnnotation($item, new Join) ?:
 | 
				
			||||||
                $alias = $join->alias ?? $item;
 | 
					                $this->entityResolver->searchFieldAnnotation($item, new Relation);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $entity = $join->entity ?? $this->entityResolver->properties[$item]['type'];
 | 
					            if (( $annotation instanceof Relation ) && ( $annotation->normalizeType() === 'manytomany' )) {
 | 
				
			||||||
 | 
					                throw new Exception("Many-to-many relation can not be preloaded within joins.");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ( $annotation ) {
 | 
				
			||||||
 | 
					                $alias = $annotation->alias ?? $item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $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) {
 | 
				
			||||||
                    $this->select("$alias.$key as {$alias}\${$field['name']}");
 | 
					                    $this->select("$alias.$key as {$alias}\${$field['name']}");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $key = is_string($join->key) ? $this->entityClass::field($join->key) : $join->key;
 | 
					                $this->open();
 | 
				
			||||||
                $foreignKey = is_string($join->foreignKey) ? $entity::field($join->foreignKey, $alias) : $join->foreignKey;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $this->join($join->type, $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias);
 | 
					                foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) {
 | 
				
			||||||
 | 
					                    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);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                foreach($this->entityResolver->searchFieldAnnotationList($item, new Having() ) as $condition) {
 | 
				
			||||||
 | 
					                    $this->having(is_object($condition->field) ? $condition->field : $entity::field($condition->field), $condition->value, $condition->operator);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $this->close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $key = is_string($annotation->key) ? $this->entityClass::field($annotation->key) : $annotation->key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $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) {
 | 
				
			||||||
 | 
					                    foreach($this->entityResolver->searchFieldAnnotationList($item, new Where() ) as $condition) {
 | 
				
			||||||
 | 
					                        $field = clone $condition->field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if ( is_object($condition->field) && ( $condition->field->entityClass === $entity ) ) {
 | 
				
			||||||
 | 
					                            $field->alias = $alias;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            $join->where(is_object($field) ? $field : $entity::field($field, $alias), $condition->value, $condition->operator);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
                throw new \Exception("You referenced field `$item` which do not exist or do not contain a valid @Join annotation.");
 | 
					                throw new \Exception("You referenced field `$item` which do not exist or do not contain a valid @Join annotation.");
 | 
				
			||||||
@ -409,7 +442,6 @@ class Repository
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest) : self
 | 
					    public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest) : self
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $searchRequest->count = $searchRequest->filter( clone $this )
 | 
					        $searchRequest->count = $searchRequest->filter( clone $this )
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user