A base API controller for Laravel that gives sorting, filtering, eager loading and pagination for your resources

Related tags

Laravel bruno
Overview

Bruno

Latest Version Software License Build Status Coverage Status Total Downloads

Introduction

A Laravel base controller class and a trait that will enable to add filtering, sorting, eager loading and pagination to your resource URLs.

Dedicated to Giordano Bruno

This package is named after my hero Giordano Bruno. A true visionary who dared to dream beyond what was thought possible. For his ideas and his refusal to renounce them he was burned to the stake in 1600. I highly recommend this short cartoon on his life narrated by Neil deGrasse Tyson.

Functionality

Tutorial

To get started with Bruno I highly recommend my article on resource controls in Laravel APIs

Installation

For Laravel 5.3 and below

composer require optimus/bruno ~2.0

For Laravel 5.4 and above

composer require optimus/bruno ~3.0

Usage

The examples will be of a hypothetical resource endpoint /books which will return a collection of Book, each belonging to a Author.

Book n ----- 1 Author

Available query parameters

Key Type Description
Includes array Array of related resources to load, e.g. ['author', 'publisher', 'publisher.books']
Sort array Property to sort by, e.g. 'title'
Limit integer Limit of resources to return
Page integer For use with limit
Filter_groups array Array of filter groups. See below for syntax.

Implementation



namespace App\Http\Controllers;

use Optimus\Api\Controller\EloquentBuilderTrait;
use Optimus\Api\Controller\LaravelController;
use App\Models\Book;

class BookController extends LaravelController
{
    use EloquentBuilderTrait;

    public function getBooks()
    {
        // Parse the resource options given by GET parameters
        $resourceOptions = $this->parseResourceOptions();

        // Start a new query for books using Eloquent query builder
        // (This would normally live somewhere else, e.g. in a Repository)
        $query = Book::query();
        $this->applyResourceOptions($query, $resourceOptions);
        $books = $query->get();

        // Parse the data using Optimus\Architect
        $parsedData = $this->parseData($books, $resourceOptions, 'books');

        // Create JSON response of parsed data
        return $this->response($parsedData);
    }
}

Syntax documentation

Eager loading

Simple eager load

/books?includes[]=author

Will return a collection of 5 Books eager loaded with Author.

IDs mode

/books?includes[]=author:ids

Will return a collection of Books eager loaded with the ID of their Author

Sideload mode

/books?includes[]=author:sideload

Will return a collection of Books and a eager loaded collection of their Authors in the root scope.

See mere about eager loading types in Optimus\Architect's README

Pagination

Two parameters are available: limit and page. limit will determine the number of records per page and page will determine the current page.

/books?limit=10&page=3

Will return books number 30-40.

Sorting

Should be defined as an array of sorting rules. They will be applied in the order of which they are defined.

Sorting rules

Property Value type Description
key string The property of the model to sort by
direction ASC or DESC Which direction to sort the property by

Example

[
    {
        "key": "title",
        "direction": "ASC"
    }, {
        "key": "year",
        "direction": "DESC"
    }
]

Will result in the books being sorted by title in ascending order and then year in descending order.

Filtering

Should be defined as an array of filter groups.

Filter groups

Property Value type Description
or boolean Should the filters in this group be grouped by logical OR or AND operator
filters array Array of filters (see syntax below)

Filters

Property Value type Description
key string The property of the model to filter by (can also be custom filter)
value mixed The value to search for
operator string The filter operator to use (see different types below)
not boolean Negate the filter

Operators

Type Description Example
ct String contains ior matches Giordano Bruno and Giovanni
sw Starts with Gior matches Giordano Bruno but not Giovanni
ew Ends with uno matches Giordano Bruno but not Giovanni
eq Equals Giordano Bruno matches Giordano Bruno but not Bruno
gt Greater than 1548 matches 1600 but not 1400
gte Greater than or equalTo 1548 matches 1548 and above (ony for Laravel 5.4 and above)
lte Lesser than or equalTo 1600 matches 1600 and below (ony for Laravel 5.4 and above)
lt Lesser than 1600 matches 1548 but not 1700
in In array ['Giordano', 'Bruno'] matches Giordano and Bruno but not Giovanni
bt Between [1, 10] matches 5 and 7 but not 11

Special values

Value Description
null (string) The property will be checked for NULL value
(empty string) The property will be checked for NULL value

Custom filters

Remember our relationship Books n ----- 1 Author. Imagine your want to filter books by Author name.

[
    {
        "filters": [
            {
                "key": "author",
                "value": "Optimus",
                "operator": "sw"
            }
        ]
    }
]

Now that is all good, however there is no author property on our model since it is a relationship. This would cause an error since Eloquent would try to use a where clause on the non-existant author property. We can fix this by implementing a custom filter. Where ever you are using the EloquentBuilderTrait implement a function named filterAuthor

public function filterAuthor(Builder $query, $method, $clauseOperator, $value)
{
    // if clauseOperator is idential to false,
    //     we are using a specific SQL method in its place (e.g. `in`, `between`)
    if ($clauseOperator === false) {
        call_user_func([$query, $method], 'authors.name', $value);
    } else {
        call_user_func([$query, $method], 'authors.name', $clauseOperator, $value);
    }
}

Note: It is important to note that a custom filter will look for a relationship with the same name of the property. E.g. if trying to use a custom filter for a property named author then Bruno will try to eagerload the author relationship from the Book model.

Custom filter function

Argument Description
$query The Eloquent query builder
$method The where method to use (where, orWhere, whereIn, orWhereIn etc.)
$clauseOperator Can operator to use for non-in wheres (!=, =, > etc.)
$value The filter value
$in Boolean indicating whether or not this is an in-array filter

Examples

[
    {
        "or": true,
        "filters": [
            {
                "key": "author",
                "value": "Optimus",
                "operator": "sw"
            },
            {
                "key": "author",
                "value": "Prime",
                "operator": "ew"
            }
        ]
    }
]

Books with authors whoose name start with Optimus or ends with Prime.

[
    {
        "filters": [
            {
                "key": "author",
                "value": "Brian",
                "operator": "sw"
            }
        ]
    },
    {
        "filters": [
            {
                "key": "year",
                "value": 1990,
                "operator": "gt"
            },
            {
                "key": "year",
                "value": 2000,
                "operator": "lt"
            }
        ]
    }
]

Books with authors whoose name start with Brian and which were published between years 1990 and 2000.

Optional Shorthand Filtering Syntax (Shorthand)

Filters may be optionally expressed in Shorthand, which takes the a given filter array[key, operator, value, not(optional)] and builds a verbose filter array upon evaluation.

For example, this group of filters (Verbose)

[
    {
        "or": false,
        "filters": [
            {
                "key": "author",
                "value": "Optimus",
                "operator": "sw"
            },
            {
                "key": "author",
                "value": "Prime",
                "operator": "ew"
            }
            {
                "key": "deleted_at",
                "value": null,
                "operator": "eq",
                "not": true
            }
        ]
    }
]

May be expressed in this manner (Shorthand)

[
    {
        "or": false,
        "filters": [
            ["author", "sw", "Optimus"],
            ["author", "ew", "Prime"],
            ["deleted_at", "eq", null, true]
        ]
    }
]

Standards

This package is compliant with PSR-1, PSR-2 and PSR-4. If you notice compliance oversights, please send a patch via pull request.

Testing

$ phpunit

Contributing

Please see CONTRIBUTING for details.

License

The MIT License (MIT). Please see License File for more information.

Comments
  • Shorthand Syntax, plus 'between' and 'distinct' filtering

    Shorthand Syntax, plus 'between' and 'distinct' filtering

    This PR covers a couple issues:

    • Introducing the concept of Shorthand (esbenp/bruno#23)
    • Adds the ability to execute 'distinct' queries (esbenp/bruno#22)
    • Adds the ability to filter using 'between' method (esbenp/bruno#21)

    I welcome any comments + feedback! Thanks!

    opened by pmccarren 10
  • Call to undefined method Illuminate\Database\Query\Builder::getQualifiedForeignKeyName()

    Call to undefined method Illuminate\Database\Query\Builder::getQualifiedForeignKeyName()

    I'm getting an error when trying to use filter on relationships

    Call to undefined method Illuminate\Database\Query\Builder::getQualifiedForeignKeyName()

    The error seems to come from line 255 of EloquentBuilderTrait.

    Anyone else have this issue?

    opened by simonpeters 8
  • Laravel 7 suport?

    Laravel 7 suport?

    Hello, its possible to install this package in laravel version 7? I'm trying to install it with composer and its not working :(. Composer output:

    Problem 1 - Conclusion: remove laravel/framework v7.18.0 - Conclusion: don't install laravel/framework v7.18.0 - optimus/bruno 3.0.0 requires laravel/framework ~5.4 -> satisfiable by laravel/framework[5.4.x-dev, 5.5.x-dev, 5.6.x-dev, 5.7.x-dev, 5.8.x-dev]. - optimus/bruno 3.1.0 requires laravel/framework ~5.4 -> satisfiable by laravel/framework[5.4.x-dev, 5.5.x-dev, 5.6.x-dev, 5.7.x-dev, 5.8.x-dev]. - Can only install one of: laravel/framework[5.5.x-dev, v7.18.0]. - Can only install one of: laravel/framework[5.6.x-dev, v7.18.0]. - Can only install one of: laravel/framework[5.7.x-dev, v7.18.0]. - Can only install one of: laravel/framework[5.8.x-dev, v7.18.0]. - Can only install one of: laravel/framework[5.4.x-dev, v7.18.0]. - Installation request for laravel/framework (locked at v7.18.0, required as ^7.0) -> satisfiable by laravel/framework[v7.18.0]. - Installation request for optimus/bruno ~3.0 -> satisfiable by optimus/bruno[3.0.0, 3.1.0].

    Installation failed, reverting ./composer.json to its original content.

    opened by allanvobraun 3
  • Filter_groups Example

    Filter_groups Example

    Can anyone give an example of filter_groups please? I don't know how to pass filter_group's options in url. I use it like below, but does not work: By clicking on the link, show questions that have answer with specified id.

    <a class="btn btn-default" href="questions?Filter_groups=[{"or":false,"filters":[["answer", "eq",{{ $answer->id }}],]}]">Show Questions That Have This Answer</a><
    

    In fact i want to pass this data :

    [
        {
            "or": false,
            "filters": [
                ["answer", "eq", "id"],
            ]
        }
    ]
    
    opened by akoSalman 2
  • Add support to MySQL for keyword LIKE, add support to laravel 5.4.* for relation keys and other minor fixes

    Add support to MySQL for keyword LIKE, add support to laravel 5.4.* for relation keys and other minor fixes

    The keyword ILIKE can be used instead of LIKE to make the match case insensitive according to the active locale. This is not in the SQL standard but is a PostgreSQL extension.

    opened by Carghaez 2
  • Packagist is not tracking releases

    Packagist is not tracking releases

    The packagist package optimus/bruno is currently not tracking releases. The most recently published release is v4.0.3.

    Happy to help in any way I can!

    opened by pmccarren 1
  • Query for filtering

    Query for filtering

    Hey, I can't get filtering work, it always says:

    "message": "Filter group does not have the 'filters' key.",

    This is the query i'm using. api/v1/categories?filter_groups[filters][key]=name&filter_groups[filters][value]=tecnology&filter_groups[filters][operator]=eq

    Hope you can help me.

    opened by nickaguilarh 1
  • Feature: Optional shorthand filter syntax

    Feature: Optional shorthand filter syntax

    I'd like to introduce a concept of 'Shorthand Filtering Syntax' (a.k.a. Shorthand).

    What is Shorthand? Shorthand takes the a filter array[key, operator, value, not(optional)] and builds a verbose filter array upon evaluation.

    For example, Shorthand Filtering would allow (Verbose):

    $filter_groups = [
    	[
    		'or' => false,
    		'filters' => [
    			[
    				'key' => 'user_id,
    				'operator' => 'eq',
    				'value' => 1
    			],
    			[
    				'key' => 'type',
    				'operator' => 'eq',
    				'value' => 'moderator',
    				'not' => true
    			],
    			[ 
    				'key' => 'deleted_at',
    				'operator' => 'eq',
    				'value' => null
    			]
    		]
    	]
    ];
    

    ... To be expressed in this manner (Shorthand):

    $filter_groups = [
    	[
    		'or' => false,
    		'filters' => [
    			[ 'user_id, 'eq', 1 ],
    			[ 'type', 'eq', 'moderator', true ],
    			[ 'deleted_at', 'eq', null ]
    		]
    	]
    ];
    

    Shorthand syntax is more concise while allowing greater readability, faster skimming. All of which are good things! :)

    Usage of shorthand syntax is optional. The filter array should be treated as Shorthand IFF it does not contain the key 'key' and the number of array elements is >= 3.

    I welcome and questions or comments!

    opened by pmccarren 1
  • throw InvalidArgumentException is trying to find an exception from the local namespace

    throw InvalidArgumentException is trying to find an exception from the local namespace

    See https://github.com/esbenp/laravel-controller/blob/master/src/EloquentBuilderTrait.php#L23

    [2016-01-27 17:43:02] testing.ERROR: Symfony\Component\Debug\Exception\FatalThrowableError: Fatal error: Call to undefined function Optimus\Api\Controller\InvalidArg
    umentException() in /vagrant/Code/api/vendor/optimus/laravel-controller/src/EloquentBuilderTrait.php:23
    Stack trace:
    #0 /vagrant/Code/api/vendor/optimus/eloquent/src/Repository.php(176): Optimus\Database\Eloquent\Repository->applyResourceOptions(Object(Illuminate\Database\Eloquent\
    Builder), Array)
    #1 /vagrant/Code/api/vendor/optimus/eloquent/src/Repository.php(104): Optimus\Database\Eloquent\Repository->createBaseBuilder(Array)
    
    opened by etorofiev 1
  • What to do on shared children and pivot tables?

    What to do on shared children and pivot tables?

    If a shared child already exists in the root object collection it will not be added again. How about shared children with pivot table data? Maybe save the pivot table data somewhere? Or should the pivot table data be whats left in the original collection?

    opened by esbenp 1
  • fix: redundant joins

    fix: redundant joins

    Reuse of custom filter within the same query will result in redundant joins. To resolve this, we cache a list of joins and skip redundant ones.

    Closes #43

    opened by pmccarren 0
  • Required parameter $joins follows optional parameter $or

    Required parameter $joins follows optional parameter $or

    Description: Uncaught ErrorException: Required parameter $joins follows optional parameter $or in /vendor/optimus/bruno/src/EloquentBuilderTrait.php:108

    this line: protected function applyFilter($queryBuilder, array $filter, $or = false, array &$joins)

    when I delete "= false" it works.

    opened by Carla1315 0
  • Fix PHP 8 error

    Fix PHP 8 error

    Trying to run native sail docker I got error

     During class fetch: Uncaught ErrorException: Required parameter $joins follows optional parameter $or in /var/www/html/vendor/optimus/bruno/src/EloquentBuilderTrait.php:106
    

    https://stackoverflow.com/a/65297280/518704

    To this is a fix

    opened by gruz 0
  • Removed default value from $or variable on applyFilter function

    Removed default value from $or variable on applyFilter function

    ~~Leaving the $join variable blank when using PHP 8 causes an exception when running artisan.~~

    ~~An empty array has been assigned to the variable to prevent this from happening.~~

    UPDATE: Related to this deprecated PHP feature: https://stackoverflow.com/a/65297280/518704

    To ensure compatibility with PHP 8, the default value for $or has been removed.

    opened by ch00n 2
  • second and third level filtering

    second and third level filtering

    Hello,

    How can I do the second and third level for filtering with 2D and 3D array. Aworking example will be highly appreciated.

    e.g. consider my array

    "books":[
    {
    "id":1, "author_id":1, "title":"How to save the world from evil", "pages":100, "author":{
    "id":1, "name":"Optimus Prime" "author_details":{
    "id":1, "dept":"Literature" } } },

    I want to search by books.author.name && books.author.author_details.dept What should be changes in the controller? How should be the API call?

    Thanks

    opened by tejastechie 2
  • fix boolean casting for filterGroup $or

    fix boolean casting for filterGroup $or

    This will fix the issue of boolean casting for filterGroup $or. Now it supports string in boolean value. i.e. it parse "true" to true and "false" to false.

    opened by rijan0101 0
Releases(6.0.6)
Owner
Esben Petersen
Founder of traede.com
Esben Petersen
Cursor pagination for your Laravel API

Cursor Pagination for Laravel This package provides a cursor based pagination already integrated with Laravel's query builder and Eloquent ORM. It cal

Juan Pablo Barreto 71 Sep 8, 2022
Column sorting with Laravel 8 & 9 - Eloquent sortable

Column sorting for Laravel - Sortable - Sort by Larasort : Column sorting for Laravel - Sort easily Introduction - Larasort package This package allow

Stephen Damian - Laravel Developer 11 Sep 20, 2022
Laravel Helpers Automatic Loading System

About Laravel Helpers Automatic Load Laravel Helpers Automatic Loading System Doc: Copy the Helpers folder and paste it on app folder Then Go To app/P

IQBAL HASAN 2 Nov 9, 2021
Quickly identify controller methods with no route in your Laravel applications.

Orphan Controller Quickly identify controller methods with no route in your Laravel applications. Installation You can install the package via Compose

Ryan Chandler 16 Feb 18, 2022
Bring Laravel 8's cursor pagination to Laravel 6, 7

Laravel Cursor Paginate for laravel 6,7 Installation You can install the package via composer: composer require vanthao03596/laravel-cursor-paginate U

Pham Thao 9 Nov 10, 2022
A lightweight PHP paginator, for generating pagination controls in the style of Stack Overflow and Flickr.

PHP Paginator A lightweight PHP paginator, for generating pagination controls in the style of Stack Overflow and Flickr. The "first" and "last" page l

Jason Grimes 370 Dec 21, 2022
In-place pagination without page refresh by using Backbone.js with Laravel PHP framework

Laravel Backbone - based in-place pagination demo Store application See demo at: http://demos.maxoffsky.com/ajax-pagination/ Tutorial at: http://maxof

Maksim Surguy 41 Oct 11, 2022
Laravel 7 Ajax Pagination Example

Now, let's see post of Laravel ajax pagination with jQuery. We will look at example of Laravel pagination json. In this article, we will implement a jQuery ajax pagination in Laravel . You can understand a concept of Laravel ajax bootstrap pagination. Here, Creating a basic example of pagination jQuery ajax Laravel

Wesley Sinde 3 Feb 23, 2022
Eloquent Befriended brings social media-like features like following, blocking and filtering content based on following or blocked models.

Laravel Befriended Eloquent Befriended brings social media-like features like following, blocking and filtering content based on following or blocked

Renoki Co. 720 Jan 3, 2023
A simple and modern approach to stream filtering in PHP

clue/stream-filter A simple and modern approach to stream filtering in PHP Table of contents Why? Support us Usage append() prepend() fun() remove() I

Christian Lück 1.5k Dec 29, 2022
Advanced Laravel models filtering capabilities

Advanced Laravel models filtering capabilities Installation You can install the package via composer: composer require pricecurrent/laravel-eloquent-f

Andrew Malinnikov 162 Oct 30, 2022
In Laravel, we commonly face the problem of adding repetitive filtering code, this package will address this problem.

Filterable In Laravel, we commonly face the problem of adding repetitive filtering code, sorting and search as well this package will address this pro

Zoran Shefot Bogoevski 1 Jun 21, 2022
Library that offers Input Filtering based on Annotations for use with Objects. Check out 2.dev for 2.0 pre-release.

DMS Filter Component This library provides a service that can be used to filter object values based on annotations Install Use composer to add DMS\Fil

Rafael Dohms 89 Nov 28, 2022
This project uses dflydev/dot-access-data to provide simple output filtering for cli applications.

FilterViaDotAccessData This project uses dflydev/dot-access-data to provide simple output filtering for applications built with annotated-command / Ro

Consolidation 44 Jul 19, 2022
Fast and simple implementation of a REST API based on the Laravel Framework, Repository Pattern, Eloquent Resources, Translatability, and Swagger.

Laravel Headless What about? This allows a fast and simple implementation of a REST API based on the Laravel Framework, Repository Pattern, Eloquent R

Julien SCHMITT 6 Dec 30, 2022
Open source Unifi controller

imperian-systems/unifi-controller Note: This package is backend only, no user interface is included Install snappy PHP extension https://github.com/kj

Imperian Systems 111 Dec 18, 2022
Sample Content - PHP Retriever - Simple MVC Front Controller Mini Framework

### PHP-RETRIEVER AND SAMPLE CONTENT | SIMPLE MVC FRONT CONTROLLER MINI FRAMEWORK Version: 0.2 License: GPLv3 or later Requires at least: PHP 7.3+ Co

null 1 Nov 30, 2021
Package for Laravel that gives artisan commands to setup and edit environment files.

Setup and work with .env files in Laravel from the command line NOTE: This doesn't work with Laravel 5 since .env files were changed. This is for Lara

Matt Brunt 6 Dec 17, 2022
Let's base your Laravel project with PROS style

Purpose This library is for convenient methods that use to register code base for Laravel project Target We aimed to reduce complexity for real projec

Protean Studios Co., Ltd. 4 Mar 29, 2022