diff --git a/src/Annotation/Property/Field.php b/src/Annotation/Property/Field.php index 25d1d93..30e9519 100644 --- a/src/Annotation/Property/Field.php +++ b/src/Annotation/Property/Field.php @@ -15,7 +15,9 @@ class Field implements \Ulmus\Annotation\Annotation { public array $attributes = []; public bool $nullable; - + + public bool $readonly = false; + public function __construct(? string $type = null, ? int $length = null) { if ( $type !== null ) { diff --git a/src/Common/EntityResolver.php b/src/Common/EntityResolver.php index 9936711..8aef889 100644 --- a/src/Common/EntityResolver.php +++ b/src/Common/EntityResolver.php @@ -125,18 +125,20 @@ class EntityResolver { return null; } - public function searchFieldAnnotation(string $field, Annotation $annotationType) : ? Annotation + public function searchFieldAnnotation(string $field, Annotation $annotationType, bool $caseSensitive = true) : ? Annotation { - $found = $this->searchFieldAnnotationList($field, $annotationType); + $found = $this->searchFieldAnnotationList($field, $annotationType, $caseSensitive); return $found ? $found[0] : null; } - public function searchFieldAnnotationList(string $field, Annotation $annotationType) : array + public function searchFieldAnnotationList(string $field, Annotation $annotationType, bool $caseSensitive = true) : array { $list = []; - - if ( null !== ( $this->properties[$field] ?? null ) ) { - foreach($this->properties[$field]['tags'] ?? [] as $tag) { + + $search = $caseSensitive ? $this->properties : array_change_key_case($this->properties, \CASE_LOWER); + + if ( null !== ( $search[$field] ?? null ) ) { + foreach($search[$field]['tags'] ?? [] as $tag) { if ( $tag['object'] instanceof $annotationType ) { $list[] = $tag['object']; } diff --git a/src/Common/PdoObject.php b/src/Common/PdoObject.php index 22197b6..462c1a8 100644 --- a/src/Common/PdoObject.php +++ b/src/Common/PdoObject.php @@ -29,7 +29,7 @@ class PdoObject extends PDO { public function runQuery(string $sql, array $parameters = []): ? PDOStatement { static::$dump && call_user_func_array(static::$dump, [ $sql, $parameters ]); - + # \debogueur([ $sql, $parameters ]); try { if (false !== ( $statement = $this->prepare($sql) )) { return $this->execute($statement, $parameters, true); @@ -42,6 +42,21 @@ class PdoObject extends PDO { return null; } + public function runInsertQuery(array $filter, array $dataset) + { + return $this->runQuery($filter, $dataset); + } + + public function runUpdateQuery(array $filter, array $dataset) + { + return $this->runQuery($filter, $dataset); + } + + public function runDeleteQuery(string $sql, array $parameters = []): ? PDOStatement + { + return $this->runQuery($sql, $parameters); + } + public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true): ? PDOStatement { try { diff --git a/src/EntityTrait.php b/src/EntityTrait.php index 475fd6d..23f93fe 100644 --- a/src/EntityTrait.php +++ b/src/EntityTrait.php @@ -62,19 +62,19 @@ trait EntityTrait { /** * @Ignore */ - public function entityFillFromDataset(iterable $dataset) : self + public function entityFillFromDataset(iterable $dataset, bool $overwriteDataset = false) : self { $loaded = $this->isLoaded(); - + $entityResolver = $this->resolveEntity(); - + foreach($dataset as $key => $value) { $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_COLUMN_NAME, false) ?? null; - + if ( $field === null ) { $field = $entityResolver->field(strtolower($key), EntityResolver::KEY_LC_ENTITY_NAME, false); } - + if ( $field === null ) { if ($this->entityStrictFieldsDeclaration ) { throw new \Exception("Field `$key` can not be found within your entity ".static::class); @@ -98,9 +98,9 @@ trait EntityTrait { if ( $field['type'] === 'string' ) { $annotation = $entityResolver->searchFieldAnnotation($field['name'], new Field() ); - + if ( $annotation->length ?? null ) { - $value = substr($value, 0, $annotation->length); + $value = mb_substr($value, 0, $annotation->length); } } elseif ( $field['type'] === 'bool' ) { @@ -112,17 +112,20 @@ trait EntityTrait { elseif ( ! $field['builtin'] ) { $this->{$field['name']} = Ulmus::instanciateObject($field['type'], [ $value ]); } - + # Keeping original data to diff on UPDATE query - if ( ! $loaded || $isLoadedDataset ) { + if ( ! $loaded ) { #if ( $field !== null ) { # $annotation = $entityResolver->searchFieldAnnotation($field['name'], new Field() ); # $this->entityLoadedDataset[$annotation ? $annotation->name : $field['name']] = $dataset; # <--------- THIS TO FIX !!!!!! #} $this->entityLoadedDataset = array_change_key_case($dataset, \CASE_LOWER); } + elseif ($overwriteDataset) { + $this->entityLoadedDataset = array_change_key_case($dataset, \CASE_LOWER) + $this->entityLoadedDataset; + } } - + return $this; } diff --git a/src/Repository.php b/src/Repository.php index 11cd72d..5c6067f 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -56,6 +56,11 @@ class Repository return $this->collectionFromQuery(); } + public function loadAllFromField($field, $value) : EntityCollection + { + return $this->loadFromField($field, $value); + } + public function loadFromField($field, $value) : EntityCollection { return $this->where($field, $value)->collectionFromQuery(); @@ -81,12 +86,12 @@ class Repository public function deleteOne() { - return $this->limit(1)->deleteSqlQuery()->runQuery(); + return $this->limit(1)->deleteSqlQuery()->runDeleteQuery(); } public function deleteAll() { - return $this->deleteSqlQuery()->runQuery(); + return $this->deleteSqlQuery()->runDeleteQuery(); } public function deleteFromPk($value) : bool @@ -140,7 +145,7 @@ class Repository $primaryKeyDefinition = Ulmus::resolveEntity($this->entityClass)->getPrimaryKeyField(); if ( ! $entity->isLoaded() ) { - $statement = $this->insertSqlQuery($fieldsAndValue ?? $dataset, $replace)->runQuery(); + $statement = $this->insertSqlQuery($fieldsAndValue ?? $dataset, $replace)->runInsertQuery(); if ( ( 0 !== $statement->lastInsertId ) && ( null !== $primaryKeyDefinition )) { @@ -156,16 +161,16 @@ class Repository throw new \Exception(sprintf("No primary key found for entity %s", $this->entityClass)); } - $diff = $fieldsAndValue ?? $this->generateDatasetDiff($entity); + $diff = $fieldsAndValue ?? $this->generateWritableDataset($entity); if ( [] !== $diff ) { $pkField = key($primaryKeyDefinition); $pkFieldName = $primaryKeyDefinition[$pkField]->name ?? $pkField; $this->where($pkFieldName, $dataset[$pkFieldName]); - $update = $this->updateSqlQuery($diff)->runQuery(); + $update = $this->updateSqlQuery($diff)->runUpdateQuery(); - $entity->entityFillFromDataset($dataset); + $entity->entityFillFromDataset($dataset, true); return $update ? (bool) $update->rowCount() : false; } @@ -220,6 +225,22 @@ class Repository return array_diff_assoc($oldValues ? $dataset : $array , $oldValues ? $array : $dataset ); } + + public function generateWritableDataset(object $entity, bool $oldValues = false) : array + { + $intersect = []; + + $dataset = $this->generateDatasetDiff($entity, $oldValues); + + foreach($dataset as $field => $value) { + if ( false === ( $this->entityResolver->searchFieldAnnotation($field, new Field, false)->readonly ?? false ) ) { + $intersect[$field] = $field; + } + } + + return array_intersect_key($dataset, $intersect); + } + public function yield() : \Generator { $class = $this->entityClass; @@ -482,7 +503,7 @@ class Repository } foreach($this->entityResolver->searchFieldAnnotationList($item, new Filter() ) as $filter) { - call_user_func_array([ $this->entityClass, $filter->method ], [ $this, $item ]); + call_user_func_array([ $this->entityClass, $filter->method ], [ $this, $item, true ]); } $this->close(); @@ -508,7 +529,7 @@ class Repository } foreach($this->entityResolver->searchFieldAnnotationList($item, new FilterJoin() ) as $filter) { - call_user_func_array([ $this->entityClass, $filter->method ], [ $join, $item ]); + call_user_func_array([ $this->entityClass, $filter->method ], [ $join, $item, true ]); } }); } @@ -617,6 +638,27 @@ class Repository return Ulmus::runQuery($this->queryBuilder, $this->adapter); } + public function runInsertQuery() /* : mixed */ + { + $this->finalizeQuery(); + + return Ulmus::runInsertQuery($this->queryBuilder, $this->adapter); + } + + public function runUpdateQuery() /* : mixed */ + { + $this->finalizeQuery(); + + return Ulmus::runUpdateQuery($this->queryBuilder, $this->adapter); + } + + public function runDeleteQuery() /* : mixed */ + { + $this->finalizeQuery(); + + return Ulmus::runDeleteQuery($this->queryBuilder, $this->adapter); + } + public function resetQuery() : self { $this->queryBuilder->reset(); diff --git a/src/Repository/RelationBuilder.php b/src/Repository/RelationBuilder.php index 6df3d15..2d5470c 100644 --- a/src/Repository/RelationBuilder.php +++ b/src/Repository/RelationBuilder.php @@ -106,7 +106,7 @@ class RelationBuilder protected function applyFilter(Repository $repository, string $name) : Repository { foreach($this->filters ?? [] as $filter) { - $repository = call_user_func_array([ $this->entity, $filter->method ], [ $repository, $name ]); + $repository = call_user_func_array([ $this->entity, $filter->method ], [ $repository, $name, false ]); } return $repository; @@ -156,7 +156,7 @@ class RelationBuilder } foreach($data ?: $this->entity->entityLoadedDataset as $key => $value) { - if ( $key === sprintf(static::SUBQUERY_FIELD_SUFFIX, $name) ) { + if ( $key === sprintf(static::SUBQUERY_FIELD_SUFFIX, strtolower($name)) ) { if ($value) { if ( null === ( $dataset = \json_decode($value, true) ) ) { throw new \Exception(sprintf("JSON error '%s' from '%s'", \json_last_error_msg(), $value)); @@ -168,7 +168,7 @@ class RelationBuilder return $entity::entityCollection(); } } - elseif ( substr($key, 0, $len ) === sprintf(static::JOIN_FIELD_SEPARATOR, $name) ) { + elseif ( substr($key, 0, $len ) === sprintf(static::JOIN_FIELD_SEPARATOR, strtolower($name)) ) { $vars[substr($key, $len)] = $value; } } diff --git a/src/Ulmus.php b/src/Ulmus.php index 9636c2b..07fa13c 100644 --- a/src/Ulmus.php +++ b/src/Ulmus.php @@ -79,6 +79,24 @@ abstract class Ulmus return $return; } + public static function runInsertQuery(Query\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) + { + return static::runQuery($queryBuilder, $adapter); + } + + public static function runUpdateQuery(Query\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) + { + return static::runQuery($queryBuilder, $adapter); + } + + public static function runDeleteQuery(Query\QueryBuilderInterface $queryBuilder, ? ConnectionAdapter $adapter = null) + { + $return = static::connector($adapter)->runDeleteQuery($queryBuilder->render(), array_merge($queryBuilder->values ?? [], $queryBuilder->parameters ?? [])); + $queryBuilder->reset(); + + return $return; + } + public static function resolveEntity(string $entityClass) : Common\EntityResolver { return static::$resolved[$entityClass] ?? static::$resolved[$entityClass] = new Common\EntityResolver($entityClass);