3

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).

Dmitry K.
  • 3,065
  • 2
  • 21
  • 32

6 Answers6

5

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.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
3

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;
}
2

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;
            });
}
Eric Tucker
  • 6,144
  • 1
  • 22
  • 36
1

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;
            });
    }
Sam
  • 304
  • 4
  • 12
0

I'm not sure if anyone still needs this. But I found another solution. It's not the best solution, but it gets the job done.

Both the transform() and map() functions are supported. Here's the link: https://jnbrnplbr.medium.com/transform-map-laravel-paginated-collection-b1ab912d7996

0

map or transform will not work. You should use through which is supported in AbstractPaginator as specified in laravel official api.

Ex:

User::filter($request->all()
   ->with('applications')
   ->paginate(config('app.defaults.pageSize'))
   // through() will call transform() on the $items in the pagination object
   ->through(function ($user, $key) {
      $user['picture'] = $user->avatar;

      return $user;
   });

Ref: https://stackoverflow.com/a/65560742/11297747

free2idol1
  • 174
  • 1
  • 3
  • 12