diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..640ae76 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/vendor/ +/composer.phar +/composer.lock +.DS_Store +.vscode \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bfc4332 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Awssat Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..270822a --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +## Introduction +Clear previously set statements in Laravel query builder/Eloqent builder easily. + +## Features +- Support most of query builder statemets. (where, limit, order etc..) +- Intuitive, just type ->reset{..} followed by the statement name like: resetLimit() +- Well tested (check tests folder). +- Easy to use .. + + +## Install + +Via Composer +``` bash +composer require awssat/laravel-query-test +``` + +### Before Laravel 5.5 +You'll need to manually register `Awssat\QueryReset\QueryResetServiceProvider::class` service provider in `config/app.php`. + +## Usage +| Query\Builder method | Description | +| --- | --- | +| resetOrder() | remove all `order by ...` statements from the query | +| resetLimit() | remove all `limit ...` statements from the query | +| resetOffset() | remove all `offset ...` statements from the query | +| resetHaving() | remove all `having ...` statements from the query | +| resetWhere() | remove all `where ...` statements from the query | +| resetSelect() | remove all `select ...` statements from the query | +| resetJoin() | remove all `join ...` statements from the query | +| resetDistinct() | remove all `distinct ...` statements from the query | +| resetGroup() | remove all `group by ...` statements from the query | +| resetAggregate() | remove all aggregate's methods statements from the query such as `count`, `max`, `min`, `avg`, and `sum`. | + +| Eloquent\Builder method | Description | +| --- | --- | +| resetWith() or resetEagerLoad() | remove all eager Loads | +| resetScopes() | remove all restrictive scopes | + + +### Examples +```php +$model->orderBy('id')->resetOrder() +``` + +```php +$model->with('items')->resetWith() +``` + +## Usage case +if you're using statements in your relations defining methods or using built in laravel realtions that's using statement by default such as `order by` or a model's scope that interfere with your query ... and you don't want that for a specific query call .. use this package. + + + +## License + +This package is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0e5bdc5 --- /dev/null +++ b/composer.json @@ -0,0 +1,39 @@ +{ + "name": "awssat/laravel-query-reset", + "type": "library", + "description": "Clear previously set statements in Laravel query builder", + "keywords": ["laravel", "builder", "clear", "reset", "query"], + "license": "MIT", + "homepage": "https://github.com/awssat/laravel-query-reset", + "authors": [ + { + "name": "Awssat developers", + "email": "hello@awssat.com" + } + ], + "require": { + "illuminate/database": "5.*", + "illuminate/support": "5.*" + }, + "require-dev": { + "phpunit/phpunit": "^6.1", + "mockery/mockery": "~1.0" + }, + "autoload": { + "psr-4": { + "Awssat\\QueryReset\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Awssat\\QueryReset\\Tests\\": "tests" + } + }, + "extra": { + "laravel": { + "providers": [ + "Awssat\\QueryReset\\QueryResetServiceProvider" + ] + } + } +} diff --git a/src/EloquentReset.php b/src/EloquentReset.php new file mode 100644 index 0000000..611de5d --- /dev/null +++ b/src/EloquentReset.php @@ -0,0 +1,34 @@ + ['variable' => 'eagerLoad', 'set' => []], + 'eagerLoad' => ['variable' => 'eagerLoad', 'set' => []], + 'scopes' => ['variable' => 'scopes', 'set' => []], + ]; + + public static function getMethods() + { + return array_keys(static::$statements); + } + + public static function __callStatic($name, $arguments) + { + $name = lcfirst(str_replace('reset', '', $name)); + + if (array_key_exists($name, static::$statements)) { + $currentStatement = static::$statements[$name]; + + return function () use ($name, $currentStatement) { + $cname = $currentStatement['variable']; + + $this->{$cname} = $currentStatement['set']; + + return $this; + }; + } + } +} \ No newline at end of file diff --git a/src/QueryReset.php b/src/QueryReset.php new file mode 100644 index 0000000..b7d9d3a --- /dev/null +++ b/src/QueryReset.php @@ -0,0 +1,42 @@ + ['variable' => 'orders', 'unions' => true, 'set' => null], + 'limit' => ['variable' => 'limit', 'unions' => true, 'set' => null], + 'offset' => ['variable' => 'offset', 'unions' => true, 'set' => null], + 'having' => ['variable' => 'havings', 'set' => null], + 'where' => ['variable' => 'wheres', 'set' => []], + 'select' => ['variable' => 'columns', 'set' => null], + 'join' => ['variable' => 'joins', 'set' => null], + 'distinct' => ['variable' => 'distinct', 'set' => null], + 'aggregate' => ['variable' => 'aggregate', 'set' => null], + 'group' => ['variable' => 'groups', 'set' => null], + ]; + + public static function getMethods() + { + return array_keys(static::$statements); + } + + public static function __callStatic($name, $arguments) + { + $name = lcfirst(str_replace('reset', '', $name)); + + if (array_key_exists($name, static::$statements)) { + $currentStatement = static::$statements[$name]; + + return function () use ($name, $currentStatement) { + $cname = $currentStatement['variable']; + $unions = $currentStatement['unions'] ?? false; + + $this->{$this->unions && $unions ? 'unions'.ucfirst($cname) : $cname} = $currentStatement['set']; + + return $this; + }; + } + } +} \ No newline at end of file diff --git a/src/QueryResetServiceProvider.php b/src/QueryResetServiceProvider.php new file mode 100644 index 0000000..8d196b4 --- /dev/null +++ b/src/QueryResetServiceProvider.php @@ -0,0 +1,35 @@ +reset* methods to query builder + */ + public function register() + { + //Query builder + Collection::make(QueryReset::getMethods()) + ->reject(function($method) { + return Builder::hasMacro('reset'. ucfirst($method)); + }) + ->each(function($method) { + Builder::macro('reset'. ucfirst($method), QueryReset::$method()); + }); + + //Eloquent builder + Collection::make(EloquentReset::getMethods()) + ->reject(function($method) { + return EloquentBuilder::hasMacro('reset'. ucfirst($method)); + }) + ->each(function($method) { + EloquentBuilder::macro('reset'. ucfirst($method), EloquentReset::$method()); + }); + } +} diff --git a/tests/QueryResetTest.php b/tests/QueryResetTest.php new file mode 100644 index 0000000..f9397ad --- /dev/null +++ b/tests/QueryResetTest.php @@ -0,0 +1,117 @@ +each(function ($item) { + $name = 'reset'.ucfirst($item); + Builder::macro('reset' . ucfirst($item), QueryReset::{$name}()); + }); + + collect(EloquentReset::getMethods()) + ->each(function ($item) { + $name = 'reset'.ucfirst($item); + EloquentBuilder::macro('reset'.ucfirst($item), EloquentReset::{$name}()); + }); + } + + /** + * @test + */ + public function query_rest_class_get_methods_return_non_empty_array() + { + $a = QueryReset::getMethods(); + + $this->assertTrue(is_array($a) && count($a) > 0); + } + + /** + * @test + */ + public function eloquent_rest_class_get_methods_return_non_empty_array() + { + $a = EloquentReset::getMethods(); + + $this->assertTrue(is_array($a) && count($a) > 0); + } + + /** + * @test + */ + public function static_call_of_resetMethod_return_callable() + { + $this->assertTrue(is_callable(QueryReset::resetLimit())); + $this->assertTrue(is_callable(EloquentReset::resetWith())); + } + + /** + * @test + */ + public function query_rest_methods_added_successfully_to_builder() + { + collect(QueryReset::getMethods()) + ->each(function($item) { + $name = 'reset' . ucfirst($item); + $this->assertTrue(Builder::hasMacro($name), "{$name} macro is not loaded!"); + }); + } + + /** + * @test + */ + public function eloquent_rest_methods_added_successfully_to_builder() + { + //EloquentBuilder doesnt have 'hasMacro' currently .. so.. later! + $this->assertTrue(true); + } + + + /** + * @test + */ + public function query_rest_methods_should_really_really_reset() + { + $this->assertNotContains('limit 3', $this->getBuilder()->from('items')->limit(3)->resetLimit()->where('id', '=', 2)->toSql()); + $this->assertNotContains('order by', $this->getBuilder()->from('items')->limit(3)->resetLimit()->where('id', '=', 2)->toSql()); + $this->assertNotContains('offset 12', $this->getBuilder()->from('items')->offset(12)->resetOffset()->orderBy('id')->toSql()); + $this->assertNotContains('name_one', $this->getBuilder()->select('name_one')->from('items')->offset(12)->resetSelect()->toSql()); + $this->assertNotContains('distinct', $this->getBuilder()->distinct()->from('items')->offset(12)->resetDistinct()->toSql()); + } + + /** + * @test + */ + public function eloquent_rest_methods_should_really_really_reset() + { + $this->assertCount(0, $this->getEloquentBuilder()->with(['items'])->resetWith()->getEagerLoads()); + } + + protected function getBuilder() + { + $grammar = new \Illuminate\Database\Query\Grammars\Grammar; + $processor = m::mock('Illuminate\Database\Query\Processors\Processor'); + return new Builder(m::mock('Illuminate\Database\ConnectionInterface'), $grammar, $processor); + } + + protected function getEloquentBuilder() + { + return new EloquentBuilder($this->getBuilder()); + } +} \ No newline at end of file