From 2a68e5d27d913b6a097492a233b288ac4181dfcd Mon Sep 17 00:00:00 2001 From: Carghaez Date: Wed, 26 Jul 2017 21:13:27 +0200 Subject: [PATCH 01/10] Add support to MySQL for keyword LIKE. The keyword ILIKE can be used instead of LIKE to make the match case insensitive according to the active locale. This is not in the SQL standard but is a PostgreSQL extension. --- src/EloquentBuilderTrait.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index bc77093..fc7b539 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -5,6 +5,7 @@ use DB; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Support\Facades\Config; use InvalidArgumentException; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; @@ -84,6 +85,8 @@ protected function applyFilter(Builder $query, array $filter, $or = false, array // $value, $not, $key, $operator extract($filter); + $dbType = Config::get('database.default'); + $table = $query->getModel()->getTable(); if ($value === 'null' || $value === '') { @@ -105,8 +108,9 @@ protected function applyFilter(Builder $query, array $filter, $or = false, array 'sw' => $value.'%' // starts with ]; - $databaseField = DB::raw(sprintf('CAST(%s.%s AS TEXT)', $table, $key)); - $clauseOperator = $not ? 'NOT ILIKE' : 'ILIKE'; + $castToText = (($dbType === 'postgres') ? 'TEXT' : 'CHAR'); + $databaseField = DB::raw(sprintf('CAST(%s.%s AS ' . $castToText . ')', $table, $key)); + $clauseOperator = ($not ? 'NOT':'') . (($dbType === 'postgres') ? 'ILIKE' : 'LIKE'); $value = $valueString[$operator]; break; case 'eq': From e43b3aaa7e4aaa4d2c07f30598abe8c538dad827 Mon Sep 17 00:00:00 2001 From: Carghaez Date: Wed, 26 Jul 2017 21:14:50 +0200 Subject: [PATCH 02/10] Add support to laravel 5.4.* for relation keys --- src/EloquentBuilderTrait.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index fc7b539..d379408 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -221,9 +221,9 @@ private function joinRelatedModelIfExists(Builder $query, $key) if ($relation instanceof BelongsTo) { $query->join( $relation->getRelated()->getTable(), - $model->getTable().'.'.$relation->getForeignKey(), + $model->getTable().'.'.$relation->getQualifiedForeignKeyName(), '=', - $relation->getRelated()->getTable().'.'.$relation->getOtherKey(), + $relation->getRelated()->getTable().'.'.$relation->getOwnerKey(), $type ); } elseif ($relation instanceof BelongsToMany) { @@ -231,14 +231,14 @@ private function joinRelatedModelIfExists(Builder $query, $key) $relation->getTable(), $relation->getQualifiedParentKeyName(), '=', - $relation->getForeignKey(), + $relation->getQualifiedForeignKeyName(), $type ); $query->join( $relation->getRelated()->getTable(), $relation->getRelated()->getTable().'.'.$relation->getRelated()->getKeyName(), '=', - $relation->getOtherKey(), + $relation->getQualifiedRelatedKeyName(), $type ); } else { @@ -246,7 +246,7 @@ private function joinRelatedModelIfExists(Builder $query, $key) $relation->getRelated()->getTable(), $relation->getQualifiedParentKeyName(), '=', - $relation->getForeignKey(), + $relation->getQualifiedForeignKeyName(), $type ); } From 139c4aaf5caa630bc08441f5a0c3c23cffaa6cf4 Mon Sep 17 00:00:00 2001 From: Carghaez Date: Wed, 26 Jul 2017 21:15:28 +0200 Subject: [PATCH 03/10] Minor fixes --- src/LaravelController.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/LaravelController.php b/src/LaravelController.php index 751c1a4..6ec6c87 100644 --- a/src/LaravelController.php +++ b/src/LaravelController.php @@ -2,7 +2,9 @@ namespace Optimus\Bruno; +use JsonSerializable; use InvalidArgumentException; +use Illuminate\Contracts\Support\Arrayable; use Illuminate\Routing\Controller; use Illuminate\Routing\Router; use Illuminate\Http\JsonResponse; @@ -10,6 +12,10 @@ abstract class LaravelController extends Controller { + /** + * Defaults + * @var array + */ protected $defaults = []; /** @@ -37,11 +43,16 @@ protected function response($data, $statusCode = 200, array $headers = []) */ protected function parseData($data, array $options, $key = null) { - $architect = new Architect; + $architect = new Architect(); return $architect->parseData($data, $options['modes'], $key); } + /** + * Page sort + * @param array $sort + * @return array + */ protected function parseSort(array $sort) { return array_map(function($sort) { if (!isset($sort['direction'])) { @@ -82,7 +93,7 @@ protected function parseIncludes(array $includes) * Parse filter group strings into filters * Filters are formatted as key:operator(value) * Example: name:eq(esben) - * @param array $filters + * @param array $filter_groups * @return array */ protected function parseFilterGroups(array $filter_groups) From 130d9c9c9638b52e06bdde5ee5df2d203f4ec8e6 Mon Sep 17 00:00:00 2001 From: Carghaez Date: Thu, 27 Jul 2017 01:18:47 +0200 Subject: [PATCH 04/10] Minor update: change $query to $queryBuilder follows the laravel's standard. --- src/EloquentBuilderTrait.php | 56 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index d379408..a6879f7 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -14,11 +14,11 @@ trait EloquentBuilderTrait { /** * Apply resource options to a query builder - * @param Builder $query + * @param Builder $queryBuilder * @param array $options * @return Builder */ - protected function applyResourceOptions(Builder $query, array $options = []) + protected function applyResourceOptions(Builder $queryBuilder, array $options = []) { if (!empty($options)) { extract($options); @@ -28,11 +28,11 @@ protected function applyResourceOptions(Builder $query, array $options = []) throw new InvalidArgumentException('Includes should be an array.'); } - $query->with($includes); + $queryBuilder->with($includes); } if (isset($filter_groups)) { - $filterJoins = $this->applyFilterGroups($query, $filter_groups); + $filterJoins = $this->applyFilterGroups($queryBuilder, $filter_groups); } if (isset($sort)) { @@ -44,29 +44,29 @@ protected function applyResourceOptions(Builder $query, array $options = []) $filterJoins = []; } - $sortingJoins = $this->applySorting($query, $sort, $filterJoins); + $sortingJoins = $this->applySorting($queryBuilder, $sort, $filterJoins); } if (isset($limit)) { - $query->limit($limit); + $queryBuilder->limit($limit); } if (isset($page)) { - $query->offset($page*$limit); + $queryBuilder->offset($page*$limit); } } - return $query; + return $queryBuilder; } - protected function applyFilterGroups(Builder $query, array $filterGroups = [], array $previouslyJoined = []) + protected function applyFilterGroups(Builder $queryBuilder, array $filterGroups = [], array $previouslyJoined = []) { $joins = []; foreach ($filterGroups as $group) { $or = $group['or']; $filters = $group['filters']; - $query->where(function (Builder $query) use ($filters, $or, &$joins) { + $queryBuilder->where(function (Builder $query) use ($filters, $or, &$joins) { foreach ($filters as $filter) { $this->applyFilter($query, $filter, $or, $joins); } @@ -74,25 +74,25 @@ protected function applyFilterGroups(Builder $query, array $filterGroups = [], a } foreach(array_diff($joins, $previouslyJoined) as $join) { - $this->joinRelatedModelIfExists($query, $join); + $this->joinRelatedModelIfExists($queryBuilder, $join); } return $joins; } - protected function applyFilter(Builder $query, array $filter, $or = false, array &$joins) + protected function applyFilter(Builder $queryBuilder, array $filter, $or = false, array &$joins) { // $value, $not, $key, $operator extract($filter); $dbType = Config::get('database.default'); - $table = $query->getModel()->getTable(); + $table = $queryBuilder->getModel()->getTable(); if ($value === 'null' || $value === '') { $method = $not ? 'WhereNotNull' : 'WhereNull'; - call_user_func([$query, $method], sprintf('%s.%s', $table, $key)); + call_user_func([$queryBuilder, $method], sprintf('%s.%s', $table, $key)); } else { $method = filter_var($or, FILTER_VALIDATE_BOOLEAN) ? 'orWhere' : 'where'; $clauseOperator = null; @@ -145,7 +145,7 @@ protected function applyFilter(Builder $query, array $filter, $or = false, array $customFilterMethod = $this->hasCustomMethod('filter', $key); if ($customFilterMethod) { call_user_func_array([$this, $customFilterMethod], [ - $query, + $queryBuilder, $method, $clauseOperator, $value, @@ -158,11 +158,11 @@ protected function applyFilter(Builder $query, array $filter, $or = false, array } else { // In operations do not have an operator if ($operator === 'in') { - call_user_func_array([$query, $method], [ + call_user_func_array([$queryBuilder, $method], [ $databaseField, $value ]); } else { - call_user_func_array([$query, $method], [ + call_user_func_array([$queryBuilder, $method], [ $databaseField, $clauseOperator, $value ]); } @@ -170,7 +170,7 @@ protected function applyFilter(Builder $query, array $filter, $or = false, array } } - protected function applySorting(Builder $query, array $sorting, array $previouslyJoined = []) + protected function applySorting(Builder $queryBuilder, array $sorting, array $previouslyJoined = []) { $joins = []; foreach($sorting as $sortRule) { @@ -186,14 +186,14 @@ protected function applySorting(Builder $query, array $sorting, array $previousl if ($customSortMethod) { $joins[] = $key; - call_user_func([$this, $customSortMethod], $query, $direction); + call_user_func([$this, $customSortMethod], $queryBuilder, $direction); } else { - $query->orderBy($key, $direction); + $queryBuilder->orderBy($key, $direction); } } foreach(array_diff($joins, $previouslyJoined) as $join) { - $this->joinRelatedModelIfExists($query, $join); + $this->joinRelatedModelIfExists($queryBuilder, $join); } return $joins; @@ -209,9 +209,9 @@ private function hasCustomMethod($type, $key) return false; } - private function joinRelatedModelIfExists(Builder $query, $key) + private function joinRelatedModelIfExists(Builder $queryBuilder, $key) { - $model = $query->getModel(); + $model = $queryBuilder->getModel(); // relationship exists, join to make special sort if (method_exists($model, $key)) { @@ -219,7 +219,7 @@ private function joinRelatedModelIfExists(Builder $query, $key) $type = 'inner'; if ($relation instanceof BelongsTo) { - $query->join( + $queryBuilder->join( $relation->getRelated()->getTable(), $model->getTable().'.'.$relation->getQualifiedForeignKeyName(), '=', @@ -227,14 +227,14 @@ private function joinRelatedModelIfExists(Builder $query, $key) $type ); } elseif ($relation instanceof BelongsToMany) { - $query->join( + $queryBuilder->join( $relation->getTable(), $relation->getQualifiedParentKeyName(), '=', $relation->getQualifiedForeignKeyName(), $type ); - $query->join( + $queryBuilder->join( $relation->getRelated()->getTable(), $relation->getRelated()->getTable().'.'.$relation->getRelated()->getKeyName(), '=', @@ -242,7 +242,7 @@ private function joinRelatedModelIfExists(Builder $query, $key) $type ); } else { - $query->join( + $queryBuilder->join( $relation->getRelated()->getTable(), $relation->getQualifiedParentKeyName(), '=', @@ -252,7 +252,7 @@ private function joinRelatedModelIfExists(Builder $query, $key) } $table = $model->getTable(); - $query->select(sprintf('%s.*', $table)); + $queryBuilder->select(sprintf('%s.*', $table)); } } } From 11edc83191151375a3fd1e8a7ef8ea34038ffe91 Mon Sep 17 00:00:00 2001 From: Carghaez Date: Thu, 27 Jul 2017 01:21:18 +0200 Subject: [PATCH 05/10] Minor update: add docs to methods --- src/EloquentBuilderTrait.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index a6879f7..a2bf1ae 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -59,6 +59,12 @@ protected function applyResourceOptions(Builder $queryBuilder, array $options = return $queryBuilder; } + /** + * @param Builder $queryBuilder + * @param array $filterGroups + * @param array $previouslyJoined + * @return array + */ protected function applyFilterGroups(Builder $queryBuilder, array $filterGroups = [], array $previouslyJoined = []) { $joins = []; @@ -80,6 +86,12 @@ protected function applyFilterGroups(Builder $queryBuilder, array $filterGroups return $joins; } + /** + * @param Builder $queryBuilder + * @param array $filter + * @param bool|false $or + * @param array $joins + */ protected function applyFilter(Builder $queryBuilder, array $filter, $or = false, array &$joins) { // $value, $not, $key, $operator @@ -170,6 +182,12 @@ protected function applyFilter(Builder $queryBuilder, array $filter, $or = false } } + /** + * @param Builder $queryBuilder + * @param array $sorting + * @param array $previouslyJoined + * @return array + */ protected function applySorting(Builder $queryBuilder, array $sorting, array $previouslyJoined = []) { $joins = []; @@ -199,6 +217,11 @@ protected function applySorting(Builder $queryBuilder, array $sorting, array $pr return $joins; } + /** + * @param $type + * @param $key + * @return bool|string + */ private function hasCustomMethod($type, $key) { $methodName = sprintf('%s%s', $type, Str::studly($key)); @@ -209,6 +232,10 @@ private function hasCustomMethod($type, $key) return false; } + /** + * @param Builder $queryBuilder + * @param $key + */ private function joinRelatedModelIfExists(Builder $queryBuilder, $key) { $model = $queryBuilder->getModel(); From 66c175082d5491ac67e53a4fba5fe3e12fcbd806 Mon Sep 17 00:00:00 2001 From: Carghaez Date: Thu, 27 Jul 2017 01:25:18 +0200 Subject: [PATCH 06/10] Minor fix: for better readability and git-friendly function --- src/EloquentBuilderTrait.php | 50 +++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index a2bf1ae..dc29f28 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -20,40 +20,42 @@ trait EloquentBuilderTrait */ protected function applyResourceOptions(Builder $queryBuilder, array $options = []) { - if (!empty($options)) { - extract($options); - - if (isset($includes)) { - if (!is_array($includes)) { - throw new InvalidArgumentException('Includes should be an array.'); - } + if (empty($options)) { + return $queryBuilder; + } - $queryBuilder->with($includes); - } + extract($options); - if (isset($filter_groups)) { - $filterJoins = $this->applyFilterGroups($queryBuilder, $filter_groups); + if (isset($includes)) { + if (!is_array($includes)) { + throw new InvalidArgumentException('Includes should be an array.'); } - if (isset($sort)) { - if (!is_array($sort)) { - throw new InvalidArgumentException('Sort should be an array.'); - } + $queryBuilder->with($includes); + } - if (!isset($filterJoins)) { - $filterJoins = []; - } + if (isset($filter_groups)) { + $filterJoins = $this->applyFilterGroups($queryBuilder, $filter_groups); + } - $sortingJoins = $this->applySorting($queryBuilder, $sort, $filterJoins); + if (isset($sort)) { + if (!is_array($sort)) { + throw new InvalidArgumentException('Sort should be an array.'); } - if (isset($limit)) { - $queryBuilder->limit($limit); + if (!isset($filterJoins)) { + $filterJoins = []; } - if (isset($page)) { - $queryBuilder->offset($page*$limit); - } + $sortingJoins = $this->applySorting($queryBuilder, $sort, $filterJoins); + } + + if (isset($limit)) { + $queryBuilder->limit($limit); + } + + if (isset($page)) { + $queryBuilder->offset($page*$limit); } return $queryBuilder; From 0d2dcab27f3d41326952566d90354c7bc0871c2e Mon Sep 17 00:00:00 2001 From: Carghaez Date: Thu, 27 Jul 2017 01:39:22 +0200 Subject: [PATCH 07/10] Added Support for gte (greater than or equal to) and lte (lesser than or equal to) operators --- README.md | 2 ++ src/EloquentBuilderTrait.php | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index 58d6764..e1394c2 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,9 @@ sw | Starts with | `Gior` matches `Giordano Bruno` but not `Giovanni` ew | Ends with | `uno` matches `Giordano Bruno` but not `Giovanni` eq | Equals | `Giordano Bruno` matches `Giordano Bruno` but not `Bruno` gt | Greater than | `1548` matches `1600` but not `1400` +gte| Greater than or equalTo | `1548` matches `1548` and above lt | Lesser than | `1600` matches `1548` but not `1700` +lte | Lesser than or equalTo | `1600` matches `1600` and below in | In array | `['Giordano', 'Bruno']` matches `Giordano` and `Bruno` but not `Giovanni` **Special values** diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index dc29f28..7dc9924 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -134,9 +134,15 @@ protected function applyFilter(Builder $queryBuilder, array $filter, $or = false case 'gt': $clauseOperator = $not ? '<' : '>'; break; + case 'gte': + $clauseOperator = $not ? '<' : '>='; + break; case 'bt': $clauseOperator = 'between'; break; + case 'lte': + $clauseOperator = $not ? '>' : '<='; + break; case 'lt': $clauseOperator = $not ? '>' : '<'; break; From 63cdff3eb9ad7c08f7c87168580251d6b9d84b6a Mon Sep 17 00:00:00 2001 From: Carghaez Date: Thu, 27 Jul 2017 01:52:05 +0200 Subject: [PATCH 08/10] Update require dependencies to the correct version of Laravel --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d82c828..d6e60b2 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ } }, "require": { - "laravel/framework": "~5.1", + "laravel/framework": "~5.4", "optimus/architect": "~1.0" }, "require-dev": { From 1816755a0d2ab2d798164be47e1e80f19b5b7e25 Mon Sep 17 00:00:00 2001 From: Carghaez Date: Fri, 28 Jul 2017 12:04:31 +0200 Subject: [PATCH 09/10] Remove useless support of bt --- src/EloquentBuilderTrait.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index 7dc9924..ce7e7e7 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -137,9 +137,6 @@ protected function applyFilter(Builder $queryBuilder, array $filter, $or = false case 'gte': $clauseOperator = $not ? '<' : '>='; break; - case 'bt': - $clauseOperator = 'between'; - break; case 'lte': $clauseOperator = $not ? '>' : '<='; break; From 65ea24479173fb7d4d7ed8af713b29c7e44ba821 Mon Sep 17 00:00:00 2001 From: Carghaez Date: Fri, 28 Jul 2017 12:05:53 +0200 Subject: [PATCH 10/10] Add fix of driver name and README.md --- README.md | 12 +++++++++--- src/EloquentBuilderTrait.php | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e1394c2..dc15e9f 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,14 @@ To get started with Bruno I highly recommend my article on ## Installation +For Laravel 5.3 and below ```bash -composer require optimus/bruno ~1.0 +composer require optimus/bruno ~2.0 +``` + +For Laravel 5.4 and above +```bash +composer require optimus/bruno ~3.0 ``` ## Usage @@ -181,9 +187,9 @@ sw | Starts with | `Gior` matches `Giordano Bruno` but not `Giovanni` ew | Ends with | `uno` matches `Giordano Bruno` but not `Giovanni` eq | Equals | `Giordano Bruno` matches `Giordano Bruno` but not `Bruno` gt | Greater than | `1548` matches `1600` but not `1400` -gte| Greater than or equalTo | `1548` matches `1548` and above +gte| Greater than or equalTo | `1548` matches `1548` and above (ony for Laravel 5.4 and above) +lte | Lesser than or equalTo | `1600` matches `1600` and below (ony for Laravel 5.4 and above) lt | Lesser than | `1600` matches `1548` but not `1700` -lte | Lesser than or equalTo | `1600` matches `1600` and below in | In array | `['Giordano', 'Bruno']` matches `Giordano` and `Bruno` but not `Giovanni` **Special values** diff --git a/src/EloquentBuilderTrait.php b/src/EloquentBuilderTrait.php index ce7e7e7..c5ba5e6 100644 --- a/src/EloquentBuilderTrait.php +++ b/src/EloquentBuilderTrait.php @@ -5,7 +5,6 @@ use DB; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Support\Facades\Config; use InvalidArgumentException; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Str; @@ -99,7 +98,7 @@ protected function applyFilter(Builder $queryBuilder, array $filter, $or = false // $value, $not, $key, $operator extract($filter); - $dbType = Config::get('database.default'); + $dbType = $queryBuilder->getConnection()->getDriverName(); $table = $queryBuilder->getModel()->getTable();