GithubHelp home page GithubHelp logo

mehdi-fathi / eloquent-filter Goto Github PK

View Code? Open in Web Editor NEW
419.0 9.0 41.0 5.86 MB

Eloquent Filter is a package for filter data of models by the query strings. Easy to use and fully dynamic.

Home Page: https://mehdi-fathi.github.io/eloquent-filter/

License: MIT License

PHP 99.97% Makefile 0.03%
laravel php laravel-filter eloquent-filter laravel-filter-url dynamic-filters eloquent eloquent-orm query-filter laravel-query-filter

eloquent-filter's Introduction

Eloquent Filter Tweet

alt text

Latest Stable Version Run tests License GitHub stars Monthly Downloads Scrutinizer Code Quality codecov

Eloquent Filter is a robust Laravel package providing an intuitive way to filter your Eloquent models using query strings. Perfect for crafting responsive APIs and complex data sets, this package seamlessly integrates with Laravel's existing Eloquent models, adding powerful and dynamic filtering capabilities with minimal setup.

Features:

  • Support for complex query structures
  • Easy to override conditions for custom behavior
  • Harmonious integration with Laravel and Eloquent, including query builders
  • Full control over filter execution and customization

We've tailored Eloquent Filter to be as flexible as you needโ€”whether your queries are straightforward or complex. With an extensive feature set, you can implement specific functionalities unique to your application with ease.

Note We considered what predictable features you wanted to implement no matter simple or complex, although we have a lot of features to make able you to implement your specific something's else.

Table of Content

Requirements

  • PHP 8.0,8.1,8.2
  • Laravel 8.x,9.x,10.x,11.x(New)

Version information

The Eloquent Filter has reached more than 100,000 installations recently, so I made a decision to release version 4.0 with 2 new features.

The current version supports:

  • Support query builder along with eloquent
  • Set a specific name for custom methods
Major Version Versions Status PHP Version Laravel Version
^4.0 4.2.0 - 4.x.x Active support >= 8.2 >= 11.x
^4.0 4.0.x - 4.1.5 Active support >= 8.0 >= 9.x - <= 10.x
^3.0 3.2.x - 3.4.x End of life >= 8.0 >= 9.x
^3.0 3.0.0 - 3.0.5 End of life >= 7.4.0 >= 5.6.x - <= 8.x
^2.0 2.0.0 - 2.6.7 End of life <= 7.4.0 >= 5.x - <= 5.4

๐ŸŽค Introduction

Conceivably, you would face challenges if you've done a task as an end-point in which there are some queries with many advanced options.

Let's say we want to make an advanced search page with multiple filter options.

A simple implementation without Eloquent Filter

The Resource URI would be look like:

/users/index?age_more_than=25&gender=male&created_at=25-09-2019

And a simple implementation in the Controller would look like :

<?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);
        }

        if ($request->has('created_at')) {
            $users->where('created_at','>=', $request->created_at);
        }

        return json_encode($users->get());
    }
}

This solution is simple and that works well but not for an enterprise project. But you'd have to add a condition for each filter you need. Especially if you would make more complex filtering, your code can become a monster quickly! ๐Ÿ’ฅ

Hence, Eloquent Filter is ready for to you get rid of complexity in addition to saving time.

A simple implementation with Eloquent Filter

Eloquent Filter can help you to fix that ``problem. Just you will set query string to work with that. It would make your own query automatically and systematically while you can control them.

Right After installing Eloquent Filter, the request URI would be like this:

/users/list?age_more_than[operator]=>&age[value]=35&gender=male&created_at[operator]==>&created_at[value]=25-09-2019

And in the Controller, You just need that one line:

/**
 * Class UsersController.
 */

namespace App\Http\Controllers;

use App\User;

class UsersController
{
    public function list()
    {
        return User::filter()->get();
    }
}

By Eloquent filter implementation, you can use all the documented filters!

๐Ÿ”Œ Installation

1- Run the following command in your project directory to add the Eloquent Filter as a dependency

    $ composer require mehdi-fathi/eloquent-filter
  • Note for Laravel versions older than 5.8 you should install version 2.2.5

      $ composer require mehdi-fathi/eloquent-filter:2.2.5
    
  • Note We support auto-discovery but you can check them.

2- Add eloquentFilter\ServiceProvider::class to provider app.php

'providers' => [
  /*
   * Package Service Providers...
   */
    eloquentFilter\ServiceProvider::class
]

3- Add Facade 'EloquentFilter' => eloquentFilter\Facade\EloquentFilter::class to aliases app.php

'alias' => [
  /*
   * Facade alias...
   */
    'EloquentFilter' => eloquentFilter\Facade\EloquentFilter::class,
],

That's it enjoy! ๐Ÿ’ฅ

๐Ÿ“– Basic Usage

Config Model and set whitelist

Add the Filterable trait to yourself models and set fields in the whitelist array in which you will want to use of filter . You can override this method in your models as well.

use eloquentFilter\QueryFilter\ModelFilters\Filterable;

class User extends Model
{
    use Filterable;
    
    private static $whiteListFilter =[
        'id',
        'username',
        'email',
        'created_at',
        'updated_at',
    ];
}
  • You can set * char for that filter in all fields aslike below example:
private static $whiteListFilter = ['*'];

You able add or set $whiteListFilter on the fly in your method. For example:

Set array to WhiteListFilter

  • Note This method override $whiteListFilter array
User::setWhiteListFilter(['name']); 

Add new field to WhiteListFilter

User::addWhiteListFilter('name'); 

Use in Controller

Change your code the controller of the laravel project as like below example:

namespace App\Http\Controllers;

/**
 * Class UsersController.
 */
class UsersController
{

    public function list()
    {
          if (!empty(request()->get('username'))) {
          
              $users = User::ignoreRequest('perpage')
                        ->filter()
                        ->with('posts')
                        ->orderByDesc('id')
                        ->paginate(request()->get('perpage'),['*'],'page');

          } else {
              $users = User::filter(
                ['username' => ['mehdi','ali']]           
                )->with('posts')
                ->orderByDesc('id')
                ->paginate(10,['*'],'page');
          }
    }
}

-Note The Eloquent Filter config by default uses the query string to make queries in Laravel. Although, you can set the collection data in the filter method Model for making your own custom condition without query string.

-Note Therefore you must unset yourself param as perpage. Just you can set page param for paginate this param ignore from the filter.

  • You can ignore some request params via use of the bellow code.
User::ignoreRequest(['perpage'])
            ->filter()
            ->paginate(request()->get('perpage'), ['*'], 'page');

Call ignoreRequest that will ignore some requests that you don't want to use in conditions of eloquent filter. e.g: the perpage param will never be in the conditions eloquent filter. it's related to the paginate method. page param ignore by default in Eloquent Filter of Laravel.

  • You can filter some request params as acceptable filter.
User::AcceptRequest(['username','id'])
            ->filter()
            ->paginate(request()->get('perpage'), ['*'], 'page');

Call AcceptRequest will accept requests in which you want to use in conditions Eloquent Filter. e.g: username and id key will be in the conditions eloquent filter.

-Note Just in case, you must set $whiteListFilter in Models. Aim of the method avert to manipulation query string by a bad user.

Simple Examples

You just pass data form as query string. For example:

Simple Where

/users/[email protected]

SELECT ... WHERE ... email = '[email protected]'
/users/list?first_name=mehdi&last_name=fathi

SELECT ... WHERE ... first_name = 'mehdi' AND last_name = 'fathi'
  • If you send date format Y-m-d we will work like WhereDate() method Laravel.

Where In

This example make method whereIn.

/users/list?username[]=ali&username[]=ali22&family=ahmadi

SELECT ... WHERE ... username in ('ali','ali22') AND family = 'ahmadi'

OrWhere

This example make method orWhere().

/users/list?name=mehdi&username=fathi&or[username]=ali

SELECT ... WHERE ... name = 'mehdi' AND username = 'fathi' or username = 'ali'

Where like

If you are going to make a query by like conditions. You can do that by this example.

/users/list?first_name[like]=%John%

SELECT ... WHERE ... first_name LIKE '%John%'

Where by operator

You can set any operator mysql in the queries string.

/users/list?count_posts[operator]=>&count_posts[value]=35

SELECT ... WHERE ... count_posts > 35
/users/list?username[operator]=!=&username[value]=ali

SELECT ... WHERE ... username != 'ali'
/users/list?count_posts[operator]=<&count_posts[value]=25

SELECT ... WHERE ... count_posts < 25

Where the nested relations Model

You can set all nested relations in the query string just via the array of query string. imagine, the user model has a relation with posts. And posts table has a relation with orders table.

You can make query conditions by set posts[count_post] and posts[orders][name] in the query string.

  • Just be careful you must set posts.count_post and posts.orders.name in the User model.
use eloquentFilter\QueryFilter\ModelFilters\Filterable;

class User extends Model
{
    use Filterable;
   
    private static $whiteListFilter =[
        'username',
        'posts.count_post',
        'posts.category',
        'posts.orders.name',
    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\belongsTo
     */
    public function posts()
    {
        return $this->belongsTo('Models\Post');
    }

}
/users/list?posts[count_post]=876&username=mehdi

select * from "users" where exists 
         (select * from "posts" where "posts"."user_id" = "users"."id" 
         and "posts"."count_post" = 876)
         and "username" = "mehdi"
  • The above example is the same code that you used without the eloquent filter. Check it under code. It's not amazing?
$builder = (new User())->with('posts');
        $builder->whereHas('posts', function ($q) {
            $q->where('count_post', 876);
        })->where('username','mehdi');

Where array the nested relation Model

You can pass array to make whereIn condition.

/users/list?posts[category][]=php&posts[category][]=laravel&posts[category][]=jquery&username=mehdi

select * from "users" where exists 
         (select * from "posts" where 
         "posts"."category" in ('php','laravel','jquery') )
         and "username" = "mehdi"

Special Params

You can set special params limit and orderBy in the query string to make a query by that.

/users/list?f_params[limit]=1

SELECT ... WHERE ... order by `id` desc limit 1 offset 0
/users/list?f_params[orderBy][field]=id&f_params[orderBy][type]=ASC

SELECT ... WHERE ... order by `id` asc
/users/list?f_params[orderBy][field]=id,count_posts&f_params[orderBy][type]=ASC

SELECT ... WHERE ...  order by `id` asc, `count_posts` asc

Where between

If you are going to make a query based on date, You must fill keys, start, and end in the query string. Hence You can set it as a query string. These params are used for the filter by date.

/users/list?created_at[start]=2016/05/01&created_at[end]=2017/10/01

SELECT ... WHERE ... created_at BETWEEN '2016/05/01' AND '2017/10/01'

Advanced Where

/users/list?count_posts[operator]=>&count_posts[value]=10&username[]=ali&username[]=mehdi&family=ahmadi&created_at[start]=2016/05/01&created_at[end]=2020/10/01
&f_params[orderBy][field]=id&f_params[orderBy][type]=ASC

select * from `users` where `count_posts` > 10 and `username` in ('ali', 'mehdi') and 
`family` = ahmadi and `created_at` between '2016/05/01' and '2020/10/01' order by 'id' asc limit 10 offset 0

Therefore, fields of query string are same rows table database in $whiteListFilter in your model or declare the method in your model as override method. The overridden method can be considered a custom query filter.

Custom Query Filter

Eloquent Filter doesn't support all the conditions by default. For this situation, you can make an overridden method. If you are going to make yourself a query filter, you can do it easily. You should take care of using filterCustom before method name in new version.

You should run the command to make a trait and use it on the model:

php artisan eloquentFilter:filter users
namespace App\ModelFilters;

use Illuminate\Database\Eloquent\Builder;

/**
 * Trait UsersFilter.
 */
trait UsersFilter
{
    /**
     * This is a sample custom query
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @param                                       $value
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function filterCustomSample_like(Builder $builder, $value)
    {
        return $builder->where('username', 'like', '%'.$value.'%');
    }
}

-Note These fields of query string are the same methods of the trait. Use trait in your model:

/users/list?sample_like=a

select * from `users` where `username` like %a% order by `id` desc limit 10 offset 0
use App\ModelFilters\UsersFilter;

class User extends Model
{
    use UsersFilter,Filterable;

    protected $table = 'users';
    protected $guarded = [];
    private static $whiteListFilter =[
        'id',
        'username',
        'email',
        'created_at',
        'updated_at',
    ];
    
}

Some Filter methods

User::filter()->paginate();
  • EloquentFilter::filterRequests() : get all params that used by the Eloquent Filter. You can set key to get specific index. For example EloquentFilter::filterRequests('username') it's getting username index.

  • EloquentFilter::getAcceptedRequest() : get all params that set by the AcceptRequest method.

  • EloquentFilter::getIgnoredRequest() : get all ignored params that set by the getIgnoreRequest method.

Custom Detection Conditions

Sometimes you want to make your custom condition to make a new query that Eloquent Filter doesn't support by default. The good news is you would make a custom condition in the eloquent filter from now on.

You can make conditions to generate a new query after checking by that. For example:

We must have two classes. The First detects conditions second class generates the query.

  • Step 1: Create a class to detect some conditions
use eloquentFilter\QueryFilter\Detection\Contract\DetectorConditionsContract;

/**
 * Class WhereRelationLikeCondition.
 */
class WhereRelationLikeCondition implements DetectorConditionsContract
{
    /**
     * @param $field
     * @param $params
     * @param $is_override_method
     *
     * @return string|null
     */
    public static function detect($field, $params, $is_override_method = false): ?string
    {
        if (!empty($params['value']) && !empty($params['limit']) && !empty($params['email'])) {
            $method = WhereRelationLikeConditionQuery::class;
        }

        return $method ?? null;
    }
}
  • Step 2:Right after, create a class to generate a query. In this example we make WhereRelationLikeConditionQuery class:
use eloquentFilter\QueryFilter\Queries\BaseClause;
use Illuminate\Database\Eloquent\Builder;

/**
 * Class WhereRelationLikeConditionQuery.
 */
class WhereRelationLikeConditionQuery extends BaseClause
{
    /**
     * @param $query
     *
     * @return Builder
     */
    public function apply($query): Builder
    {
        return $query
            ->whereHas('posts', function ($q) {
                $q->where('comment', 'like', "%" . $this->values['like_relation_value'] . "%");
            })
            ->where("$this->filter", '<>', $this->values['value'])
            ->where('email', 'like', "%" . $this->values['email'] . "%")
            ->limit($this->values['limit']);
    }
}
  • Step 3: You make the method EloquentFilterCustomDetection for return array detections of the condition in the model.
use eloquentFilter\QueryFilter\ModelFilters\Filterable;

class User extends Model
{
    use Filterable;
   
    private static $whiteListFilter =[
        'username',
        'posts.count_post',
        'posts.category',
        'posts.orders.name',
    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\belongsTo
     */
    public function posts()
    {
        return $this->belongsTo('Models\Post');
    }

    public function EloquentFilterCustomDetection(): array
    {
        return [
            WhereRelationLikeCondition::class
        ];
    }

}
  • Each of the query params is used to detect in WhereRelationLikeCondition for the first time after that check by default detection eloquent filter.

Make method EloquentFilterCustomDetection in the above example and return array conditions class.

/users/list?username[value]=mehdi&username[limit]=10&username[email]=mehdifathi&username[like_relation_value]=mehdi&count_posts=10

select * from "users"
 where exists (select * from "posts" where 
"users"."post_id" = "posts"."id" 
and "comment" like ?) and "username" <> ? and "email" like ? and "count_posts" = ? limit 10

You just run code User::filter(); for see result.

  • Model::setLoadInjectedDetection(false) : You can deactivate custom detection conditions on the fly.

-Note as well, you can set custom detection on the fly by use of the method SetCustomDetection. For example :

$users = User::SetCustomDetection([WhereRelationLikeCondition::class])->filter();

-Note You can disable EloquentFilterCustomDetection on the fly by this code :

 User::SetLoadDefaultDetection(false)->filter();

-Note You can set many detection conditions. e.g:

class User extends Model
{
    use Filterable;
    public function EloquentFilterCustomDetection(): array
    {
        return [
            WhereRelationLikeCondition::class,
            WhereRelationLikeVersion2Condition::class,
            WhereRelationLikeVersion3Condition::class,
        ];
    }
}
  • EloquentFilter::getInjectedDetections() gets all of your customs injected detection.

-Note Every custom detection will run before any detections by default eloquent filter.

Configuring

You can publish the configuration file to customize the package further:

Publish Config

php artisan vendor:publish --provider="eloquentFilter\ServiceProvider"

Config

  • You can disable/enable Eloquent Filter in the config file (eloquentFilter.php).

      'enabled' => env('EloquentFilter_ENABLED', true),
    
  • Eloquent Filter recognizes every param of the queries string. Maybe you have a query string that you don't want to recognize by Eloquent Filter. You can use ignoreRequest for his purpose. But we have a clean solution to this problem. You can set param request_filter_key in the config file. Therefore, every query string will recognize by the request_filter_key param.

      'request_filter_key' => '', // filter
    

For example, if you set 'request_filter_key' => 'filter', that Eloquent Filter recognizes filter query string.

/users/list?filter[email][email protected]

  • You can disable/enable all the custom detection of Eloquent Filter in the config file (eloquentFilter.php).

      'enabled_custom_detection' => env('EloquentFilter_Custom_Detection_ENABLED', true),
    
  • You should set an index array ignore_request to ignore all filters.

      'ignore_request' => [] //[ 'show_query','new_trend' ],
    
  • You had better keep max_limit. It's a limitation for preventing making awful queries mistakenly by the developer or intentionally by a villain user.

      'max_limit' => 20
    
  • With filtering_keys ,You have a place to declare some provided key and use it in filtering.

      'filtering_keys'=>[
        'title_sport_advanced' => [
            'title' => 'sport',
            'created_at' => [
                'start' => '2019-01-01 17:11:46',
                'end' => '2019-02-06 10:11:46',
            ],
            'sub_cat' => [
                'news 1', 'news 2'
            ],
        ]
      ]
    

    Then you just need to pass config('eloquentFilter.filtering_keys.title_sport_advanced') to filter method.

  • From now on , we have the ability to record logs by logger instance. Since queries is made dynamically somehow , the need of feature keeping queries with their time is required. So we added it in this version with some other options to better management.

      'log' => [
      'has_keeping_query' => false,
      'max_time_query' => null,
      'type' => 'eloquentFilter.query'
      ]
    

    It's disable by default you enable by has_keeping_query, type is type log ,and max_time_query is a value for keeping queries with high time-executed.

Alias

Sometimes you may want to change some parameters in the URL while those mention a field of the model. e.g. name of the input form is not similar to the model ,or you want to change them for other reasons so the alias as a new feature can be useful.

    class Stat extends Model
    {
        use Filterable;
        /**
         * @var array
         */
        private static $whiteListFilter = [
            'type',
            'national_code',
        ];

        /**
         * @var array
         */
        private $aliasListFilter = [
            'national_code' => 'code',
        ];
    }

Then you should send the code param in the URL for making a query with the national code field of the model readily.

Query Builder Introduction

Great news!

Some people asked me a lot to add new feature to support Laravel query builder. It needed a lot of energy and devoting time , so I decided to implement it. It's quite tough however finally it's almost done now.

We are supporting query builder along with eloquent from now on. Not only you would use query builder ,but also you can use eloquent at the same time.

It's a new feature ,and I'm snowed under the code to fix issues. Anyway this feature is up right now with just some limitation. We don't support WhereCustomCondition and WhereHas for query builder at the moment but other conditions were ready to use. in addition, we don't have any kind of whitelist , blacklist , custom detectioon or alias. currently , It's just a simple feature.

  • Below is an order checking conditions list if you use name of them for set a black list.
Name Method eloquent Example
SpecialCondition support f_params, e.g: limit and order
WhereBetweenCondition whereBetween
WhereByOptCondition where where('column', ">", $value)
WhereLikeCondition where where('column', 'like', $value)
WhereInCondition whereIn whereIn('column', $value)
WhereOrCondition orWhere orWhere('column', $value)
WhereDateCondition whereDate whereDate('column', $value)
where where where('column', $value)
  • Usage of them is just extremely like model just you need use filter as a method. Obviously, there's no need any change like use trait or etc.
 DB::table('users')->filter();

Magic Methods

Magic methods are a collection of methods that you can use as a wrapper in the Eloquent Filter. For example, serialize data before filtering or changing data in response and others. Now Eloquent Filter have serializeRequestFilter,ResponseFilter.

Request Filter

Eloquent Filter has a magic method for just change requests injected before handling by eloquent filter. This method is SerializeRequestFilter. You just implement SerializeRequestFilter method in your Model. For example

class User extends Model
{
    use Filterable;
    public function serializeRequestFilter($request)
    {
       $request['username'] = trim($request['username']);
       return $request;
    }
}

As above code, you can modify every query params of the Model in the method serializeRequestFilter before running by Eloquent Filter. That is a practical method when you want to set user_id or convert date or remove space and others.

Response Filter

Response Filter is an overriding method for changing response right after handle by Eloquent Filter. The method called getResponseFilter and You could implement the method getResponseFilter in your Model. e.g:

class User extends Model
{
    use Filterable;
    public function getResponseFilter($response)
    {
        $data['data'] = $response;
        return $data;
    }
}

Black List Detections

Obviously, you never want all users who are able to get data by manipulating requests. As a result, we'd better have an eloquent control feature. Although we have this ability on request side, we need this feature on Eloquent side as well.

We would set a blacklist detection to prevent making conditions by using it. Therefore, that list has been disabled in making conditions. for example:

namespace App\Http\Controllers;

/**
 * Class UsersController.
 */
class UsersController
{

    public function list()
    {
              $users = User::setBlackListDetection(
                  [
                      'WhereCondition',
                  ]
                )->filter()
                ->orderByDesc('id')
                ->paginate();
    }
}
  • Below is an order checking conditions list if you use name of them for set a black list.
Name Method eloquent Example
WhereCustomCondition Your declared custom method of Model
SpecialCondition support f_params, e.g: limit and order
WhereBetweenCondition whereBetween
WhereByOptCondition where where('column', ">", $value)
WhereLikeCondition where where('column', 'like', $value)
WhereInCondition whereIn whereIn('column', $value)
WhereOrCondition orWhere orWhere('column', $value)
WhereHas WhereHas
WhereDateCondition whereDate whereDate('column', $value)
where where where('column', $value)
  • You are able to set on Model layer as well. black_list_detections array is used for this purpose.
<?php

namespace Tests\Models;

use eloquentFilter\QueryFilter\ModelFilters\Filterable;
use Illuminate\Database\Eloquent\Model;

class Car extends Model
{
    use Filterable;
    
    private static $whiteListFilter = '*';

    protected $black_list_detections = [
        'WhereCondition',
    ];
}

Macro Methods

-isUsedEloquentFilter is a macro method for builder to check either query used eloquent-filter.

-getDetectionsInjected is a macro method to get list array of injected objects.

e.g:

        $users = User::SetCustomDetection([WhereRelationLikeCondition::class])->filter();
        echo $users->isUsedEloquentFilter(); // will true
        echo $users->getDetectionsInjected(); // will showing a list array of injected objects

Contributing

If you'd like to contribute to Eloquent Filter, please fork the repository and create a pull request. We welcome contributions of all kinds, including bug fixes, new features, and documentation improvements.

Proposed Features (Under Consideration)

We are constantly working to improve our package and have planned the following features for upcoming releases:

  • Configurable Filter Presets: Implement the ability to define and save filter presets. This feature would allow users to quickly apply common sets of filters without having to specify them each time.

Your contributions are always welcome! If you would like to help with the development of these features.

License

Eloquent Filter is open-source software licensed under the MIT license.

Contact

If you have any questions or feedback about Eloquent Filter, please feel free to contact us at [email protected]. We'd love to hear from you!

Acknowledgements

We'd like to thank the Laravel community for their support and contributions to this project.

eloquent-filter's People

Contributors

clprosser avatar frankyso avatar juliencd avatar kamleshpaul avatar mehdi-fathi avatar ohmydevops avatar orenlande avatar stickler-ci avatar stylecibot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eloquent-filter's Issues

WhereIn request for relationships

I have relation like ' order_details[markets][market_id] ' , and making form get request with select2 multiple parameter.

How to pass the array to request, now I'm getting error like

Call to undefined method App\Models\Markets:market_id()

when I add [] in the last of name attribute like order_details[markets][market_id][], same with order_details[][markets][market_id]

P.S. Thanks for the extension, it's pretty good and understandable than spatie-query-builder. Good job man

f_params[limit]=XXX not working as expected

Hello,

When we use f_params[limit]=\d it gives one result only whatever the limit we provide (it act like we have queried f_params[limit]=1) .

Suggested fix below:

public function apply($query): Builder
{
foreach ($this->values as $key => $param) {
if (!in_array($key, self::$reserve_param['f_params'])) {
throw new \Exception("$key is not in f_params array.");
}
if (is_array($param)) {
$this->values['orderBy']['field'] = explode(',', $this->values['orderBy']['field']);
foreach ($this->values['orderBy']['field'] as $order_by) {
$query->orderBy($order_by, $this->values['orderBy']['type']);
}
} else {
$query->limit($param);
}
}

    return $query;
}

Multiple OrderBy

Hello!

Thank you for this plugin.

Can we make a query with multiple order by please?

Target class [eloquentFilter] does not exist.

Describe the bug
I have followed step by step, but after doing the filter it shows up
Target class [eloquentFilter] does not exist.

To Reproduce
Steps to reproduce the behavior using Laravel 9, PHP 8:

  1. Install
  2. Add provider and alias to app.php
  3. Add trait Filterable in model
  4. Add filter() -> User::filter()->get();

Has anyone have some issue?

Latest version is not working.

I have installed 4.. . And included my searchable columns in whiteListFilter array. In the form I have used name="search". while searching it kept saying to add search to whiteListFilter. After so many days of hard working I have found out it is version issue. Now I have installed 3.4 and it's working for me.

LIKE's search sometimes changes the value's character format

When I make a call to my API with paramters to use LIKE filter it happens that the format of the passed value is cahnged to not UTF8.
This problem causes the error "Malformed UTF-8 characters, possibly incorrectly encoded"

Example of a call to my API's backend:
api/clienti?cliente[LIKE]=%CALOI%

WhereBetweenCondition fails if start or end is zero

Describe the bug
In file eloquent-filter/src/QueryFilter/Detection/ConditionsDetect/WhereBetweenCondition.php the condition fails if start or end is zero

To Reproduce
Steps to reproduce the behavior:
Pass to method detect something like
array ( 'price' => array ( 'start' => 0, 'end' => 336, ) )

Expected behavior
detect returns WhereBetween::class

Actual behavior
detect return null

Where Like %admin% Not Working

Bug description
"where like" query doesn't work only for word %admin% . I have sent directly sql query to database with "select * from users like '%admin%'" and it will show users contains "admin" in the name, but not with eloquent-filter.

Step to reproduce
Steps to reproduce the behavior:

  1. Do request with "where like" params, for example: {{urll}}/api/auth/users?name[like]=%admin%.
  2. Result: no data found.

Expected behavior
Data containing word "admin" appears.

Where Like and operators in nested relation

Is your feature request related to a problem? Please describe.
First of all I want to congratulate you for the great job you did here.
I wish I could use operators and where like in nested relation, like this:

  • select * from users ... ... join posts ... where posts.title like '%program%'
  • select * from users ... ... join posts ... where posts.views > 100
    Kind of "posts[title][like]=%program%" but eloquentFilter expects "like" be a column: posts.title.like.

Describe the solution you'd like
So I was thinking about the last item of the column param be the operator:
posts[title][like]=%program% => posts.title like '%program%'
posts[views][=]=100 => posts.views = 100
posts[views][>]=100 => posts.views > 100

What do you think about it?

When we pass 0 it throw error

Url query string : Job?node_id=0

and getting error

{
"message": "Argument 1 passed to Illuminate\Foundation\Application::handle() must be an instance of Symfony\Component\HttpFoundation\Request, instance of Illuminate\Database\Eloquent\Builder given, called in /var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php on line 167",
"exception": "TypeError",
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Application.php",
"line": 917,
"trace": [
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\Foundation\Application",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 103,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 115,
"function": "then",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/mehdi-fathi/eloquent-filter/src/QueryFilter/QueryFilter.php",
"line": 88,
"function": "thenReturn",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php",
"line": 261,
"function": "apply",
"class": "eloquentFilter\QueryFilter\QueryFilter",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/mehdi-fathi/eloquent-filter/src/QueryFilter/ModelFilters/Filterable.php",
"line": 33,
"function": "__callStatic",
"class": "Illuminate\Support\Facades\Facade",
"type": "::"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
"line": 1315,
"function": "scopeFilter",
"class": "App\Models\MasterJob",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
"line": 1097,
"function": "callNamedScope",
"class": "Illuminate\Database\Eloquent\Model",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
"line": 1078,
"function": "Illuminate\Database\Eloquent\{closure}",
"class": "Illuminate\Database\Eloquent\Builder",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
"line": 1096,
"function": "callScope",
"class": "Illuminate\Database\Eloquent\Builder",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
"line": 1504,
"function": "callNamedScope",
"class": "Illuminate\Database\Eloquent\Builder",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Support/Traits/ForwardsCalls.php",
"line": 23,
"function": "__call",
"class": "Illuminate\Database\Eloquent\Builder",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php",
"line": 1884,
"function": "forwardCallTo",
"class": "Illuminate\Database\Eloquent\Model",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/app/Http/Controllers/JobController.php",
"line": 39,
"function": "__call",
"class": "Illuminate\Database\Eloquent\Model",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Controller.php",
"line": 54,
"function": "index",
"class": "App\Http\Controllers\JobController",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php",
"line": 45,
"function": "callAction",
"class": "Illuminate\Routing\Controller",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 255,
"function": "dispatch",
"class": "Illuminate\Routing\ControllerDispatcher",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Route.php",
"line": 197,
"function": "runController",
"class": "Illuminate\Routing\Route",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 691,
"function": "run",
"class": "Illuminate\Routing\Route",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 128,
"function": "Illuminate\Routing\{closure}",
"class": "Illuminate\Routing\Router",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/app/Http/Middleware/NullToBlank.php",
"line": 18,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "App\Http\Middleware\NullToBlank",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php",
"line": 41,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\Routing\Middleware\SubstituteBindings",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php",
"line": 44,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\Auth\Middleware\Authenticate",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php",
"line": 33,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 128,
"function": "Laravel\Sanctum\Http\Middleware\{closure}",
"class": "Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 103,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/sanctum/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php",
"line": 34,
"function": "then",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/app/Http/Middleware/setHeader.php",
"line": 19,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "App\Http\Middleware\setHeader",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 103,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 693,
"function": "then",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 668,
"function": "runRouteWithinStack",
"class": "Illuminate\Routing\Router",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 634,
"function": "runRoute",
"class": "Illuminate\Routing\Router",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Routing/Router.php",
"line": 623,
"function": "dispatchToRoute",
"class": "Illuminate\Routing\Router",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 166,
"function": "dispatch",
"class": "Illuminate\Routing\Router",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 128,
"function": "Illuminate\Foundation\Http\{closure}",
"class": "Illuminate\Foundation\Http\Kernel",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\Foundation\Http\Middleware\TransformsRequest",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php",
"line": 21,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\Foundation\Http\Middleware\TransformsRequest",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php",
"line": 27,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\Foundation\Http\Middleware\ValidatePostSize",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php",
"line": 87,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/fruitcake/laravel-cors/src/HandleCors.php",
"line": 37,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Fruitcake\Cors\HandleCors",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/fideloper/proxy/src/TrustProxies.php",
"line": 57,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 167,
"function": "handle",
"class": "Fideloper\Proxy\TrustProxies",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php",
"line": 103,
"function": "Illuminate\Pipeline\{closure}",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 141,
"function": "then",
"class": "Illuminate\Pipeline\Pipeline",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php",
"line": 110,
"function": "sendRequestThroughRouter",
"class": "Illuminate\Foundation\Http\Kernel",
"type": "->"
},
{
"file": "/var/www/html/dcc-cms/public/index.php",
"line": 52,
"function": "handle",
"class": "Illuminate\Foundation\Http\Kernel",
"type": "->"
}
]
}

May be somewhere we need to add type to column so it will consider 0 as int not Boolean or string

Laravel 9 Support

Thank you for your amazing package, :)

can you please release it for laravel 9 sir?

Possible to make queries for relationships?

Hello, great library. I wondered if it's possible to support relationship models?
Lets say I have Orders model, and there Order Shipment model.
Relationship looks like $this->hasOne('OrderShipment', [primary_key]).

Now, when we query the information, I need to able search in these related models. for example, I'd like to have something like &order_shipment.status=New

Final SQL should be something like SELECT .. WHERE ... AND order_shipment.status = 'New'.

Nested relation Model and LIKE

The filter function of relation Model works well.
But it does not work if you want to use the LIKE operator instead of "=".

So i'd like to query "WHERE column LIKE '%value%'" instead of "WHERE column = '%value%'".

Example:
https://....index?location[locationName][name][like]=%Sacram%

That does not work and i get the error that the column 'like' does not exist, which makes sense.

Without [like] in the url it makes the right query, but then it will only filter for exactly %Sacram%.

Where Between clause doesn't work with relations

Describe the bug
I need to do a where between on a relation but it seems to break down when using the start and end parameters.

To Reproduce
Query: Users::select('users.name')->join('posts', 'posts.user_id', '=', 'users.id')->filter(['posts' => [ 'created_at' => [ 'start' => '2021/01/21', 'end' => '2021/01/23' ] ]])->get();

Error:
You must set posts.updated_at.start in whiteListFilter in Users.php

Expected behavior
It should create a whereBetween using the posts updated_at

Use custom exceptions for better error handling

Is your feature request related to a problem? Please describe.
The package often throws exception which is very good for error handling and debugging. But catching or handling those exceptions are kind of problematic. Since the package only throws \Exception, it's hard to catch them by their specific name as all exceptions extend this base Exception class.
So it would be good if those exceptions were custom made.

Describe the solution you'd like
Create and throw custom exception classes that extend the base \Exception class. For example, EloquentFilterException etc. So, one can simply do this:

try {
//...
} catch (\eloquentFilter\Exceptions\EloquentFilterException $e) {
} catch(\AnyOtherException $e) {
}

Thanks.

Describe alternatives you've considered

Additional context

Add Laravel 10 Support

Is your feature request related to a problem? Please describe.
This package can't be installed to Laravel 10, currently due to conflicting dependency versions.

Describe the solution you'd like
To update the dependency versions to make it installable on Laravel 10.

Describe alternatives you've considered

Additional context
Laravel 10 has released recently.

Custom filter method naming convention

I don't think filter naming conventions should be a 1:1 match. This has too much potential with collision/confusion with attributes or other methods.

I'd suggest they should follow the existing builder "scopeX" naming convention, or "filterX".

For example, a "keywords" filter should be one of these:

function scopeKeywords($builder, $value)
function filterKeywords($builder, $value)

For backward compatibility, the code could still look for an exact match method, but I think the package should transition away from this.

For more flexibility, a value of the "acceptRequest" array could specify which method to use. For example:

$query->acceptRequest([
       'keywords' => 'whereKeywords',
       'title',
       'created_at',
       'updated_at',
])->filter();

This would result in calling $model->whereKeywords() with the 'keywords' request input value, defined as Model::scopeWhereKeywords().

Dynamic filtering and front-end solution

Is your feature request related to a problem? Please describe.
My feature request isn't related to a problem.

Describe the solution you'd like
A front-end solution/guide and a dynamic solution for e-commerce websites like product filtering with filters managed by the admin panel.

Describe alternatives you've considered
AJAX Requests and Blade foreach for the filters stored in the database.

Additional context
I don't really understand the package, I read the full readme and made it to work but only with one hard coded "filter", the brand of the product.

handle Exception

HI Author,

i m using this, it so far is very good and helpful but now i m getting on issue with it.

when i set in model $whiteListFilter = ['id']

it should mean ?id will handle by this library rest user can handle own
but now it is looking for ?anykey it should happen if user $whiteListFilter = ['*'] add like this

blow is the code which you need to look

throw new \Exception("You must set $field in whiteListFilter in $class_name.php

Thanks you

Add date function to the where query for created_at/updated_at and other TIMESTAMP columns

Is your feature request related to a problem? Please describe.
One of the problems I'm facing right now while using this is, whenever I try to use the conditions on TIMESTAMP fields:

For example:
?created_at[operator]==&created_at[value]=2022-07-14

This will generate this query:

select * from `contents` where  `created_at` = '2022-07-14'

And since Laravel stores the created_at field as a TIMESTAMP column, the query won't return any result.

On the other hand, Eloquent's whereDate() scope works, as it generates this query:

select * from `contents` where date(`created_at`) = '2022-07-14'

Describe the solution you'd like

My suggestion is to use the date() function to the where query just like Eloquent's whereDate() does, if the column's name are created_at / updated_at. Or perhaps this can be set in a model property for any other fields like:

public static array $filterUseDate = ['created_at'];

Great package btw. Thanks.

Filter not working when using WHERE LIKE with nested relationships and request_filter_key set in config

Filter not working when using WHERE LIKE with nested relationships and request_filter_key set in config
I have request_filter_key set in config to 'filter'. So my query parameter for a WHERE LIKE becomes filter[relation.column][like]. Eloquent Filter tries to parse this relation.column as a column name instead of querying a nested relation.

To Reproduce
Steps to reproduce the behavior:

  1. Set request_filter_key to a string in Eloquent Filter config.
  2. Send query param in a key[relation.column][like] format.
  3. Exception occurs: Column not found: 1054 Unknown column 'relation.column' in 'where clause'

Expected behavior
Query should filter with WHERE LIKE regardless of nesting.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment:

  • OS: Windows 10
  • Browser Chrome
  • Version 92.0.4515.159

Target class [eloquentFilter] does not exist.

Hello, unfortunately I can't get this extension to work. I tried a few months ago, but failed because of the same problem as now.

Error message:
Target class [eloquentFilter] does not exist.

I made all adjustments according to the instructions. Also in the app.php file I inserted both lines according to the instructions.
Can someone please help me?

Model:

<?php

namespace App;

use eloquentFilter\QueryFilter\ModelFilters\Filterable;
use Illuminate\Database\Eloquent\Model;
#use Illuminate\Database\Eloquent\Builder;

class Files extends Model
{
    use Filterable;

	public $timestamps = false;
	protected $fillable = ["user_id", "relative_path", "filename", "fileextension", "insert_time", "file_last_changed", "last_scan_touch", "last_analysed_metadata", "last_convert_run", "last_recognition_run", "probably_deleted"];


    /**
     * @var array
     */
    private static $whiteListFilter = ['*'];

Controller:

<?php

namespace App\Http\Controllers;

use App\Files;
use App\FileMetatags;
use App\FilesLocation;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;

class FileController extends Controller
{

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */

    public function indexJSON() {

        $filesFiltered = Files::filter();

        dd($filesFiltered);

Create Blade helper

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Where the nested relation Model dose not work properly with inertiajs.

laravel 8.33
eloquent-filter 2.4.6

I am using eloquent-filter with inertiajs. Now using array query string like this item[price] is not possible in .vue file. I have to convert it to a string like 'item[price]'.

So my final method in vue file look like this
methodName(){ this.$inertia.get({ data: { item[price]: this.item.price, }, }) }

But problem is when I select different price it send &item[price]=100&item[price]=200
and this is default behavior of inertiajs, Which I don't want. Is it possible to use different identifier for nested relation Model?

ignoreRequest sets "deleted_at is null"

Describe the bug
I try to filter on a model including trashed entries. This works as designed, however, adding ignoreRequest() adds where deleted_at is null to the query, which is definitely not intended. I don't see any reason why especially ignoreRequest should add that.

To Reproduce
Steps to reproduce the behavior:

  1. Add a filter to a query including trashed entries (::withTrashed()). The result includes trashed entries (if exist).
  2. Add ignoreRequest() to the builder. The result does not include trashed entries anymore.

Here is some boilerblade code:

dump($request->input());
dump(Vehicle::withTrashed()->filter()->toSql());
dump(Vehicle::withTrashed()->ignoreRequest(["id"])->toSql()); //ignoring id for demonstration
dd(Vehicle::withTrashed()->ignoreRequest(["id"])->filter()->toSql());

The result:

array:1 [
  "id" => "1"
]
"select * from `vehicles` where `id` = ?"
"select * from `vehicles` where `vehicles`.`deleted_at` is null"
"select * from `vehicles` where `vehicles`.`deleted_at` is null"

Expected behavior
I expect that calling ignoreRequest() does not modify the query in that way (i.e. only fields listed as argument should be ignored).

Workaround
Just remove the desired field (which should be ignored) from the request and add it again afterwards.

$id = $request->input("id");
$request->request->remove("id");
$vehicles = Vehicle::withTrashed()->filter()->get(); //Cannot call ignoreRequest(['rent']) as else filtered by deleted_at

//Add it back to make default laravel functions work properly
$request->request->add([
    'id' => $id
]);
dd($vehicles);

Versions:

  • Laravel: v8.27.0
  • Your Eloquent Filter: v2.4.4
  • PHP: v7.4.11

Additional context
I tried this in a fresh laravel project as well, just to confirm my observation.

How to use directly my custom filter?

Hi!

How can I use my custom filter in filter() method?

trait ModelFilter
{
    public function filterCustomOwn(Builder $builder, $value) {
    .....
    return $builder;
    }
}

This not work:
Model::filter(["own" => 1])->paginate();

But works from url, if I not pass data to filter() method.

Thank you!

Or Where

Hi Everybody,

How can we use orWhere ? i'm trying to get an entity by name or by firstname 2 and i cant make request like:

SELECT * FROM product WHERE name=1 OR firstname=2

Describe the solution you'd like
For now I add in QueryFilterBuilder.php whereOr method:

/**
     * @param       $field
     * @param array $params
     */
    public function whereOr($field, array $params)
    {
        $this->builder->orWhere("$field", $params['or']);
    }

And a case in QueryBuilder.php in the method: "detectMethodByParams":

private function detectMethodByParams($field, $params)
    {
        if (!empty($params['start']) && !empty($params['end'])) {
            $method = 'whereBetween';
        } elseif (!empty($params['operator']) && !empty($params['value'])) {
            $method = 'whereByOpt';
        } elseif (!empty($params['like'])) {
            $method = 'like';
        } elseif (!empty($params['or'])) { // HERE
            $method = 'whereOr';
        } elseif (is_array($params) && !$this->isAssoc($params)) {
            $method = 'whereIn';
        } elseif (stripos($field, '.')) {
            $method = 'wherehas';
        } elseif (is_string($params)) {
            $method = 'where';
        }

        return $method ?? null;
    }

Maybe we can already make a query for that, i'm waiting for your answer!

Thanks a lot for this package!

ignoreRequest

First, sorry by me english!!

Describe the bug
You must set perpage in whiteListFilter in model.php or create a override method with name perpage or call ignoreRequest function for ignore perpage

To Reproduce
My code:

public function index()
{
Model::ignoreRequest(['links','meta','page','perpage'])->orderBy('id', 'Desc')->MyScope()->filter()->paginate()->appends(request()->query());
}

Column not found: 1054 Unknown column '0' in 'where clause

when we pass extra param which are not present in AcceptRequest()
this is my code

ControlPanel::AcceptRequest([
            'id',
            'name',
            'description',
            'theme',
            'created_at',
            'updated_at',
        ])->filter();

now here if i pass some extra field which is not present in this list like ?foo=baar it throw below error

Error

SQLSTATE[42S22]: Column not found: 1054 Unknown column '0' in 'where clause' (SQL: select count() as aggregate from control_panels where 0 = id and 1 = name and 2 = description and 3 = theme and 4 = created_at and 5 = updated_at) {"exception":"[object] (Illuminate\Database\QueryException(code: 42S22): SQLSTATE[42S22]: Column not found: 1054 Unknown column '0' in 'where clause' (SQL: select count() as aggregate from control_panels where 0 = id and 1 = name and 2 = description and 3 = theme and 4 = created_at and 5 = updated_at) at /var/www/html/dcc-repository/vendor/laravel/framework/src/Illuminate/Database/Connection.php:678)

i m using

"mehdi-fathi/eloquent-filter": "^2.4.5",

with laravel 8

NOTE - it is working fine in 2.4.0 version

Supporting hasManyThrough filtering?

Hello Mehdi,

I've been developing more and more using your library. Recently, I've stumbled upon the following issue:

Call to undefined method Illuminate\Database\Eloquent\Relations\HasManyThrough::filter()

I'm using hasManyThrough relationship on this specific resource, and looks like the libaray has difficulties to handle the request. Do you know why it happens? any workarounds with it?

Thank you!

Wrong instructions for publishing the configuration file on README.md

Describe the bug
Wrong instructions for publishing the configuration file.

To Reproduce
Steps to reproduce the behavior:

  1. On console: php artisan vendor:publish --provider="eloquentFilter\EloquentFilterServiceProvider"
    Results : INFO No publishable resources for tag [].

Expected behavior
Publish the configuration file.

Screenshots
image

Desktop:

  • OS: Ubuntu 22.04.1 LTS on Windows 10 WSL
  • Laravel framework v9.41.0 with PHP 8.1.2-1ubuntu2.8 (cli) - Zend Engine v4.1.2
  • Browser: Chrome v107.0.5304.107 64 bits

Additional context
On README.md:
image

Support for DB Query Builder

Is your feature request related to a problem? Please describe.
Not related to a problem

Describe the solution you'd like
I would like to be able to use filters with the Query builder, not just Eloquent

Describe alternatives you've considered
I have not found any alternatives

eloquent-filter doesn't work Laravel 7.4

I have a new project that is based on Laravel 7.4 and when I run the command to add eloquent-filter dependency, it crashes:
To Reproduce
Running the comand inside a Laravel 7.4 project:
composer require mehdi-fathi/eloquent-filter

Errors:
02:04 $ composer require mehdi-fathi/eloquent-filter
Using version ^1.6 for mehdi-fathi/eloquent-filter
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

Problem 1
- Conclusion: remove laravel/framework v7.4.0
- Conclusion: don't install laravel/framework v7.4.0
- mehdi-fathi/eloquent-filter 1.6.0 requires illuminate/pagination 5.5.|5.6.|5.7.|5.8.|^6.0|^6.1 -> satisfiable by illuminate/pagination[5.5.x-dev, 5.6.x-dev, 5.7.17, 5.7.18, 5.7.19, 5.7.x-dev, 5.8.x-dev, 6.x-dev, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34, v5.5.35, v5.5.36, v5.5.37, v5.5.39, v5.5.40, v5.5.41, v5.5.43, v5.5.44.........

  • don't install illuminate/pagination v6.7.0|don't install laravel/framework v7.4.0
    • don't install illuminate/pagination v6.8.0|don't install laravel/framework v7.4.0
    • Installation request for laravel/framework (locked at v7.4.0, required as ^7.0) -> satisfiable by laravel/framework[v7.4.0].
    • Installation request for mehdi-fathi/eloquent-filter ^1.6 -> satisfiable by mehdi-fathi/eloquent-filter[1.6.0, 1.6.0.x-dev].

If you think I'm doing something wrong, please tell me. Let's talk about it

Column in where clause is ambiguous

When an Eloquent query contains a join the where clause generated by the filters becomes ambiguous

To Reproduce
Steps to reproduce the behavior:

This type of query will break due to an ambiguous column in the sql
Users::select('users.name')->join('posts', 'posts.user_id', '=', 'users.id')->filter(['name' => 'test'])->get()

Sql Generated: SELECT users.name FROM users JOIN posts ON posts.user_id = users.id WHERE name=test;

To Fix
Add the table name to the where clauses, maybe there could be a config for this?

Can't publish config

Describe the bug
According to the README.md the config can be published using:

php artisan vendor:publish --provider="eloquentFilter\QueryFilter\ServiceProvider"

However, this yields the error: No publishable resources for tag [].
The reason is that the provider mentioned in the command does not match the definition.
Laravel uses the function below to get the paths for publishing. Adding two dumps (one for $provider and one for static::$publishes) shows the missmatch.
https://github.com/laravel/framework/blob/97b41840b9bbf93e0fe9c764201e77eb92a09dac/src/Illuminate/Support/ServiceProvider.php#L344

To fix is, simply update the command:

php artisan vendor:publish --provider="eloquentFilter\ServiceProvider"

To Reproduce
Steps to reproduce the behavior:

  1. Install a fresh laravel instance
  2. Install this package (including app.php, ... according to instructions)
  3. Publish the config using the command mentioned above.

Expected behavior
The config should be published (without the error message)

Screenshots

The missmatch mentioned above (using two dumps):
WindowsTerminal_sl32FUL8U6

Deprecated on PHP 8.2

Describe the bug
It seems there is deprecated notice appearing with the new warnings implemented in php 8.1/8.2

https://www.php.net/manual/fr/migration81.deprecated.php
https://www.php.net/manual/en/migration82.deprecated.php

To Reproduce
Use the query() method on any filterable model

Expected behavior
No warning

Additional context

DEPRECATED Calling static trait method eloquentFilter\QueryFilter\Core\HelperFilter::isAssoc is deprecated, it should only be called on a class using the trait in vendor/mehdi-fathi/eloquent-filter/src/QueryFilter/Detection/ConditionsDetect/Eloquent/WhereInCondition.php on line 22.

Missing f_params[offset]

Hello,
As we have a params for the limit, it misses a parameter for the offset ("skip" eloquent feature).
This feature will be great.
Thanks and regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.