diff --git a/src/Annotation/Property/Join.php b/src/Annotation/Property/Join.php new file mode 100644 index 0000000..2709dda --- /dev/null +++ b/src/Annotation/Property/Join.php @@ -0,0 +1,31 @@ +type = $type; + } + + if ($key !== null) { + $this->key = $key; + } + + if ($foreignKey !== null) { + $this->foreignKey = $foreignKey; + } + } +} diff --git a/src/Common/PdoObject.php b/src/Common/PdoObject.php index b487aef..ba20a73 100644 --- a/src/Common/PdoObject.php +++ b/src/Common/PdoObject.php @@ -55,12 +55,17 @@ class PdoObject extends PDO { else { throw new \PDOException($statement->errorCode() . " - " . json_encode($statement->errorInfo())); } - } + } catch (\PDOException $e) { $this->rollback(); throw $e; } + catch (\Throwable $e) { + debogueur($statement, $parameters, $commit); + + throw $e; + } return null; } diff --git a/src/Common/Sql.php b/src/Common/Sql.php index bc77934..a03ed06 100644 --- a/src/Common/Sql.php +++ b/src/Common/Sql.php @@ -14,7 +14,7 @@ abstract class Sql { protected array $arguments; - public function __construct(string $name, ...$arguments) { + public function __construct( $name, ...$arguments) { $this->name = $name; $this->arguments = $arguments; $this->parseArguments(); @@ -39,6 +39,22 @@ abstract class Sql { } }; } + + public static function identifier(string $identifier) : object + { + return new class($identifier) { + + protected string $identifier; + + public function __construct(string $identifier) { + $this->identifier = $identifier; + } + + public function __toString() { + return $this->identifier; + } + }; + } public static function escape($value) { diff --git a/src/Entity/Field/Date.php b/src/Entity/Field/Date.php index b91a45d..fe0df70 100644 --- a/src/Entity/Field/Date.php +++ b/src/Entity/Field/Date.php @@ -9,4 +9,8 @@ class Date extends Datetime { return $this->format("Y-m-d"); } + public function formatLocale(string $format) : string + { + return strftime($format, $this->getTimestamp()); + } } diff --git a/src/Entity/Field/Datetime.php b/src/Entity/Field/Datetime.php index af12034..7f6cfd8 100644 --- a/src/Entity/Field/Datetime.php +++ b/src/Entity/Field/Datetime.php @@ -30,4 +30,8 @@ class Datetime extends \DateTime implements EntityObjectInterface { return $this->format($this->format); } + public function formatLocale(string $format) : string + { + return strftime($format, $this->getTimestamp()); + } } diff --git a/src/EntityCollection.php b/src/EntityCollection.php index 031a190..24d0f7c 100644 --- a/src/EntityCollection.php +++ b/src/EntityCollection.php @@ -47,23 +47,39 @@ class EntityCollection extends \ArrayObject { } } - public function buildArray(string $keyColumn, /* string|callable */ $value) : array + public function buildArray(string $keyColumn, /* string|callable|null */ $value = null) : array { - $list = []; - foreach($this as $key => $item) { + foreach($this as $item) { switch (true) { - case is_string($value): - $list[$item->$keyColumn] = $item->$value; + case is_null($value): + $list[] = $item->$keyColumn; break; case is_callable($value): $list[$item->$keyColumn] = $value($item); break; + + case is_object($value): + case is_string($value): + $value = (string) $value; + + $list[$item->$keyColumn] = $item->$value; + break; } } return $list; } + + public function toArray(bool $includeRelations = false) : array { + $list = []; + + foreach($this as $entity) { + $list[] = $entity->toArray($includeRelations); + } + + return $list; + } } diff --git a/src/EntityTrait.php b/src/EntityTrait.php index 7623235..f367a39 100644 --- a/src/EntityTrait.php +++ b/src/EntityTrait.php @@ -8,25 +8,26 @@ use Ulmus\Repository, Ulmus\Common\EntityField; use Ulmus\Annotation\Classes\{ Method, Table, Collation, }; -use Ulmus\Annotation\Property\{ Field, Relation, OrderBy, Where, }; +use Ulmus\Annotation\Property\{ Field, Relation, OrderBy, Where, Join }; use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, }; trait EntityTrait { + use EventTrait; /** * @Ignore */ - protected bool $strictEntityFieldsDeclaration = false; + protected bool $entityStrictFieldsDeclaration = false; /** * @Ignore */ - protected array $unmatchedEntityDatasetFields = []; + protected array $entityDatasetUnmatchedFields = []; /** * @Ignore */ - public array $datasetSource = []; + public array $entityLoadedDataset = []; /** * @Ignore @@ -37,94 +38,144 @@ trait EntityTrait { # Resolve relations here if one is called - # @TODO REFACTOR THIS CODE URGENTLY ! - if ( null !== ( $relation = $entityResolver->searchFieldAnnotation($name, new Relation() ) ) ) { - $relationType = strtolower(str_replace(['-', '_'], '', $relation->type)); - - $order = $entityResolver->searchFieldAnnotationList($name, new OrderBy() ); - $where = $entityResolver->searchFieldAnnotationList($name, new Where() ); + # @TODO REFACTOR THIS CODE ASAP ! + if ( $this->isLoaded() ) { - if ( $relation->entity ?? false ) { - $baseEntity = $relation->entity(); - - $repository = $baseEntity->repository(); + if ( null !== ( $join= $entityResolver->searchFieldAnnotation($name, new Join() ) ) ) { + $vars = []; - foreach($where as $condition) { - $repository->where($condition->field, $condition->value, $condition->operator); + $entity = $join->entity ?? $entityResolver->properties[$name]['type']; + + foreach($this->entityDatasetUnmatchedFields as $key => $value) { + $len = strlen( $name ) + 1; + + if ( substr($key, 0, $len ) === "{$name}$" ) { + $vars[substr($key, $len)] = $value; + } } - foreach($order as $item) { - $repository->orderBy($item->field, $item->order); - } - - $field = $relation->key; - - if ( method_exists($this, $filterMethod = "filterRelation$name") ) { - $this->$filterMethod($repository); + if ( [] !== $data = (array_values(array_unique($vars)) !== [ null ] ? $vars : []) ) { + return ( new $entity() )->fromArray($data); } } - switch( $relationType ) { - case 'onetoone': - $repository->where( $baseEntity->field($relation->foreignKey), $this->$field ); - $result = call_user_func([$repository, $relation->function]); - - if ( count($result) === 0 ) { - return $baseEntity; + if ( null !== ( $relation = $entityResolver->searchFieldAnnotation($name, new Relation() ) ) ) { + $relationType = strtolower(str_replace(['-', '_'], '', $relation->type)); + + $order = $entityResolver->searchFieldAnnotationList($name, new OrderBy() ); + $where = $entityResolver->searchFieldAnnotationList($name, new Where() ); + + if ( $relation->entity ?? false ) { + $baseEntity = $relation->entity(); + + $repository = $baseEntity->repository(); + + foreach($where as $condition) { + $repository->where($condition->field, $condition->value, $condition->operator); } - - return $this->$name = $result[0]; - - case 'onetomany': - $repository->where( $baseEntity->field($relation->foreignKey), $this->$field); # <<<<<<<<< CHANGE $THIS->ID WITH PROPER NOMENCLATURE - - return $this->$name = call_user_func([$repository, $relation->function]); - - case 'manytomany': - if ( false === $relation->bridge ?? false ) { - throw new \Exception("Your many-to-many @Relation() from variable `$name` is missing a 'bridge' value."); + + foreach($order as $item) { + $repository->orderBy($item->field, $item->order); } - - $bridgeEntity = Ulmus::resolveEntity($relation->bridge); - $bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, new Relation() ); - $relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, new Relation() ); - - $repository = $relationRelation->entity()->repository(); - $bridgeAlias = uniqid("bridge_"); - $relationAlias = uniqid("relation_"); + $field = $relation->key; + } - $repository->select("{$repository->alias}.*") - ->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName(), $relation->bridge::field($relationRelation->key, $bridgeAlias), $relationRelation->entity::field($relationRelation->foreignKey), $bridgeAlias) - ->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} ); + switch( $relationType ) { + case 'onetoone': + $repository->where( $baseEntity->field($relation->foreignKey), $this->$field ); - $this->$name = call_user_func([ $repository, $relationRelation->function ]); - - if ($relation->bridgeField ?? false) { - $repository = $relationRelation->entity::repository(); + $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository); - $repository->select("$bridgeAlias.*") + $result = call_user_func([$repository, $relation->function]); + + if ( count($result) === 0 ) { + return $baseEntity; + } + + return $this->$name = $result[0]; + + case 'onetomany': + $repository->where( $baseEntity->field($relation->foreignKey), $this->$field); + $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository); + + return $this->$name = call_user_func([$repository, $relation->function]); + + case 'manytomany': + if ( false === $relation->bridge ?? false ) { + throw new \Exception("Your many-to-many @Relation() from variable `$name` is missing a 'bridge' value."); + } + + $bridgeEntity = Ulmus::resolveEntity($relation->bridge); + $bridgeRelation = $bridgeEntity->searchFieldAnnotation($relation->field, new Relation() ); + $relationRelation = $bridgeEntity->searchFieldAnnotation($relation->foreignField, new Relation() ); + + $repository = $relationRelation->entity()->repository(); + + $bridgeAlias = uniqid("bridge_"); + $relationAlias = uniqid("relation_"); + + # @TODO Rewrite to be done here, this code must move somewhere else... + $repository->select("{$repository->alias}.*") ->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName(), $relation->bridge::field($relationRelation->key, $bridgeAlias), $relationRelation->entity::field($relationRelation->foreignKey), $bridgeAlias) ->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} ); - $bridgeName = $relation->bridgeField; + foreach($where as $condition) { + $repository->where($condition->field, $condition->value, $condition->operator); + } + + foreach($order as $item) { + $repository->orderBy($item->field, $item->order); + } + + $this->eventExecute(Event\EntityRelationLoadInterface::class, $name, $repository); - $this->$bridgeName = $repository->collectionFromQuery($relation->bridge); - } - - return $this->$name; - } + $this->$name = call_user_func([ $repository, $relationRelation->function ]); + + if ($relation->bridgeField ?? false) { + $repository = $relationRelation->entity::repository(); + + $repository->select("$bridgeAlias.*") + ->join(Query\Join::TYPE_INNER, $bridgeEntity->tableName(), $relation->bridge::field($relationRelation->key, $bridgeAlias), $relationRelation->entity::field($relationRelation->foreignKey), $bridgeAlias) + ->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} ); + + foreach($where as $condition) { + $repository->where($condition->field, $condition->value, $condition->operator); + } + + foreach($order as $item) { + $repository->orderBy($item->field, $item->order); + } + + $bridgeName = $relation->bridgeField; + + $this->$bridgeName = $repository->collectionFromQuery($relation->bridge); + } + + return $this->$name; + } + + return; + } + } + else { - return; } throw new \Exception(sprintf("[%s] - Undefined variable: %s", static::class, $name)); } + /** + * @Ignore + */ public function __isset(string $name) : bool { + if ( $this->isLoaded() && static::resolveEntity()->searchFieldAnnotation($name, new Relation() ) ) { + return true; + } + return isset($this->$name); } @@ -145,11 +196,11 @@ trait EntityTrait { } if ( $field === null ) { - if ($this->strictEntityFieldsDeclaration ) { + if ($this->entityStrictFieldsDeclaration ) { throw new \Exception("Field `$key` can not be found within your entity ".static::class); } else { - $this->unmatchedEntityDatasetFields[$key] = $value; + $this->entityDatasetUnmatchedFields[$key] = $value; } } elseif ( is_null($value) ) { @@ -178,24 +229,30 @@ trait EntityTrait { if ( ! $loaded ) { #if ( $field !== null ) { # $annotation = $entityResolver->searchFieldAnnotation($field['name'], new Field() ); - # $this->datasetSource[$annotation ? $annotation->name : $field['name']] = $dataset; # <--------- THIS TO FIX !!!!!! + # $this->entityLoadedDataset[$annotation ? $annotation->name : $field['name']] = $dataset; # <--------- THIS TO FIX !!!!!! #} - $this->datasetSource = array_change_key_case($dataset, \CASE_LOWER); + $this->entityLoadedDataset = array_change_key_case($dataset, \CASE_LOWER); } } return $this; } + /** + * @Ignore + */ public function fromArray(iterable $dataset) : self { return $this->entityFillFromDataset($dataset); } - public function entityGetDataset(bool $returnSource = false) : array - { + /** + * @Ignore + */ + public function entityGetDataset(bool $includeRelations = false, bool $returnSource = false) : array + { if ( $returnSource ) { - return $this->datasetSource; + return $this->entityLoadedDataset; } $dataset = []; @@ -226,19 +283,52 @@ trait EntityTrait { } } + # @TODO Must fix recursive bug ! + if ($includeRelations) { + foreach($entityResolver->properties as $name => $field){ + $relation = $entityResolver->searchFieldAnnotation($name, new Relation() ); + + if ( $relation && isset($this->$name) && ($relation->entity ?? $relation->bridge) !== static::class ) { + if ( null !== $value = $this->$name ?? null ) { + if ( is_iterable($value) ) { + $list = []; + + foreach($value as $entity) { + $list[] = $entity->entityGetDataset(true); + } + + $dataset[$name] = $list; + } + elseif ( is_object($value) ) { + $dataset[$name] = $value->entityGetDataset(true); + } + } + } + } + } + return $dataset; } - public function toArray() : array + /** + * @Ignore + */ + public function toArray($includeRelations = false) : array { - return $this->entityGetDataset(); + return $this->entityGetDataset($includeRelations); } + /** + * @Ignore + */ public function toCollection() : array { return new EntityCollection($this->toArray()); } + /** + * @Ignore + */ public function isLoaded() : bool { if ( null === $pkField = $this->resolveEntity()->getPrimaryKeyField($this) ) { @@ -250,12 +340,17 @@ trait EntityTrait { return isset($this->$key); } - + /** + * @Ignore + */ public function __sleep() { return array_keys($this->resolveEntity()->fieldList()); } + /** + * @Ignore + */ public function jsonSerialize() { return $this->entityGetDataset(); @@ -264,7 +359,7 @@ trait EntityTrait { /** * @Ignore */ - public function resolveEntity() : EntityResolver + public static function resolveEntity() : EntityResolver { return Ulmus::resolveEntity(static::class); } diff --git a/src/Event/EntityRelationLoadInterface.php b/src/Event/EntityRelationLoadInterface.php new file mode 100644 index 0000000..26536db --- /dev/null +++ b/src/Event/EntityRelationLoadInterface.php @@ -0,0 +1,9 @@ +eventList[] = $event; + } + + public function eventFromType(string $type) : array + { + return array_filter($this->eventList, fn($ev) => $ev instanceof $type); + } + + public function eventExecute(string $type, ...$arguments) : void + { + foreach($this->eventFromType($type) as $event) { + call_user_func_array([ $event, 'execute'], $arguments); + } + } +} \ No newline at end of file diff --git a/src/Query/Join.php b/src/Query/Join.php index 77033c9..238a3f4 100644 --- a/src/Query/Join.php +++ b/src/Query/Join.php @@ -47,6 +47,6 @@ class Join extends Fragment { public function render() : string { - return $this->renderSegments([ $this->side, static::SQL_TOKEN, $this->table, $this->alias ?? "", $this->attachment, $this->field, "=", $this->value ]); + return $this->renderSegments([ strtoupper($this->side), static::SQL_TOKEN, $this->table, $this->alias ?? "", $this->attachment, $this->field, "=", $this->value ]); } } diff --git a/src/Query/Where.php b/src/Query/Where.php index abd5a74..736d5ec 100644 --- a/src/Query/Where.php +++ b/src/Query/Where.php @@ -112,7 +112,7 @@ class Where extends Fragment { return (in_array($this->operator, [ '!=', '<>' ]) ? Where::CONDITION_NOT . " " : "") . Where::COMPARISON_IN; } - return $this->operator; + return $this->operator; } protected function value() @@ -140,7 +140,7 @@ class Where extends Fragment { return $value->name(); } else { - return $this->queryBuilder->addParameter($this->value); + return $this->queryBuilder->addParameter($value); } } diff --git a/src/QueryBuilder.php b/src/QueryBuilder.php index f9251e7..c597c79 100644 --- a/src/QueryBuilder.php +++ b/src/QueryBuilder.php @@ -174,6 +174,11 @@ class QueryBuilder public function where($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, string $condition = Query\Where::CONDITION_AND, bool $not = false) : self { + # Empty IN case + if ( [] === $value ) { + return $this; + } + if ( $this->where ?? false ) { $where = $this->where; } diff --git a/src/Repository.php b/src/Repository.php index 919d17e..ea89b4f 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -6,6 +6,8 @@ use Ulmus\Common\EntityResolver; class Repository { + use EventTrait; + const DEFAULT_ALIAS = "this"; public ? ConnectionAdapter $adapter; @@ -17,7 +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; @@ -36,9 +40,9 @@ class Repository return $this->where($field, $value)->loadOne(); } - public function loadFromPk($value, $primaryKey = "id") : ? object + public function loadFromPk($value, /* ? stringable */ $primaryKey = null) : ? object { - return $this->loadOneFromField($primaryKey, $value); + return $primaryKey ? $this->loadOneFromField($primaryKey, $value) : $this->wherePrimaryKey($value)->loadOne(); } public function loadAll() : EntityCollection @@ -53,6 +57,10 @@ class Repository public function count() : int { + if ( null !== $select = $this->queryBuilder->getFragment(Query\Select::class) ) { + $this->queryBuilder->removeFragment($select); + } + $this->select("COUNT(*)")->selectSqlQuery(); $this->finalizeQuery(); @@ -79,8 +87,39 @@ class Repository 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 ) { + throw new \Exception(sprintf("No primary key found for entity %s", $this->entityClass)); + } + else { + $pkField = key($primaryKeyDefinition); + + return $this->deleteFromPk($entity->$pkField); + } + + return false; + } + + 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(); @@ -124,7 +163,7 @@ class Repository public function generateDatasetDiff(object $entity) : array { - return array_diff_assoc( array_change_key_case($entity->toArray()), array_change_key_case($entity->entityGetDataset(true)) ); + return array_diff_assoc( array_change_key_case($entity->toArray()), array_change_key_case($entity->entityGetDataset(false, true)) ); } public function yieldAll() : \Generator @@ -294,9 +333,9 @@ class Repository return $this; } - public function orNotHaving($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self + public function orNotHaving($field, $value) : self { - $this->queryBuilder->having($field, $value, $operator, Query\Having::CONDITION_OR, true); + $this->queryBuilder->having($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Having::CONDITION_OR, true); return $this; } @@ -322,9 +361,9 @@ class Repository return $this; } - public function orNotIn($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self + public function orNotIn($field, $value) : self { - return $this->orNot($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR); + return $this->orNot($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true); } public function like($field, $value) : self @@ -436,11 +475,14 @@ class Repository return $this; } + + /* @TODO */ public function commit() : self { return $this; } + /* @TODO */ public function rollback() : self { return $this; @@ -457,6 +499,33 @@ class Repository return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value); } + public function withJoin(/*string|array*/ $fields) : self + { + $resolvedEntity = Ulmus::resolveEntity($this->entityClass); + $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 { $searchRequest->count = $searchRequest->filter( clone $this ) @@ -473,12 +542,12 @@ class Repository ->offset($searchRequest->offset()) ->limit($searchRequest->limit()); } - + public function collectionFromQuery(? string $entityClass = null) : EntityCollection { $class = $entityClass ?: $this->entityClass; - $entityCollection = new EntityCollection(); + $entityCollection = $this->instanciateEntityCollection(); $this->selectSqlQuery(); @@ -487,9 +556,20 @@ class Repository foreach(Ulmus::iterateQueryBuilder($this->queryBuilder, $this->adapter) as $entityData) { $entityCollection->append( ( new $class() )->entityFillFromDataset($entityData) ); } + + $this->eventExecute(Event\RepositoryCollectionFromQueryInterface::class, $entityCollection); return $entityCollection; } + + public function arrayFromQuery() : array + { + $this->selectSqlQuery(); + + $this->finalizeQuery(); + + return Ulmus::datasetQueryBuilder($this->queryBuilder, $this->adapter); + } public function runQuery() : ? \PDOStatement { @@ -556,9 +636,9 @@ class Repository } - public function table() + public function instanciateEntityCollection() : EntityCollection { - return "REFLECT TABLE"; + return new EntityCollection(); } public function escapeTable(string $identifier) : string @@ -576,5 +656,9 @@ class Repository 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 {} } diff --git a/src/Ulmus.php b/src/Ulmus.php index d93e1a2..d2f8bd8 100644 --- a/src/Ulmus.php +++ b/src/Ulmus.php @@ -37,6 +37,25 @@ abstract class Ulmus ]; } + public static function datasetQueryBuilder(QueryBuilder $queryBuilder, ? ConnectionAdapter $adapter = null) : array + { + $rows = []; + + $sql = $queryBuilder->render(); + + $statement = ( $adapter ?: static::$defaultAdapter )->pdo()->select($sql, $queryBuilder->parameters ?? []); + + while ( $row = $statement->fetch() ) { + $rows[] = $row; + } + + $statement->closeCursor(); + + $queryBuilder->reset(); + + return $rows; + } + public static function pdo(? ConnectionAdapter $adapter = null) : Common\PdoObject { return ( $adapter ?: static::$defaultAdapter )->pdo();