All Projects → mohammad-fouladgar → Eloquent Builder

mohammad-fouladgar / Eloquent Builder

Licence: mit
Provides an advanced filter for Laravel or Lumen model.

Projects that are alternatives of or similar to Eloquent Builder

Elasticsearch
The missing elasticsearch ORM for Laravel, Lumen and Native php applications
Stars: ✭ 375 (+42.05%)
Mutual labels:  eloquent, query-builder, laravel
Laravel Eloquent Query Cache
Adding cache on your Laravel Eloquent queries' results is now a breeze.
Stars: ✭ 529 (+100.38%)
Mutual labels:  eloquent, query-builder, laravel
Querybuilderparser
A simple to use query builder for the jQuery QueryBuilder plugin for use with Laravel.
Stars: ✭ 126 (-52.27%)
Mutual labels:  eloquent, query-builder, laravel
Cms
Multilingual PHP CMS built with Laravel and bootstrap
Stars: ✭ 2,342 (+787.12%)
Mutual labels:  eloquent, laravel
Quicksand
Easily schedule regular cleanup of old soft-deleted Eloquent data.
Stars: ✭ 259 (-1.89%)
Mutual labels:  eloquent, laravel
Laravel Migrate Fresh
An artisan command to build up a database from scratch
Stars: ✭ 179 (-32.2%)
Mutual labels:  eloquent, laravel
Schedule
Schedule is a package that helps tracking schedules for your models. If you have workers in a company, you can set schedules for them and see their availability though the time.
Stars: ✭ 155 (-41.29%)
Mutual labels:  eloquent, laravel
Blogetc
Easily add a full Laravel blog (with built in admin panel and public views) to your laravel project with this simple package.
Stars: ✭ 198 (-25%)
Mutual labels:  eloquent, laravel
Eloquent Hashids
On-the-fly hashids for Laravel Eloquent models. (🍰 Easy & ⚡ Fast)
Stars: ✭ 196 (-25.76%)
Mutual labels:  eloquent, laravel
Laravel Jit Loader
Stars: ✭ 210 (-20.45%)
Mutual labels:  eloquent, laravel
Bouncer
Eloquent roles and abilities.
Stars: ✭ 2,763 (+946.59%)
Mutual labels:  eloquent, laravel
Eloquent Filter
The Eloquent Filter is a package for filter data of models by the query string. Easy to use and fully dynamic.
Stars: ✭ 175 (-33.71%)
Mutual labels:  eloquent, laravel
Laravel Auditing
Record the change log from models in Laravel
Stars: ✭ 2,210 (+737.12%)
Mutual labels:  eloquent, laravel
Larapoll
A Laravel package to manage your polls
Stars: ✭ 189 (-28.41%)
Mutual labels:  eloquent, laravel
Rating
Laravel Eloquent Rating allows you to assign ratings to any model.
Stars: ✭ 175 (-33.71%)
Mutual labels:  eloquent, laravel
Laravel Computed Properties
Make your accessors smarter
Stars: ✭ 197 (-25.38%)
Mutual labels:  eloquent, laravel
Laravel Database Encryption
A package for automatically encrypting and decrypting Eloquent attributes in Laravel 5.5+, based on configuration settings.
Stars: ✭ 238 (-9.85%)
Mutual labels:  eloquent, laravel
laravel-query-inspector
The missing laravel helper that allows you to inspect your eloquent queries with it's bind parameters
Stars: ✭ 59 (-77.65%)
Mutual labels:  eloquent, query-builder
laravel-arangodb
ArangoDB driver for Laravel
Stars: ✭ 43 (-83.71%)
Mutual labels:  eloquent, query-builder
Laravel Model Expires
A package to assign expiration dates to Eloquent models.
Stars: ✭ 148 (-43.94%)
Mutual labels:  eloquent, laravel

Provides a Eloquent query builder for Laravel or Lumen

alt text

Build Status Coverage Status Test Status Code Style Status Total Downloads License

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 clean and maintainable.

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 a common implementation, following code will be expected:

<?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 will turns into this:

<?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 a filter for each parameter that you want to add to the query.

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.

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:

├── app
├── Console
│   └── Kernel.php
├── EloquentFilters
│   └── User
│       ├── AgeMoreThanFilter.php
│       └── GenderFilter.php
└── Exceptions
    └── Handler.php

Customize via 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\\',
];

Customize per domain/module

When you have a laravel project with custom directory structure, you might need to have multiple filters in multiple directories. For this purpose, you can use setFilterNamespace() method and pass the desired namespace to it.

For example, let's assume you have a project which implement a domain based structure:

.
├── app
├── bootstrap
├── config
├── database
├── Domains
│   ├── Store
│   │   ├── database
│   │   │   └── migrations
│   │   ├── src
│   │       ├── Filters // we put our Store domain filters here!
│   │       │   └── StoreFilter.php
│   │       ├── Entities
│   │       ├── Http
│   │          └── Controllers
│   │       ├── routes
│   │       └── Services
│   ├── User
│   │   ├── database
│   │   │   └── migrations
│   │   ├── src
│   │       ├── Filters // we put our User domain filters here!
│   │       │   └── UserFilter.php
│   │       ├── Entities
│   │       ├── Http
│   │          └── Controllers
│   │       ├── routes
│   │       └── Services
...

In the above example, each domain has its own filters directory. So we can set and use filters custom namespace as following:

$stores = EloquentBuilder::setFilterNamespace('Domains\\Store\\Filters')
                        ->to(\Domains\Entities\Store::class, $filters)->get();

Note: When using setFilterNamespace(), default namespace and config file will be ignored.

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.

Define filter[s] by artisan command

If you want to create a filter easily, you can use eloquent-builder:make artisan command. This command will accept at least two arguments which are Model and Filter:

php artisan eloquent-builder:make user age_more_than

There is also a possibility of creating multiple filters at the same time. To achieve this goal, you should pass multiple names to Filter argument:

php artisan eloquent-builder:make user age_more_than gender

Use a filter

You can use filters in multiple approaches:

<?php

// Use by a model class name
$users = EloquentBuilder::to(\App\User::class, request()->all())->get();

// Use by existing query
$query = \App\User::where('is_active', true);
$users = EloquentBuilder::to($query, request()->all())->where('city', 'london')->get();

// Use by instance of a model
$users = EloquentBuilder::to(new \App\User(), request()->filter)->get();

Tip: It's recommended to put your query params inside a filter key as below:

user/search?filter[age_more_than]=25&filter[gender]=male

And then use them this way: request()->filter.

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->filter);

// filters result will be:
$filters = [
    'published_post'  => true
];

Only the "published_post" filter will be applied on your query.

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 implements UserRepositoryInterface
{
    
    public function __construct(EloquentBuilder $eloquentBuilder,User $user)
    {
        $this->eloquentBuilder = $eloquentBuilder;
        $this->model = $user;
    }

    /**
     * On method call
     */
    public function __call($method, $arguments)
    {
        return $this->model->$method(...$arguments);
    }

    // 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->filters)->get();
    }
}

Testing

composer test

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email [email protected] 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.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].