Git Product home page Git Product logo

data-provider's Introduction

Laravel Data Provider


This extension allows building of the complex search queries based on the request in Laravel. In particular, it is useful for REST API composition.

For license information check the LICENSE-file.

Latest Stable Version Total Downloads Build Status

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist illuminatech/data-provider

or add

"illuminatech/data-provider": "*"

to the "require" section of your composer.json.

Usage

This extension allows building of the complex search queries based on the request data. It handles filtering, sorting, pagination, include of extra fields or relations on demand. Both Eloquent Active Record and plain database queries are supported.

This extension provides Illuminatech\DataProvider\DataProvider class, which wraps given data source object like database query builder, and provide the means to define controller-level interaction to search through this data source.

Usage example:

<?php

use App\Models\Item;
use Illuminate\Http\Request;
use Illuminatech\DataProvider\DataProvider;

class ItemController extends Controller
{
    public function index(Request $request)
    {
        $items = DataProvider::new(Item::class)
            ->filters([
                'id',
                'status' => 'status_id',
                'search' => ['name', 'description'],
            ])
            ->sort(['id', 'name', 'status', 'created_at'])
            ->sortDefault('-id')
            ->paginate($request);
            
        // ...
    }
}

This example will respond to the following request:

GET http://example.com/items?filter[status]=active&filter[search]=foo&sort=-id&page=2&per-page=20

Same example with the plain database query usage:

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminatech\DataProvider\DataProvider;

class ItemController extends Controller
{
    public function index(Request $request)
    {
        $items = DataProvider::new(DB::table('items'))
            ->filters([
                'id',
                'status',
                'search' => ['name', 'description'],
            ])
            ->sort(['id', 'name', 'status', 'created_at'])
            ->sortDefault('-id')
            ->paginate($request);
            
        // ...
    }
}

Data provider defines only a few methods for the data querying:

  • get() - returns all records matching request
  • paginate() - returns all records matching request with a paginator
  • simplePaginate() - returns all records matching request with a simple paginator
  • cursorPaginate() - returns all records matching request with a cursor paginator

However, you can use prepare() method to get data source object, adjusted to given request, to invoke the method you need. For example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;

$items = DataProvider::new(Item::class)
    ->filters(/* ... */)
    ->prepare($request) // applies all requested filters, returns `\Illuminate\Database\Eloquent\Builder` instance
    ->chunk(100, function ($items) {
        // ...
    });

Method prepare() is immutable, leaving original data source object intact. Thus, you can re-use same data provider to process several different search requests. For example:

<?php

use App\Models\Article;
use Illuminatech\DataProvider\DataProvider;

$query = Article::query() 
    ->with('category');

$dataProvider = DataProvider::new($query)
    ->filters([
        'status'
    ]);

$publishedArticles = $dataProvider->get(['filter' => ['status' => 'published']]); // has no side affect on `$query` instance
$draftArticles = $dataProvider->get(['filter' => ['status' => 'draft']]); // can process multiple requests in isolation

Specifying Data Source

There are several ways to specify a data source for the DataProvider:

  • instance of Illuminate\Database\Eloquent\Builder
  • instance of Illuminate\Database\Query\Builder
  • instance of Eloquent relation like Illuminate\Database\Eloquent\Relations\HasMany
  • name of the Eloquent model class

For example:

<?php

use App\Models\Item;
use Illuminate\Support\Facades\DB;
use Illuminatech\DataProvider\DataProvider;

$items = DataProvider::new(Item::query()) // instance of `\Illuminate\Database\Eloquent\Builder`
    ->filters(/* ... */)
    ->get();
    
$items = DataProvider::new( // all default conditions and eager loading should be applied to data source before passing it to data provider
        Item::query()
            ->with('category')
            ->where('status', 'published')
    )
    ->filters(/* ... */)
    ->get();

$items = DataProvider::new(Item::class) // invokes `Item::query()` automatically
    ->filters(/* ... */)
    ->get();

$items = DataProvider::new(DB::table('items')) // instance of `\Illuminate\Database\Query\Builder`
    ->filters(/* ... */)
    ->get();

$item = Item::query()->first();
$purchases = DataProvider::new($item->purchases()) // instance of `\Illuminate\Database\Eloquent\Relations\HasMany`
    ->filters(/* ... */)
    ->get();

Note: this extension does not put explicit restriction on the data source object type - it simply expected to match database query builder notation. Thus, you may create a custom query builder class, which works with special data storage like MongoDB or Redis, and pass its instance as a data source. If its methods signature matches \Illuminate\Database\Query\Builder - it should work. Although it is not guaranteed.

Configuration

You can publish predefined configuration file using following console command:

php artisan vendor:publish --provider="Illuminatech\DataProvider\DataProviderServiceProvider" --tag=config

This will create an application-wide configuration for all DataProvider instances. You can see its example at config/data_provider.php. You may adjust configuration per each DataProvider instance, using second argument of its constructor. For example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;

$items = DataProvider::new(Item::class, [
    'pagination' => [
        'per_page' => [
            'max' => 80,
            'default' => 20,
        ],
    ],
])
    ->filters([
        // ...
    ])
    ->paginate($request); // creates paginator with page size 20

Additional configuration will be merged recursively with one you specified at your "config/data_provider.php" file, so you should specify only those keys you wish to change.

Filtering

Filters setup example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;
use Illuminatech\DataProvider\Filters\FilterExact;

$items = DataProvider::new(Item::class)
    ->filters([
        'id', // short syntax, equals to `'id' => new FilterExact('id')`,
        'status' => 'status_id', // short syntax, equals to `'status' => new FilterExact('status_id')`,
        'search' => ['name', 'description'], // short syntax, equals to `'search' => new FilterSearch(['name', 'description'])`
        'exact_name' => new FilterExact('name'), // pass filter instance directly
        'callback' => function ($query, $name, $value) { // short syntax, equals to `'callback' => new FilterCallback(function ($query, $name, $value) {})`
            $query->whereNotIn('status', $value);
        },
    ])
    ->paginate($request);

This example will respond to the following request:

GET http://example.com/items?filter[id]=12&filter[status]=2&filter[search]=any&filter[exact_name]=foo&filter[callback][0]=1&filter[callback][1]=2

Tip: you may disable filters grouping in request by setting null as data_provider.filter.keyword configuration value.

While specifying filter attribute, you can use a dot ('.') notation to make filter challenge against relation instead of main source. In this case Illuminate\Database\Eloquent\Concerns::QueriesRelationships::whereHas() will be executed under the hood. However, this behavior will apply only for Eloquent query and relations. For example:

<?php

use App\Models\Item;
use Illuminate\Support\Facades\DB;
use Illuminatech\DataProvider\DataProvider;
use Illuminatech\DataProvider\Filters\FilterExact;

// Eloquent processes dot attributes via relations:
$items = DataProvider::new(Item::class)
    ->filters([
        'category_name' => new FilterExact('category.name'),
    ])
    ->get(['category_name' => 'programming']); // applies $itemQuery->whereHas('category', function() {...});

// Regular DB query consider dot attribute as 'table.column' specification:
$items = DataProvider::new(
        DB::table('items')
            ->join('categories', 'categories.id', '=', 'items.category_id')
    )
    ->filters([
        'category_name' => new FilterExact('category.name'),
    ])
    ->get(['category_name' => 'programming']); // applies $itemQuery->where('category.name', '=', 'programming');

List of supported filters:

Please refer to the particular filter class for more details and examples.

You can create your custom filter implementing Illuminatech\DataProvider\FilterContract interface.

Sorting

Sorting setup example:

<?php

use App\Models\User;
use Illuminatech\DataProvider\DataProvider;

$dataProvider = DataProvider::new(User::class)
    ->sort([
        'id', // short syntax, equals to `['id' => ['asc' => ['id' => 'asc'], 'desc' => ['id' => 'desc']]]`
        'name' => [
            'asc' => ['first_name' => 'asc', 'last_name' => 'asc'],
            'desc' => ['first_name' => 'desc', 'last_name' => 'desc'],
        ],
    ])
    ->sortDefault('-id');

$users = $dataProvider->get(['sort' => 'id']); // applies 'ORDER BY id ASC'
$users = $dataProvider->get(['sort' => '-id']); // applies 'ORDER BY id DESC'
$users = $dataProvider->get(['sort' => 'name']); // applies 'ORDER BY first_name ASC, last_name ASC'
$users = $dataProvider->get([]); // applies default sort: 'ORDER BY id DESC'

You may enable multisort support for the data provider setting data_provider.sort.enable_multisort configuration value to true. For example:

<?php

use App\Models\User;
use Illuminatech\DataProvider\DataProvider;

$dataProvider = DataProvider::new(User::class, [
        'sort' => [
            'enable_multisort' => true,
        ],
    ])
    ->sort([
        'id',
        'first_name',
    ]);

$users = $dataProvider->get(['sort' => 'first_name,-id']); // applies 'ORDER BY first_name ASC, id DESC'

Note: sort parameter for multi-sort can be passed both as comma separated string and as an array.

Pagination

Data provider defines following pagination methods, wrapping the ones provided by query builder:

  • paginate() - returns all records matching request with a paginator
  • simplePaginate() - returns all records matching request with a simple paginator
  • cursorPaginate() - returns all records matching request with a cursor paginator

In addition to Laravel standard pagination behavior, these methods also allow control over page size via request parameters. For example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;

$dataProvider = DataProvider::new(Item::class);

var_dump(count($dataProvider->paginate([])->items())); // outputs: 15
var_dump(count($dataProvider->paginate(['per-page' => 5])->items())); // outputs: 5
var_dump(count($dataProvider->paginate(['per-page' => 999999999])->items())); // throws a 'bad request' HTTP exception

You may control page size boundaries per each data provider using constructor configuration parameter. For example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;

$dataProvider = DataProvider::new(Item::class, [
    'pagination' => [
        'per_page' => [
            'min' => 1,
            'max' => 200,
            'default' => 20,
        ],
    ],
]);

If data_provider.pagination.appends enabled, all pagination methods will automatically append passed request data to the created paginator instance, so you do not need to invoke Illuminate\Contracts\Pagination\Paginator::appends() manually.

Include Relations

While creating an API, you may allow its client to "expand" particular entities, including their relations to the HTTP response.

Available for inclusion relations setup example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;
use Illuminatech\DataProvider\Includes\IncludeRelation;

$dataProvider = DataProvider::new(Item::class)
    ->includes([
        'category', // short syntax, equals to `'category' => new IncludeRelation('category')`
        'alias' => 'relation', // short syntax, equals to `'alias' => new IncludeRelation('relation')`,
        'published_comments' => new IncludeRelation('comments', function ($commentsQuery) {
            $commentsQuery->where('status', '=', 'published');
        }),
        'category.group', // nested relation include
    ]);

$item = $dataProvider->prepare(['include' => 'category'])->first();
var_dump($item->relationLoaded('category')); // outputs `true`

Selecting Fields

While creating an API, you may allow its client to specify the list of fields to be returned by particular listing endpoint. This may be useful to reduce HTTP traffic, skipping large text fields in response.

Selectable fields setup example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;
use Illuminatech\DataProvider\Fields\Field;

$dataProvider = DataProvider::new(Item::class)
    ->fields([
        'id', // short syntax, equals to `'id' => new Field('id')`
        'name' => new Field('name'),
        'brief' => 'description', // short syntax, equals to `'brief' => new Field('description')`
        'price',
    ]);

$item = $dataProvider->prepare(['fields' => 'id,name'])->first();
var_dump(isset($item->id)); // outputs `true`
var_dump(isset($item->name)); // outputs `true`
var_dump(isset($item->description)); // outputs `false`

You may specify selectable fields for the related models as well. For example:

<?php

use App\Models\Item;
use Illuminatech\DataProvider\DataProvider;

$dataProvider = DataProvider::new(Item::class)
    ->fields([
        'id',
        'name',
        'category' => [
            'id',
            'name',
        ],
    ]);

$item = $dataProvider->prepare([
    'fields' => [
        'id',
        'category' => [
            'id',
        ],
    ],
])->first();

var_dump(isset($item->id)); // outputs `true`
var_dump(isset($item->name)); // outputs `false`
var_dump(isset($item->category->id)); // outputs `true`
var_dump(isset($item->category->name)); // outputs `false`

Note that passing fields for the particular relation causes its eager loading. This way you actually declare "includes" while writing "fields". This may create an inconsistency in your API, as it allows loading of the particular relation via "fields", but does not allow its loading via "includes". It is your responsibility to setup includes() and fields() in consistent way.

JSON API Specification Support

This extension is compatible with JSON API Specification. However, the default configuration for the pagination mismatches it, since it provides compatibility with native Laravel pagination. But you can easily fix this with a proper configuration. For example:

<?php
// file 'config/data_provider.php'

return [
    // ...
    'pagination' => [
        'keyword' => 'page',
        'page' => [
            'keyword' => 'number',
        ],
        'per_page' => [
            'keyword' => 'size',
            // ...
        ],
        // ...
    ],
];

Dedicated Data Providers

You may create a custom data provider class dedicated to the specific use case. Such approach allows to organize the code and keep your controllers clean.

This goal can be easily achieved using Illuminatech\DataProvider\DedicatedDataProvider as a base class. It predefines a set of methods named define*, like defineConfig(), defineFilters() and so on, which you can override, creating a structured custom class. Also note, that unlike other methods, __construct() is exempt from the usual signature compatibility rules when being extended. Thus, you can specify its signature in your class as you like, defining your own dependencies. For example:

<?php

use App\Models\User;
use Illuminatech\DataProvider\DedicatedDataProvider;
use Illuminatech\DataProvider\Filters\FilterIn;

class UserPurchasesList extends DedicatedDataProvider
{
    public function __construct(User $user)
    {
        parent::__construct($user->purchases()->with('item'));
    }

    protected function defineConfig(): array
    {
        return [
            'pagination' => [
                'per_page' => [
                    'default' => 16,
                ],
            ],
        ];
    }

    protected function defineFilters(): array
    {
         return [
             'id',
             'status' => new FilterIn('status'),
             // ...
         ];
    }

    protected function defineSort(): array
    {
        return [
            'id',
            'created_at',
            // ...
        ];
    }
    
    // ...
}

// Controller code :

use Illuminate\Http\Request;

class PurchaseController extends Controller
{
    public function index(Request $request)
    {
        $items = UserPurchasesList::new($request->user())
            ->paginate($request);
            
        // ...
    }
}

data-provider's People

Contributors

klimov-paul 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

Watchers

 avatar  avatar

data-provider's Issues

Error when config file is not published

What steps will reproduce the problem?

  1. Install via composer
  2. Build a data provider from examples
  3. Receive errors

What is the expected result?

A json response with query results

What do you get instead?

#message: "array_replace_recursive(): Argument #2 must be of type array, null given"
#code: 0
#file: "/app/vendor/illuminatech/data-provider/src/DataProvider.php"
#line: 123

Additional info

Q A
This Package Version 1.0.4
Laravel Framework Version Latest
PHP version 8.2
Operating system Docker

Define dynamic value for the include relationship

What steps will reproduce the problem?

I try to create a dynamic include relationship, but unable to make a dynamic input value for it

What is the expected result?

We can define an include that has dynamic value as the parameter.

What do you get instead?

Currently nothing.

Additional info

Is this possible? In the example, we have a custom include with new IncludeRelation callback, but the value is hard-coded, is it possible to make it dynamic?

Thank you !

Q A
This Package Version 1.0.5
Laravel Framework Version 10.23.1
PHP version 8.2
Operating system Windows 11

Include N+1 Query Problem

What steps will reproduce the problem?

Use include when fetch data from model:

$options = [
    'filter' => [
        'owner' => Auth::id()
    ],
    'include' => 'breed'
];

$pets = $this->getPets->handle($options);

public function handle(array $attributes = []): array|Collection
{
    // Add the $attributes to the $this attributes
    $this->fill($attributes);

    // validate attributes
    $validatedData = $this->validateAttributes();

    return PetDataProvider::new(Pet::query())->get($validatedData);
}

What is the expected result?

image

Only two database queries.

What do you get instead?

image

It will produce the query depends on the number of the records.

Additional info

Q A
This Package Version 1.0.5
Laravel Framework Version 10.23.1
PHP version 8.2
Operating system Windows 11

Please, document fields query parameter syntax

Thank you very much for sharing this package.

My controller has this code

    $query = Customer::query() 
    ->with('country')
    $customers = DataProvider::new($query)
        ->filters([
            'id',
            'organization_id',
            'country_id',
            'legal_id_type_id',
            'vat_condition_id',
            'legal_id_number',
            'customer_type_id',
            'search' => ['name', 'contact_last_name', 'contact_first_name', 'contact_email' ],
            'name' => new FilterSearch(['name']),
            'contact_last_name' => new FilterSearch(['contact_last_name']),
            'contact_first_name' => new FilterSearch(['contact_first_name']),
            'contact_email' => new FilterSearch(['contact_email']),

        ])
        ->fields(['id', 'created_at', 'updated_at', 'organization_id', 'name', 'address', 'country_id', 'legal_id_type_id', 'vat_condition_id', 'legal_id_number', 'notify_charge_by_email', 'notify_collection_by_email',  'delayed_payment_notification_policy_id', 'contact_last_name', 'contact_first_name', 'contact_email', 'contact_landphone', 'contact_cellphone', 'customer_type_id', 'country' => ['id', 'name']  ])
        ->sort(['id', 'name'])
        ->sortDefault('id')
        ->includes(['country'])
        ->paginate(request());

Note that I've added an include 'country'. Also, I've added country id and coountry name in fields

This works fine if I request

https://timci.lndo.site/api/customers?fields[]=id,name

but I don't know how to ask for country name in query string.
I've tried with

https://timci.lndo.site/api/customers?fields[]=id,name,country.name

but that throws

Illuminatech\DataProvider\Exceptions\InvalidQueryException: Unsupported field "id,name,country.name" in "fields". in file /app/app/vendor/illuminatech/data-provider/src/Selector.php on line 301

#0 /app/app/vendor/illuminatech/data-provider/src/Selector.php(278): Illuminatech\DataProvider\Selector->applyFieldsRecursive(Object(Illuminate\Database\Eloquent\Builder), Array, Array, Array)
#1 /app/app/vendor/illuminatech/data-provider/src/Selector.php(230): Illuminatech\DataProvider\Selector->applyFields(Object(Illuminate\Database\Eloquent\Builder), Array)
#2 /app/app/vendor/illuminatech/data-provider/src/DataProvider.php(157): Illuminatech\DataProvider\Selector->apply(Object(Illuminate\Database\Eloquent\Builder), Array)
#3 /app/app/vendor/illuminatech/data-provider/src/DataProvider.php(216): Illuminatech\DataProvider\DataProvider->prepare(Array)
#4 /app/app/app/Http/Controllers/Api/CustomerController.php(74): Illuminatech\DataProvider\DataProvider->paginate(Object(Illuminate\Http\Request))
#5 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\Http\Controllers\Api\CustomerController->index()
#6 /app/app/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\Routing\Controller->callAction('index', Array)
#7 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(262): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(App\Http\Controllers\Api\CustomerController), 'index')
#8 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\Routing\Route->runController()
#9 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(721): Illuminate\Routing\Route->run()
#10 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Routing\Router->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#11 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#12 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Routing\Middleware\SubstituteBindings->handle(Object(Illuminate\Http\Request), Object(Closure))
#13 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(127): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#14 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(103): Illuminate\Routing\Middleware\ThrottleRequests->handleRequest(Object(Illuminate\Http\Request), Object(Closure), Array)
#15 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(55): Illuminate\Routing\Middleware\ThrottleRequests->handleRequestUsingNamedLimiter(Object(Illuminate\Http\Request), Object(Closure), 'api', Object(Closure))
#16 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Routing\Middleware\ThrottleRequests->handle(Object(Illuminate\Http\Request), Object(Closure), 'api')
#17 /app/app/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(44): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#18 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Auth\Middleware\Authenticate->handle(Object(Illuminate\Http\Request), Object(Closure), 'api')
#19 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#20 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(723): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#21 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(698): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#22 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(662): Illuminate\Routing\Router->runRoute(Object(Illuminate\Http\Request), Object(Illuminate\Routing\Route))
#23 /app/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(651): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#24 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(167): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#25 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http{closure}(Object(Illuminate\Http\Request))
#26 /app/app/vendor/barryvdh/laravel-debugbar/src/Middleware/InjectDebugbar.php(67): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#27 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Barryvdh\Debugbar\Middleware\InjectDebugbar->handle(Object(Illuminate\Http\Request), Object(Closure))
#28 /app/app/vendor/matthewbdaly/laravel-dynamic-serving/src/Http/Middleware/DetectMobile.php(58): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#29 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Matthewbdaly\LaravelDynamicServing\Http\Middleware\DetectMobile->handle(Object(Illuminate\Http\Request), Object(Closure))
#30 /app/app/vendor/fruitcake/laravel-cors/src/HandleCors.php(52): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#31 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fruitcake\Cors\HandleCors->handle(Object(Illuminate\Http\Request), Object(Closure))
#32 /app/app/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#33 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Http\Middleware\TrustProxies->handle(Object(Illuminate\Http\Request), Object(Closure))
#34 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#35 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#36 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull->handle(Object(Illuminate\Http\Request), Object(Closure))
#37 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#38 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\Foundation\Http\Middleware\TransformsRequest->handle(Object(Illuminate\Http\Request), Object(Closure))
#39 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\TrimStrings->handle(Object(Illuminate\Http\Request), Object(Closure))
#40 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#41 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle(Object(Illuminate\Http\Request), Object(Closure))
#42 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#43 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance->handle(Object(Illuminate\Http\Request), Object(Closure))
#44 /app/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))
#45 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(142): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#46 /app/app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(111): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#47 /app/app/public/index.php(52): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#48 {main}

Thank you in advance for any help you can give to me

Set response type in query param

Hi,

It is possible to set response type (get / paginate) in the query params? I think it'll be useful.

Thanks for the reply, best regards:

Peter

Discussion - Do you need to create multiple DataProvider to differentiate between collection and model?

Since there is no discussion section, I will ask here.

First of all, thank you for the package! It really suites the way I use action class. I hope you have a great day!

Here is my question:

API endpoint: /products
Let's say you have a DataProvider for a Product model, the input will be a Builder you will have functionality for filter and include, and it will print the get() result (collection).

At the sametime, you will have API endpoint: /products/{product}.
There won't be filter or sort, it's only include, because sometimes we will have to dynamically call the relationship data.

Do you think you will need to create a different DataProvider, or just use the same one, and why?

Thank you

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.