From 84da4dbb7b056b01b1717f28dd9f1dae242af8c0 Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Tue, 31 Mar 2020 13:24:15 -0400 Subject: [PATCH] - Bugfixes done linked to SearchRequest and Searchable features. - Fixed a bug introduced into PdoObject exception on latest commit. - Corrected the open() close() enclosure of query condition. --- src/Annotation/Property/Relation.php | 6 +- src/Common/PdoObject.php | 17 ++++- src/Query/Limit.php | 6 +- src/Query/Offset.php | 4 ++ src/Query/Where.php | 2 +- src/QueryBuilder.php | 20 ++++-- src/Repository.php | 62 ++++++++++++++++--- .../SearchRequestPaginationTrait.php | 12 ++++ src/SearchRequest/SearchableInterface.php | 2 +- 9 files changed, 111 insertions(+), 20 deletions(-) diff --git a/src/Annotation/Property/Relation.php b/src/Annotation/Property/Relation.php index 22465f9..ccc60ac 100644 --- a/src/Annotation/Property/Relation.php +++ b/src/Annotation/Property/Relation.php @@ -28,7 +28,11 @@ class Relation implements \Ulmus\Annotation\Annotation { } public function entity() { - $e = $this->entity; + try { + $e = $this->entity; + } catch (\Throwable $ex) { + throw new \Exception("Your @Relation annotation seems to be missing an `entity` entry."); + } return new $e(); } diff --git a/src/Common/PdoObject.php b/src/Common/PdoObject.php index 94a4208..346b4a3 100644 --- a/src/Common/PdoObject.php +++ b/src/Common/PdoObject.php @@ -16,7 +16,13 @@ class PdoObject extends PDO { return $statement; } } catch (\PDOException $e) { - throw $e; + switch ( $e->getCode() ) { + case 42000: + throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters)); + + default: + throw $e; + } } } @@ -26,7 +32,14 @@ class PdoObject extends PDO { return $this->execute($statement, $parameters, true); } } catch (\PDOException $e) { - throw $e; + switch ( $e->getCode() ) { + case 42000: + throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters)); + + default: + throw $e; + } + } return null; diff --git a/src/Query/Limit.php b/src/Query/Limit.php index c855097..e022a96 100644 --- a/src/Query/Limit.php +++ b/src/Query/Limit.php @@ -19,8 +19,12 @@ class Limit extends Fragment { public function render() : string { + if ( $this->limit < 0 ) { + throw new \Exception("An error occured trying to render the LIMIT fragment ; given value has to be > 0. Received {$this->limit}"); + } + return $this->renderSegments([ - sprintf($this->keyword, $this->limit) + sprintf($this->keyword, abs($this->limit)) ]); } } diff --git a/src/Query/Offset.php b/src/Query/Offset.php index b9d8d7e..a92c2f0 100644 --- a/src/Query/Offset.php +++ b/src/Query/Offset.php @@ -17,6 +17,10 @@ class Offset extends Fragment { public function render() : string { + if ( $this->offset < 0 ) { + throw new \Exception("An error occured trying to render the OFFSET fragment ; given value has to be > 0. Received {$this->offset}"); + } + return $this->renderSegments([ 'OFFSET', $this->offset, ]); diff --git a/src/Query/Where.php b/src/Query/Where.php index 6c7e5b9..a660db1 100644 --- a/src/Query/Where.php +++ b/src/Query/Where.php @@ -51,7 +51,7 @@ class Where extends Fragment { public function render() : string { $stack = []; - + foreach ($this->conditionList ?? [] as $key => $item) { if ( $item instanceof Where ) { if ( $item->conditionList ?? false ) { diff --git a/src/QueryBuilder.php b/src/QueryBuilder.php index 800b731..0903b18 100644 --- a/src/QueryBuilder.php +++ b/src/QueryBuilder.php @@ -5,7 +5,7 @@ namespace Ulmus; class QueryBuilder { public Query\Where $where; - + /** * Those are the parameters we are going to bind to PDO. */ @@ -139,7 +139,13 @@ class QueryBuilder public function open(string $condition = Query\Where::CONDITION_AND) : self { - if ( null !== ($this->where ?? false) ) { + if ( null !== ($this->where ?? null) ) { + $this->where->conditionList[] = $new = new Query\Where($this, $condition); + $this->where = $new; + } + else { + $this->where = new Query\Where($this, $condition); + $this->push($this->where); $this->where->conditionList[] = $new = new Query\Where($this, $condition); $this->where = $new; } @@ -149,7 +155,13 @@ class QueryBuilder public function close() : self { - if ( null !== ($this->where ?? false) && $this->where->parent ) { + if ( null !== ($this->where ?? null) && $this->where->parent ) { + + # if an enclosure was opened, and nothing done, we must remove the unused node + if ( empty($this->where->conditionList) && (count($this->where->parent->conditionList) === 1) ) { + unset($this->where->parent->conditionList); + } + $this->where = $this->where->parent; } @@ -167,6 +179,7 @@ class QueryBuilder } $this->conditionOperator = $operator; + $where->add($field, $value, $operator, $condition, $not); return $this; @@ -179,7 +192,6 @@ class QueryBuilder public function groupBy() : self { - //$this->queryBuilder->groupBy(); return $this; } diff --git a/src/Repository.php b/src/Repository.php index 7de41a3..605dbfe 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -217,7 +217,24 @@ class Repository public function wheres(array $fieldValues, string $operator = Query\Where::OPERATOR_EQUAL) : self { foreach($fieldValues as $field => $value) { - $this->where($field, $value, $operator); + if ( is_array($value) ) { + switch ($value[1]) { + case Query\Where::CONDITION_AND: + $this->where($field, $value[0], $operator); + break; + + case Query\Where::CONDITION_OR: + $this->or($field, $value[0], $operator); + break; + + case Query\Where::CONDITION_NOT: + $this->notWhere($field, $value[0], $operator); + break; + } + } + else { + $this->where($field, $value, $operator); + } } return $this; @@ -287,23 +304,46 @@ class Repository public function like($field, $value) : self { - $this->queryBuilder->where($field, $value, Query\Where::OPERATOR_LIKE, Query\Where::CONDITION_AND); + $this->where($field, $value, Query\Where::OPERATOR_LIKE); + + return $this; + } + + public function orLike($field, $value) : self + { + $this->or($field, $value, Query\Where::OPERATOR_LIKE); return $this; } public function notLike($field, $value) : self { - $this->queryBuilder->notWhere($field, $value, Query\Where::OPERATOR_LIKE, Query\Where::CONDITION_AND, true); + $this->notWhere($field, $value, Query\Where::OPERATOR_LIKE); return $this; } - - public function likes(array $fieldValues) : self + public function likes(array $fieldValues, string $condition = Query\Where::CONDITION_AND) : self { foreach($fieldValues as $field => $value) { - $this->like($field, $value); + if ( is_array($value) ) { + switch ($value[1]) { + case Query\Where::CONDITION_AND: + $this->like($field, $value[0]); + break; + + case Query\Where::CONDITION_OR: + $this->orLike($field, $value[0]); + break; + + case Query\Where::CONDITION_NOT: + $this->notLike($field, $value[0]); + break; + } + } + else { + $this->like($field, $value); + } } return $this; @@ -394,14 +434,16 @@ class Repository public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest) : self { - $searchRequest->count = (clone $this)->wheres($searchRequest->wheres()) - ->likes($searchRequest->likes()) + $searchRequest->count = $searchRequest->filter( clone $this ) + ->wheres($searchRequest->wheres(), Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND) + ->likes($searchRequest->likes(), Query\Where::CONDITION_OR) ->orders($searchRequest->orders()) ->groups($searchRequest->groups()) ->count(); - return $this->wheres($searchRequest->wheres()) - ->likes($searchRequest->likes()) + return $searchRequest->filter($this) + ->wheres($searchRequest->wheres(), Query\Where::OPERATOR_EQUAL, Query\Where::CONDITION_AND) + ->likes($searchRequest->likes(), Query\Where::CONDITION_OR) ->orders($searchRequest->orders()) ->groups($searchRequest->groups()) ->offset($searchRequest->offset()) diff --git a/src/SearchRequest/SearchRequestPaginationTrait.php b/src/SearchRequest/SearchRequestPaginationTrait.php index 904fb66..c4d0de9 100644 --- a/src/SearchRequest/SearchRequestPaginationTrait.php +++ b/src/SearchRequest/SearchRequestPaginationTrait.php @@ -10,6 +10,18 @@ trait SearchRequestPaginationTrait { public int $pageCount = 0; + public int $limit = 25; + + public function limit(): int + { + return $this->limit; + } + + public function offset(): int + { + return abs( ( $this->page - 1 ) * $this->limit() ); + } + public function pagination(int $page, int $itemCount) : void { $this->count = $itemCount; diff --git a/src/SearchRequest/SearchableInterface.php b/src/SearchRequest/SearchableInterface.php index 1df871f..7e03292 100644 --- a/src/SearchRequest/SearchableInterface.php +++ b/src/SearchRequest/SearchableInterface.php @@ -6,6 +6,6 @@ use \Psr\Http\Message\ServerRequestInterface; interface SearchableInterface { - public static function searchRequest(ServerRequestInterface $request) : SearchRequestInterface; + public static function searchRequest() : SearchRequestInterface; }