'How to format (transform) laravel database paginated results?

For example i have following code:

public function index()
{
    return
        Model::select(['id', 'some_field', ...// more some fields])
            ->with('data') // load relation
            ->paginate(20);
}

How do i format (transform/manipulate on) obtained data from database?

CakePHP ORM have useful method for this -https://book.cakephp.org/3.0/en/orm/query-builder.html#adding-calculated-fields && https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#map-reduce

But i can't find any thing, that can help me to do a same things in Laravel. I can override "toArray" method in a model, but this will affect all application parts (not only an index action in my controller).



Solution 1:[1]

You can do same thing in Laravel, for example:

return Model::select(['id', 'some_field', ...// more some fields])
->with('data')
->paginate(20)
->map(function($item, $key) {
    // Some pseudo code
    $item->uid = uniqid();

    // Must return the $item
    return $item;
});

There are other ways doing similar things. You can do many more in Laravel. There is a transform method as well, among many.

Solution 2:[2]

Here is my solution to only modify items without loosing the pagination data

public function index()
{
    $data_with_pagination = Model::select(['id', 'some_field', ...// more some fields])
        ->with('data') // load relation
        ->paginate(20);

    foreach ($data_with_pagination->items() as $item) {
        // modify your item here
        $item['uid'] = uniqid();
    }

    return $data_with_pagination;
}

Solution 3:[3]

paginate() and get() will return a Collection giving you access to all the Collection methods.

You would be able to do:

public function index()
{
    return
        Model::select(['id', 'some_field', ...// more some fields])
            ->with('data') // load relation
            ->paginate(20)
            ->map(function($model) {
                $model->total_things = $model->one_thing + $model->other_thing;
                return $model;
            });
}

Solution 4:[4]

Most of the answers already provided will work, but will return a collection instead of a paginated resource. The trick is to use the tap helper method before map'ping, to return the same object you modified.


   public function index()
    {
        return tap(Model::select(['id', 'some_field', ...// more some fields])
            ->with('data') // load relation
            ->paginate(20))
            ->map(function ($model) {
                $model->something_to_format = someFormattingHelper($model->something_to_format);
                return $model;
            });
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 jerome gallego
Solution 3 Eric Tucker
Solution 4 Sam