From 114fa5be09d50c911e0ea6d0c8b066a48351aba2 Mon Sep 17 00:00:00 2001 From: Dave M Date: Fri, 16 Oct 2020 15:04:05 +0000 Subject: [PATCH] - Had to fix a changed behaviour from PHP 7.4 and 7.4.x where __isset() and __get is not called on initialized properties anymore. --- src/EntityTrait.php | 34 ++++--- src/Repository.php | 217 ++++++++++++++++++++++---------------------- 2 files changed, 132 insertions(+), 119 deletions(-) diff --git a/src/EntityTrait.php b/src/EntityTrait.php index 4521f5f..933cb20 100644 --- a/src/EntityTrait.php +++ b/src/EntityTrait.php @@ -35,12 +35,11 @@ trait EntityTrait { public function __get(string $name) { $entityResolver = $this->resolveEntity(); - + # Resolve relations here if one is called - + # @TODO REFACTOR THIS CODE ASAP ! if ( $this->isLoaded() ) { - if ( null !== ( $join= $entityResolver->searchFieldAnnotation($name, new Join() ) ) ) { $vars = []; @@ -60,7 +59,7 @@ trait EntityTrait { } if ( null !== ( $relation = $entityResolver->searchFieldAnnotation($name, new Relation() ) ) ) { - $relationType = strtolower(str_replace(['-', '_'], '', $relation->type)); + $relationType = strtolower(str_replace(['-', '_', ' '], '', $relation->type)); $order = $entityResolver->searchFieldAnnotationList($name, new OrderBy() ); $where = $entityResolver->searchFieldAnnotationList($name, new Where() ); @@ -84,6 +83,7 @@ trait EntityTrait { switch( $relationType ) { case 'onetoone': $repository->where( is_object($relation->foreignKey) ? $relation->foreignKey : $baseEntity->field($relation->foreignKey), $this->$field ); + $repository->limit(1); $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository); @@ -113,7 +113,7 @@ trait EntityTrait { if ($relationRelation === null) { throw new \Exception("@Relation annotation not found for field `{$relation->foreignField}` in entity {$relation->bridge}"); } - + $repository = $relationRelation->entity()->repository(); $bridgeAlias = uniqid("bridge_"); @@ -164,10 +164,7 @@ trait EntityTrait { return; } } - else { - - } - + throw new \Exception(sprintf("[%s] - Undefined variable: %s", static::class, $name)); } @@ -179,7 +176,7 @@ trait EntityTrait { if ( $this->isLoaded() && static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) { return true; } - + return isset($this->$name); } @@ -246,6 +243,21 @@ trait EntityTrait { return $this; } + + public function resetVirtualProperties() : self + { + foreach($this->resolveEntity()->properties as $prop => $property) { + if ( ! $property['builtin'] ) { + foreach($property['tags'] as $tag) { + if ( in_array(strtolower($tag['tag']), [ 'relation', 'join' ] ) ) { + unset($this->$prop); + } + } + } + } + + return $this; + } /** * @Ignore @@ -388,7 +400,7 @@ trait EntityTrait { { $collection = new EntityCollection(...$arguments); $collection->entityClass = static::class; - + return $collection; } diff --git a/src/Repository.php b/src/Repository.php index b093bbb..8d13e8a 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -7,7 +7,7 @@ use Ulmus\Common\EntityResolver; class Repository { use EventTrait, Repository\ConditionTrait; - + const DEFAULT_ALIAS = "this"; public ? ConnectionAdapter $adapter; @@ -19,9 +19,9 @@ class Repository public string $alias; public string $entityClass; - + public array $events = []; - + public function __construct(string $entity, string $alias = self::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) { $this->entityClass = $entity; $this->alias = $alias; @@ -39,12 +39,12 @@ class Repository { return $this->where($field, $value)->loadOne(); } - + public function loadFromPk($value, /* ? stringable */ $primaryKey = null) : ? object { return $primaryKey ? $this->loadOneFromField($primaryKey, $value) : $this->wherePrimaryKey($value)->loadOne(); } - + public function loadAll() : EntityCollection { return $this->collectionFromQuery(); @@ -54,20 +54,20 @@ class Repository { return $this->where($field, $value)->collectionFromQuery(); } - + public function count() : int { if ( null !== $select = $this->queryBuilder->getFragment(Query\Select::class) ) { $this->queryBuilder->removeFragment($select); } - + if ( $this->queryBuilder->getFragment(Query\GroupBy::class) ) { $this->select( "DISTINCT COUNT(*) OVER ()" ); } else { $this->select(Common\Sql::function("COUNT", "*")); } - + $this->selectSqlQuery(); $this->finalizeQuery(); @@ -75,13 +75,13 @@ class Repository return Ulmus::runSelectQuery($this->queryBuilder, $this->adapter)->fetchColumn(0); } - protected function deleteOne() + protected function deleteOne() { return $this->limit(1)->deleteSqlQuery()->runQuery(); } - - protected function deleteAll() - { + + protected function deleteAll() + { return $this->deleteSqlQuery()->runQuery(); } @@ -90,16 +90,16 @@ class Repository if ( $value !== 0 && empty($value) ) { throw new Exception\EntityPrimaryKeyUnknown("A primary key value has to be defined to delete an item."); } - + return (bool) $this->wherePrimaryKey($value)->deleteOne()->rowCount(); } - + public function destroy(object $entity) : bool { if ( ! $this->matchEntity($entity) ) { throw new \Exception("Your entity class `" . get_class($entity) . "` cannot match entity type of repository `{$this->entityClass}`"); } - + $primaryKeyDefinition = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField(); if ( $primaryKeyDefinition === null ) { @@ -107,39 +107,39 @@ class Repository } else { $pkField = key($primaryKeyDefinition); - + return $this->deleteFromPk($entity->$pkField); } - + return false; } - public function destroyAll(EntityCollection $collection) : void + public function destroyAll(EntityCollection $collection) : void { foreach($collection as $entity) { $this->destroy($entity); } } - + public function save(object $entity) : bool - { + { if ( ! $this->matchEntity($entity) ) { throw new \Exception("Your entity class `" . get_class($entity) . "` cannot match entity type of repository `{$this->entityClass}`"); } $dataset = $entity->toArray(); - + $primaryKeyDefinition = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField(); if ( ! $entity->isLoaded() ) { $statement = $this->insertSqlQuery($dataset)->runQuery(); - - if ( ( 0 !== $statement->lastInsertId ) && - ( null !== $primaryKeyDefinition )) { + + if ( ( 0 !== $statement->lastInsertId ) && + ( null !== $primaryKeyDefinition )) { $pkField = key($primaryKeyDefinition); $entity->$pkField = $statement->lastInsertId; } - + return true; } else { @@ -153,45 +153,45 @@ class Repository $this->where($pkFieldName, $dataset[$pkFieldName]); $update = $this->updateSqlQuery($diff)->runQuery(); - + return $update ? (bool) $update->rowCount() : false; } } - + return false; } - - public function saveAll(EntityCollection $collection) : void + + public function saveAll(EntityCollection $collection) : void { foreach($collection as $entity) { $this->save($entity); } } - + public function truncate(? string $table = null, ? string $alias = null, ? string $schema = null) : self { $schema = $schema ?: $this->entityResolver->schemaName(); - + $this->queryBuilder->truncate($this->escapeTable($table ?: $this->entityResolver->tableName()), $alias ?: $this->alias, $this->escapeDatabase($this->adapter->adapter()->database), $schema ? $this->escapeSchema($schema) : null); - + $this->finalizeQuery(); - + $result = Ulmus::runSelectQuery($this->queryBuilder, $this->adapter); - + return $this; } - + public function generateDatasetDiff(object $entity) : array { return array_diff_assoc( array_change_key_case($entity->toArray()), array_change_key_case($entity->entityGetDataset(false, true)) ); } - + public function yield() : \Generator { $class = $this->entityClass; - + $this->selectSqlQuery(); - + $this->finalizeQuery(); foreach(Ulmus::iterateQueryBuilder($this->queryBuilder, $this->adapter) as $entityData) { @@ -202,74 +202,74 @@ class Repository public function select($fields) : self { $this->queryBuilder->select($fields); - + return $this; } public function insert(array $fieldlist, string $table, string $alias, ? string $schema) : self { $this->queryBuilder->insert($fieldlist, $this->escapeTable($table), $alias, $schema); - + return $this; } public function values(array $dataset) : self { $this->queryBuilder->values($dataset); - + return $this; } - + public function update(string $table, string $alias, ? string $schema) : self { $this->queryBuilder->update($this->escapeTable($table), $alias, $schema); - + return $this; } - + public function set(array $dataset) : self { $this->queryBuilder->set($dataset); - + return $this; } - + public function delete() : self { $this->queryBuilder->delete($this->alias); - + return $this; } public function from(string $table, ? string $alias, ? string $schema) : self { $this->queryBuilder->from($this->escapeTable($table), $alias, $this->escapeDatabase($this->adapter->adapter()->database), $schema ? $this->escapeSchema($schema) : null); - + return $this; } public function join(string $type, $table, $field, $value, ? string $alias = null, ? callable $callback = null) : self { $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, false, $alias); - + if ( $callback ) { $callback($join); } - + return $this; } public function outerJoin(string $type, $table, $field, $value, ? string $alias = null, ? callable $callback = null) : self { $join = $this->queryBuilder->withJoin($type, $this->escapeTable($table), $field, $value, true, $alias); - + if ( $callback ) { $callback($join); } - + return $this; } - + public function match() : self { @@ -289,11 +289,11 @@ class Repository { } - + public function groupBy($field) : self { $this->queryBuilder->groupBy($field); - + return $this; } @@ -302,14 +302,14 @@ class Repository foreach($groups as $field ) { $this->groupBy($field); } - + return $this; } - + public function orderBy($field, ? string $direction = null) : self { $this->queryBuilder->orderBy($field, $direction); - + return $this; } @@ -318,22 +318,22 @@ class Repository foreach($orderList as $field => $direction) { $this->orderBy($field, $direction); } - + return $this; } - + public function limit(int $value) : self { $this->queryBuilder->limit($value); - + return $this; } public function offset(int $value) : self { $this->queryBuilder->offset($value); - + return $this; } @@ -355,86 +355,82 @@ class Repository if ( null === $primaryKeyField = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField() ) { throw new Exception\EntityPrimaryKeyUnknown("Entity has no field containing attributes 'primary_key'"); } - + $pkField = key($primaryKeyField); - + return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value); } - + public function withJoin(/*string|array*/ $fields) : self { $resolvedEntity = Ulmus::resolveEntity($this->entityClass); - + if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) { $this->select("{$this->alias}.*"); } - + foreach((array) $fields as $item) { if ( null !== $join = $resolvedEntity->searchFieldAnnotation($item, new Annotation\Property\Join) ) { $alias = $join->alias ?? $item; $entity = $join->entity ?? $resolvedEntity->properties[$item]['type']; - + foreach($entity::resolveEntity()->fieldList(Common\EntityResolver::KEY_COLUMN_NAME) as $key => $field) { $this->select("$alias.$key as {$alias}\${$field['name']}"); } - + $key = is_string($join->key) ? $this->entityClass::field($join->key) : $join->key; $foreignKey = is_string($join->foreignKey) ? $entity::field($join->foreignKey, $alias) : $join->foreignKey; - + $this->join($join->type, $entity::resolveEntity()->tableName(), $key, $foreignKey, $alias); } else { throw new \Exception("You referenced field `$item` which do not exist or do not contain a valid @Join annotation."); } } - + return $this; } - - public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest) : self + + public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest) : self { - $likes = $searchRequest->likes(); - $wheres = $searchRequest->wheres(); - $groups = $searchRequest->groups(); - - $searchRequest->count = $searchRequest->skipCount ? 0 : $searchRequest->filter( clone $this ) - ->wheres($wheres, Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND) - ->likes($likes, Query\Where::CONDITION_OR) - ->groups($groups) + $searchRequest->count = $searchRequest->filter( clone $this ) + ->wheres($searchRequest->wheres(), Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND) + ->likes($searchRequest->likes(), Query\Where::CONDITION_OR) + ->groups($searchRequest->groups()) ->count(); - + return $searchRequest->filter($this) - ->wheres($wheres, Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND) - ->likes($likes, Query\Where::CONDITION_OR) + ->wheres($searchRequest->wheres(), Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND) + ->likes($searchRequest->likes(), Query\Where::CONDITION_OR) ->orders($searchRequest->orders()) - ->groups($groups) + ->groups($searchRequest->groups()) ->offset($searchRequest->offset()) ->limit($searchRequest->limit()); } - + public function collectionFromQuery(? string $entityClass = null) : EntityCollection { $class = $entityClass ?: $this->entityClass; - - $entityCollection = $class::entityCollection(); - + + $entityCollection = $this->instanciateEntityCollection(); + $this->selectSqlQuery(); - + $this->finalizeQuery(); foreach(Ulmus::iterateQueryBuilder($this->queryBuilder, $this->adapter) as $entityData) { - $entityCollection->append( ( new $class() )->entityFillFromDataset($entityData) ); + $entityCollection->append( ( new $class() )->resetVirtualProperties()->entityFillFromDataset($entityData) ); } - - $this->eventExecute(Event\Repository\CollectionFromQueryInterface::class, $entityCollection); + + $this->eventExecute(Event\RepositoryCollectionFromQueryInterface::class, $entityCollection); return $entityCollection; } - + public function arrayFromQuery() : array { $this->selectSqlQuery(); - + $this->finalizeQuery(); return Ulmus::datasetQueryBuilder($this->queryBuilder, $this->adapter); @@ -443,10 +439,10 @@ class Repository public function runQuery() : ? \PDOStatement { $this->finalizeQuery(); - + return Ulmus::runQuery($this->queryBuilder, $this->adapter); } - + protected function insertSqlQuery(array $dataset) : self { if ( null === $this->queryBuilder->getFragment(Query\Insert::class) ) { @@ -457,18 +453,18 @@ class Repository return $this; } - + protected function updateSqlQuery(array $dataset) : self { if ( null === $this->queryBuilder->getFragment(Query\Update::class) ) { $this->update($this->entityResolver->tableName(), $this->alias, $this->entityResolver->schemaName()); } - + $this->set($dataset); return $this; } - + protected function selectSqlQuery() : self { if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) { @@ -494,7 +490,7 @@ class Repository return $this; } - + protected function fromRow($row) : self { @@ -504,30 +500,35 @@ class Repository { } - + public function instanciateEntityCollection() : EntityCollection { return $this->entityClass::entityCollection(); } - + + public function instanciateEntity() : object + { + return new $this->entityClass(); + } + public function escapeTable(string $identifier) : string { return $this->adapter->adapter()->escapeIdentifier($identifier, Adapter\AdapterInterface::IDENTIFIER_TABLE); } - + public function escapeDatabase(string $identifier) : string { return $this->adapter->adapter()->escapeIdentifier($identifier, Adapter\AdapterInterface::IDENTIFIER_DATABASE); } - + public function escapeSchema(string $identifier) : string { return $this->adapter->adapter()->escapeIdentifier($identifier, Adapter\AdapterInterface::IDENTIFIER_SCHEMA); } - + protected function matchEntity(object $entity) { return get_class($entity) === $this->entityClass; } - + protected function finalizeQuery() : void {} -} +} \ No newline at end of file