mjahn / eloquent-builder
Requires
- php: ^7.1
- illuminate/database: ~5.5.0|~5.6.0|~5.7.0|~5.8.0|~6.0
- illuminate/http: ~5.5.0|~5.6.0|~5.7.0|~5.8.0|~6.0
- illuminate/support: ~5.5.0|~5.6.0|~5.7.0|~5.8.0|~6.0
Requires (Dev)
- mockery/mockery: ^1.0.0
- orchestra/testbench: ~3.5.0|~3.6.0|~3.7.0|~3.8.0
- php-coveralls/php-coveralls: ^2.1
- phpunit/phpunit: ^7.1
This package is auto-updated.
Last update: 2024-10-29 06:11:40 UTC
README
This package allows you to build eloquent queries, based on request parameters. It greatly reduces the complexity of the queries and conditions, which will make your code cleaner.
Basic Usage
Suppose you want to get the list of the users with the requested parameters as follows:
//Get api/user/search?age_more_than=25&gender=male&has_published_post=true [ 'age_more_than' => '25', 'gender' => 'male', 'has_published_post' => 'true', ]
In the legacy code the method written below was followed:
<?php namespace App\Http\Controllers; use App\User; use Illuminate\Http\Request; class UserController extends Controller { public function index(Request $request) { $users = User::where('is_active', true); if ($request->has('age_more_than')) { $users->where('age', '>', $request->age_more_than); } if ($request->has('gender')) { $users->where('gender', $request->gender); } // A User model may have an infinite numbers of Post(One-To-Many). if ($request->has('has_published_post')) { $users->where(function ($query) use ($request) { $query->whereHas('posts', function ($query) use ($request) { $query->where('is_published', $request->has_published_post); }); }); } return $users->get(); } }
But after using the EloquentBuilder, the above code refactor as follows:
<?php namespace App\Http\Controllers; use App\User; use EloquentBuilder; use Illuminate\Http\Request; class UserController extends Controller { public function index(Request $request) { $users = EloquentBuilder::to(User::class, $request->all()); return $users->get(); } }
You just need to define filter for each parameter that you want to add to the query.
Tip: It's recommended validates the incoming requests before sending to filters.
Tip: It's recommended present filters inside a filter key in query string like this:
user/search?filter[age_more_than]=25&filter[gender]=male
and then get them in this way:$request->only('filter')
.
Installation
Laravel
You can install the package via composer:
composer require mohammad-fouladgar/eloquent-builder
Laravel 5.5 uses Package Auto-Discovery, so you are not required to add ServiceProvider manually.
Laravel <= 5.4.x
If you don't use Auto-Discovery, add the ServiceProvider to the providers array in config/app.php
file
'providers' => [ /* * Package Service Providers... */ Fouladgar\EloquentBuilder\ServiceProvider::class, ],
And add the facade to your config/app.php
file
/* |-------------------------------------------------------------------------- | Class Aliases |-------------------------------------------------------------------------- */ 'aliases' => [ "EloquentBuilder" => Fouladgar\EloquentBuilder\Facade::class, ]
Lumen
You can install the package via composer:
composer require mohammad-fouladgar/eloquent-builder
For Lumen, add the LumenServiceProvider
to the bootstrap/app.php
file
/* |-------------------------------------------------------------------------- | Register Service Providers... |-------------------------------------------------------------------------- */ $app->register(\Fouladgar\EloquentBuilder\LumenServiceProvider::class);
For using the facade you have to uncomment the line $app->withFacades();
in the bootstrap/app.php
file
After uncommenting this line you have the EloquentBuilder
facade enabled
$app->withFacades();
Publish the configuration file
php artisan eloquent-builder:publish
and add the configuration to the bootstrap/app.php
file
$app->configure('eloquent-builder'); ... $app->register(\Fouladgar\EloquentBuilder\LumenServiceProvider::class);
Important : this needs to be before the registration of the service provider.
Default Filters Namespace
The default namespace for all filters is App\EloquentFilters
with the base name of the Model. For example, the filters namespace will be App\EloquentFilters\User
for the User
model.
With Config file
You can optionally publish the config file with:
php artisan vendor:publish --provider="Fouladgar\EloquentBuilder\ServiceProvider" --tag="config"
And set the namespace for your model filters which will reside in:
return [ /* |-------------------------------------------------------------------------- | Eloquent Filter Settings |-------------------------------------------------------------------------- | | This is the namespace all you Eloquent Model Filters will reside | */ 'namespace' => 'App\\EloquentFilters\\', ];
Define a Filter
Writing a filter is simple. Define a class that extends
the Fouladgar\EloquentBuilder\Support\Foundation\Contracts\Filter
abstract class. This class requires you to implement one method: apply
. The apply
method may add where constraints to the query as needed.
Each filter class should be suffixed with the word Filter
.
For example, take a look at the filter defined below:
<?php namespace App\EloquentFilters\User; use Fouladgar\EloquentBuilder\Support\Foundation\Contracts\Filter; use Illuminate\Database\Eloquent\Builder; class AgeMoreThanFilter extends Filter { /** * Apply the age condition to the query. * * @param Builder $builder * @param mixed $value * * @return Builder */ public function apply(Builder $builder, $value): Builder { return $builder->where('age', '>', $value); } }
Tip: Also, you can easily use local scopes in your filter. Because they are instance of the query builder.
Authorizing Filter
The filter class also contains an authorize
method. Within this method, you may check if the authenticated user actually has the authority to apply a given filter. For example, you may determine if a user has a premium account, can apply the StatusFilter
to get listing the online or offline people:
/** * Determine if the user is authorized to make this filter. * * @return bool */ public function authorize(): bool { if(auth()->user()->hasPremiumAccount()){ return true; } return false }
By default, you do not need to implement the authorize
method and the filter applies to your query builder.
If the authorize
method returns false
, a HTTP response with a 403 status code will automatically be returned.
Ignore Filters on null value
Filter parameters are ignored if contain empty or null values.
Suppose you have a request something like this:
//Get api/user/search?filter[name]&filter[gender]=null&filter[age_more_than]=''&filter[published_post]=true EloquentBuilder::to(User::class,$request->only('filter')); // filters result will be: $filters = [ 'published_post' => true ];
Only the "published_post" filter will be applied on your query.
Work with existing queries
You may also want to work with existing queries. For example, consider the following code:
<?php namespace App\Http\Controllers; use App\User; use EloquentBuilder; use Illuminate\Http\Request; class UserController extends Controller { public function index(Request $request) { $query = User::where('is_active', true); $users = EloquentBuilder::to($query, $request->all()) ->where('city', 'london') ->paginate(); return $users; } }
Use as Dependency Injection
Suppose you want use the EloquentBuilder
as DependencyInjection
in a Repository
.
Let's have an example.We have a sample UserRepository
as follows:
<?php namespace App\Repositories; use App\User; use Fouladgar\EloquentBuilder\EloquentBuilder; class UserRepository extends BaseRepository { public function __construct(EloquentBuilder $eloquentBuilder) { $this->eloquentBuilder = $eloquentBuilder; $this->makeModel(); } public function makeModel() { return $this->setModel($this->model()); } public function setModel($model) { $this->model = app()->make($model); return $this; } public function model() { return User::class; } public function all($columns = ['*']) { return $this->model->get($columns); } // other methods ... public function filters(array $filters) { $this->model = $this->eloquentBuilder->to($this->model(), $filters); return $this; } }
The filters
method applies the requested filters to the query by using EloquentBuilder
injected.
Injecting The Repository
Now,we can simply "type-hint" it in the constructor of our UserController
:
<?php namespace App\Http\Controllers; use App\Repositories\UserRepository; use Illuminate\Http\Request; class UserController extends Controller { protected $users; public function __construct(UserRepository $users) { $this->users = $users; } public function index(Request $request) { return $this->users->filters($request->all())->get(); } }
Testing
composer test
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email fouladgar.dev@gmail.com instead of using the issue tracker.
License
Eloquent-Builder is released under the MIT License. See the bundled LICENSE file for details.
Built with ❤️ for you.