• Stars
    star
    164
  • Rank 230,032 (Top 5 %)
  • Language
    PHP
  • License
    MIT License
  • Created over 9 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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

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

<?php

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.

More Repositories

1

pdf-bot

🤖 A Node queue API for generating PDFs using headless Chrome. Comes with a CLI, S3 storage and webhooks for notifying subscribers about generated PDFs
JavaScript
2,595
star
2

react-native-clean-form

Easy react-native forms using bootstrap-like syntax with redux-form+immutablejs integration. Styled using styled-components
JavaScript
479
star
3

larapi

An API-friendly fork of Laravel. Authentication, error handling, resource filtering, sorting, pagination and much more included
PHP
404
star
4

heimdal

An Laravel Exception handler build specifically for APIs.
PHP
124
star
5

onion

A before/after middleware implementation
PHP
72
star
6

lumen-api-oauth

The code for a blog post I wrote about creating web apps using a Lumen API that is authenticated by OAuth2
PHP
61
star
7

oauth2-server-lumen

A lumen bridge for lucadegasperi/oauth2-server-laravel
PHP
56
star
8

jquery-oauth

A $.ajax wrapper for OAuth 2 access and refresh token management for use in a SPA
JavaScript
52
star
9

laravel-api-consumer

PHP
39
star
10

architect

Dynamically create API resource structures for related resources
PHP
39
star
11

redux-refresh-token

An extension to your Redux API middleware that will refresh access tokens when hitting a 401 response. Works with middlewares that use FSA-style actions.
JavaScript
37
star
12

distributed-laravel

PHP
30
star
13

genie

A base repository class for Eloquent to abstract away persistence layer from your business code
PHP
27
star
14

react-native-redux-form-example

Code for http://esbenp.github.io/2017/01/06/react-native-redux-form-immutable-styled-components/
JavaScript
22
star
15

wp-darkshell

A Next-Gen Wordpress Hacker Backend
PHP
15
star
16

fineuploader-server

PHP
7
star
17

pdf-bot-laravel

🤖 Laravel integration for pdf-bot. A Node microservice for generating PDFs using headless Chrome
PHP
5
star
18

larapi-series-part-2

PHP
4
star
19

cloudinary-url-resolver

Convert Cloudinary transformations and public ids to Cloudinary resource urls
JavaScript
4
star
20

laravel-batch-request

Batch consume own api
PHP
3
star
21

esbenp.github.io

Blog site
JavaScript
3
star
22

larapi-part-3

PHP
3
star
23

redux-refresh-token-example

Example app for redux-refresh-token
JavaScript
3
star
24

fineuploader-server-thumbnail-creator

PHP
3
star
25

fineuploader-server-cloudinary

PHP
2
star
26

knockout-null-observable

JavaScript
1
star
27

sentinel-lumen

PHP
1
star
28

react-native-swift-test

Objective-C
1
star
29

fineuploader-client-knockout

JavaScript
1
star
30

knockout-bootstrap-modal

JavaScript
1
star
31

laravel-package-boilerplate

PHP
1
star
32

knockout-subscriptions-manager

JavaScript
1
star
33

knockout-bulk-table

JavaScript
1
star
34

fineuploader-client

JavaScript
1
star
35

react-init

Boilerplate: Flow, Immutable, Redux, Redux Immutable, React Router, Styled Components, Webpack 3. Based on an ejected create-react-app.
JavaScript
1
star