- Multiple bugfixe linked to query fragments
- Added a new SearchRequest package to handle search request efficiently
This commit is contained in:
parent
4b29232543
commit
938639a590
|
@ -27,7 +27,7 @@ class EntityField
|
||||||
# Must use REFLECTION before throwing this value.
|
# Must use REFLECTION before throwing this value.
|
||||||
# Should first check if it's a relation field, and if it is,
|
# Should first check if it's a relation field, and if it is,
|
||||||
# it's real key must be returned (PK usually)
|
# it's real key must be returned (PK usually)
|
||||||
return $useAlias ? "{$this->alias}.\"{$this->name}\"" : "\"{$this->name}\"";
|
return $useAlias ? "{$this->alias}.`{$this->name}`" : "`{$this->name}`";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isScalarType($type) : bool
|
public static function isScalarType($type) : bool
|
||||||
|
|
|
@ -8,8 +8,6 @@ use PDO,
|
||||||
class PdoObject extends PDO {
|
class PdoObject extends PDO {
|
||||||
|
|
||||||
public function select(string $sql, array $parameters = []): PDOStatement {
|
public function select(string $sql, array $parameters = []): PDOStatement {
|
||||||
# var_dump($sql, $parameters); die();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (false !== ( $statement = $this->prepare($sql) )) {
|
if (false !== ( $statement = $this->prepare($sql) )) {
|
||||||
$statement = $this->execute($statement, $parameters, false);
|
$statement = $this->execute($statement, $parameters, false);
|
||||||
|
@ -23,8 +21,6 @@ class PdoObject extends PDO {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function runQuery(string $sql, array $parameters = []): ? PDOStatement {
|
public function runQuery(string $sql, array $parameters = []): ? PDOStatement {
|
||||||
# dump($sql, $parameters); return null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (false !== ( $statement = $this->prepare($sql) )) {
|
if (false !== ( $statement = $this->prepare($sql) )) {
|
||||||
return $this->execute($statement, $parameters, true);
|
return $this->execute($statement, $parameters, true);
|
||||||
|
@ -50,8 +46,9 @@ class PdoObject extends PDO {
|
||||||
}
|
}
|
||||||
|
|
||||||
return $statement;
|
return $statement;
|
||||||
} else {
|
}
|
||||||
throw new PDOException('Could not begin transaction or given statement is invalid.');
|
else {
|
||||||
|
throw new \PDOException($statement->errorCode() . " - " . json_encode($statement->errorInfo()));
|
||||||
}
|
}
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
$this->rollback();
|
$this->rollback();
|
||||||
|
|
|
@ -153,8 +153,21 @@ trait EntityTrait {
|
||||||
foreach($entityResolver->fieldList() as $key => $field) {
|
foreach($entityResolver->fieldList() as $key => $field) {
|
||||||
$annotation = $entityResolver->searchFieldAnnotation($key, new Field() );
|
$annotation = $entityResolver->searchFieldAnnotation($key, new Field() );
|
||||||
|
|
||||||
if ( isset($this->$key) ) {
|
if ( isset($this->$key) ) {
|
||||||
$dataset[ $annotation->name ?? $key ] = is_object($this->$key) ? Ulmus::convertObject($this->$key) : $this->$key;
|
$realKey = $annotation->name ?? $key;
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case is_object($this->$key):
|
||||||
|
$dataset[$realKey] = Ulmus::convertObject($this->$key);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case is_array($this->$key):
|
||||||
|
$dataset[$realKey] = Ulmus::encodeArray($this->$key);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$dataset[$realKey] = $this->$key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif ( $field['nullable'] ) {
|
elseif ( $field['nullable'] ) {
|
||||||
$dataset[ $annotation->name ?? $key ] = null;
|
$dataset[ $annotation->name ?? $key ] = null;
|
||||||
|
|
|
@ -10,6 +10,6 @@ abstract class Fragment {
|
||||||
|
|
||||||
protected function renderSegments(array $segments, string $glue = " ") : string
|
protected function renderSegments(array $segments, string $glue = " ") : string
|
||||||
{
|
{
|
||||||
return implode($glue, array_filter($segments));
|
return implode($glue, array_filter($segments, function($i) { return ! is_null($i) && $i !== false && $i !== ""; }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,6 @@ class Insert extends Fragment {
|
||||||
|
|
||||||
protected function renderTable() : string
|
protected function renderTable() : string
|
||||||
{
|
{
|
||||||
return $this->table;
|
return "`$this->table`";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ class Offset extends Fragment {
|
||||||
public function set($offset) : self
|
public function set($offset) : self
|
||||||
{
|
{
|
||||||
$this->offset = $offset;
|
$this->offset = $offset;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,14 @@ class OrderBy extends Fragment {
|
||||||
public function set(array $order) : self
|
public function set(array $order) : self
|
||||||
{
|
{
|
||||||
$this->orderBy = $order;
|
$this->orderBy = $order;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add(string $field, ? string $direction = null) : self
|
public function add(string $field, ? string $direction = null) : self
|
||||||
{
|
{
|
||||||
$this->orderBy[] = [ $field, $direction ];
|
$this->orderBy[] = [ $field, $direction ];
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +25,7 @@ class OrderBy extends Fragment {
|
||||||
{
|
{
|
||||||
$list = array_map(function($item) {
|
$list = array_map(function($item) {
|
||||||
list($field, $direction) = $item;
|
list($field, $direction) = $item;
|
||||||
|
|
||||||
return $field . ( $direction ? " $direction" : "" );
|
return $field . ( $direction ? " $direction" : "" );
|
||||||
}, $this->orderBy);
|
}, $this->orderBy);
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,12 @@ class Update extends Fragment {
|
||||||
'UPDATE',
|
'UPDATE',
|
||||||
( $this->priority ?? false ),
|
( $this->priority ?? false ),
|
||||||
( $this->ignore ? 'IGNORE' : false ),
|
( $this->ignore ? 'IGNORE' : false ),
|
||||||
$this->table,
|
$this->renderTable(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function renderTable() : string
|
protected function renderTable() : string
|
||||||
{
|
{
|
||||||
return $this->table;
|
return "`$this->table`";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ class Values extends Fragment {
|
||||||
public function render() : string
|
public function render() : string
|
||||||
{
|
{
|
||||||
$this->queryBuilder->addValues($this->flattenRowsArray());
|
$this->queryBuilder->addValues($this->flattenRowsArray());
|
||||||
|
|
||||||
return $this->renderSegments([
|
return $this->renderSegments([
|
||||||
'VALUES', $this->renderParameterPlaceholders(),
|
'VALUES', $this->renderParameterPlaceholders(),
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -165,7 +165,7 @@ class QueryBuilder
|
||||||
$this->where = $where = new Query\Where($this);
|
$this->where = $where = new Query\Where($this);
|
||||||
$this->push($where);
|
$this->push($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->conditionOperator = $operator;
|
$this->conditionOperator = $operator;
|
||||||
$where->add($field, $value, $operator, $condition, $not);
|
$where->add($field, $value, $operator, $condition, $not);
|
||||||
|
|
||||||
|
|
|
@ -53,15 +53,11 @@ class Repository
|
||||||
|
|
||||||
public function count() : int
|
public function count() : int
|
||||||
{
|
{
|
||||||
$this->select("count(*) as totalItem")->selectSqlQuery();
|
$this->select("count(*)")->selectSqlQuery();
|
||||||
|
|
||||||
$this->finalizeQuery();
|
$this->finalizeQuery();
|
||||||
|
|
||||||
foreach(Ulmus::iterateQueryBuilder($this->queryBuilder, $this->adapter) as $entityData) {
|
|
||||||
return $entityData['totalItem'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return Ulmus::runQuery($this->queryBuilder, $this->adapter)->fetchColumn(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteOne()
|
public function deleteOne()
|
||||||
|
@ -218,6 +214,15 @@ class Repository
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function wheres(array $fieldValues, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
||||||
|
{
|
||||||
|
foreach($fieldValues as $field => $value) {
|
||||||
|
$this->where($field, $value, $operator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function and($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
public function and($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
||||||
{
|
{
|
||||||
return $this->where($field, $value, $operator);
|
return $this->where($field, $value, $operator);
|
||||||
|
@ -237,9 +242,9 @@ class Repository
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function orNot($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
|
public function orNot($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->notWhere($condition, Query\Where::CONDITION_OR, true);
|
$this->queryBuilder->notWhere($field, $value, $operator, Query\Where::CONDITION_OR, true);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -289,11 +294,21 @@ class Repository
|
||||||
|
|
||||||
public function notLike($field, $value) : self
|
public function notLike($field, $value) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->where($field, $value, Query\Where::OPERATOR_LIKE, Query\Where::CONDITION_AND, true);
|
$this->queryBuilder->notWhere($field, $value, Query\Where::OPERATOR_LIKE, Query\Where::CONDITION_AND, true);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function likes(array $fieldValues) : self
|
||||||
|
{
|
||||||
|
foreach($fieldValues as $field => $value) {
|
||||||
|
$this->like($field, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function match() : self
|
public function match() : self
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -316,10 +331,15 @@ class Repository
|
||||||
|
|
||||||
public function groupBy() : self
|
public function groupBy() : self
|
||||||
{
|
{
|
||||||
#$this->queryBuilder->groupBy();
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function groups(array $groups) : self
|
||||||
|
{
|
||||||
|
# foreach($this->groups)
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function orderBy($field, ? string $direction = null) : self
|
public function orderBy($field, ? string $direction = null) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->orderBy($field, $direction);
|
$this->queryBuilder->orderBy($field, $direction);
|
||||||
|
@ -327,6 +347,16 @@ class Repository
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function orders(array $orderList) : self
|
||||||
|
{
|
||||||
|
foreach($orderList as $field => $direction) {
|
||||||
|
$this->queryBuilder->orderBy($field, $direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function limit(int $value) : self
|
public function limit(int $value) : self
|
||||||
{
|
{
|
||||||
$this->queryBuilder->limit($value);
|
$this->queryBuilder->limit($value);
|
||||||
|
@ -362,9 +392,24 @@ class Repository
|
||||||
return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value);
|
return $this->where($primaryKeyField[$pkField]->name ?? $pkField, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest) : self
|
||||||
|
{
|
||||||
|
$searchRequest->count = (clone $this)->wheres($searchRequest->wheres())
|
||||||
|
->likes($searchRequest->likes())
|
||||||
|
->orders($searchRequest->orders())
|
||||||
|
->groups($searchRequest->groups())
|
||||||
|
->count();
|
||||||
|
|
||||||
|
return $this->wheres($searchRequest->wheres())
|
||||||
|
->likes($searchRequest->likes())
|
||||||
|
->orders($searchRequest->orders())
|
||||||
|
->groups($searchRequest->groups())
|
||||||
|
->offset($searchRequest->offset())
|
||||||
|
->limit($searchRequest->limit());
|
||||||
|
}
|
||||||
|
|
||||||
protected function collectionFromQuery() : EntityCollection
|
protected function collectionFromQuery() : EntityCollection
|
||||||
{
|
{
|
||||||
|
|
||||||
$class = $this->entityClass;
|
$class = $this->entityClass;
|
||||||
|
|
||||||
$entityCollection = new EntityCollection();
|
$entityCollection = new EntityCollection();
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\SearchRequest;
|
||||||
|
|
||||||
|
interface SearchRequestInterface {
|
||||||
|
public function wheres() : iterable;
|
||||||
|
|
||||||
|
public function likes() : iterable;
|
||||||
|
|
||||||
|
public function orders() : iterable;
|
||||||
|
|
||||||
|
public function groups() : iterable;
|
||||||
|
|
||||||
|
public function limit() : int;
|
||||||
|
|
||||||
|
public function offset() : int;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\SearchRequest;
|
||||||
|
|
||||||
|
trait SearchRequestPaginationTrait {
|
||||||
|
|
||||||
|
public int $count = 0;
|
||||||
|
|
||||||
|
public int $page = 1;
|
||||||
|
|
||||||
|
public int $pageCount = 0;
|
||||||
|
|
||||||
|
public function pagination(int $page, int $itemCount) : void
|
||||||
|
{
|
||||||
|
$this->count = $itemCount;
|
||||||
|
$this->page = $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pageCount() : int
|
||||||
|
{
|
||||||
|
return ceil($this->count / $this->limit());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasPagination() : int
|
||||||
|
{
|
||||||
|
return $this->pageCount() > 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Ulmus\SearchRequest;
|
||||||
|
|
||||||
|
use \Psr\Http\Message\ServerRequestInterface;
|
||||||
|
|
||||||
|
interface SearchableInterface {
|
||||||
|
|
||||||
|
public static function searchRequest(ServerRequestInterface $request) : SearchRequestInterface;
|
||||||
|
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ abstract class Ulmus
|
||||||
}
|
}
|
||||||
|
|
||||||
$statement->closeCursor();
|
$statement->closeCursor();
|
||||||
|
|
||||||
$queryBuilder->reset();
|
$queryBuilder->reset();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -68,12 +69,17 @@ abstract class Ulmus
|
||||||
{
|
{
|
||||||
return ( static::$objectInstanciator ?? static::$objectInstanciator = new Entity\ObjectInstanciator() )->instanciate($type, $arguments);
|
return ( static::$objectInstanciator ?? static::$objectInstanciator = new Entity\ObjectInstanciator() )->instanciate($type, $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function convertObject(object $obj)
|
public static function convertObject(object $obj)
|
||||||
{
|
{
|
||||||
return ( static::$objectInstanciator ?? static::$objectInstanciator = new Entity\ObjectInstanciator() )->convert($obj);
|
return ( static::$objectInstanciator ?? static::$objectInstanciator = new Entity\ObjectInstanciator() )->convert($obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function encodeArray(array $array)
|
||||||
|
{
|
||||||
|
return json_encode($array);
|
||||||
|
}
|
||||||
|
|
||||||
public static function registerAdapter(ConnectionAdapter $adapter, bool $default = false) : void
|
public static function registerAdapter(ConnectionAdapter $adapter, bool $default = false) : void
|
||||||
{
|
{
|
||||||
if ($default) {
|
if ($default) {
|
||||||
|
|
Loading…
Reference in New Issue