mstdmstd's avatar

Looks like resource toArray method is not called with collection ?

In laravel 8 app I added resource with command

php artisan make:resource HtmlBlockResource

But calling it in controll :

        $htmlBlocks = HtmlBlock::getById(1)->paginate(20);
        return view('html-blocks.list', [
            'htmlBlocks' => HtmlBlockResource::collection($htmlBlocks)
        ]);

I see only fields I got from db, looks like resource toArray method was ignored. I have in app/Http/Resources/HtmlBlockResource.php :

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class HtmlBlockResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
     */
    public function toArray($request)
    {
        \Log::info(  ' INSIDE HtmlBlockResource::' ); // I DO NOT SEE THIS LOG MESSAGE
        return [
            'name'                 => $this->name.'000000000',
            'active'               => $this->active,
            'active_label'         => $this->active.'AAAAAAA',
        ];
    }
}

Reading https://laravel.com/docs/8.x/eloquent-resources I suppose that I use collection in valid way and do not see what is wrong ?

In my app :

        "fruitcake/laravel-cors": "^2.0",
        "guzzlehttp/guzzle": "^7.0.1",
        "jd-dotlogics/laravel-grapesjs": "^3",
        "laravel/framework": "^8.75",
        "laravel/sanctum": "^2.11",
        "laravel/tinker": "^2.5",
        "laravel/ui": "^3.4",

Thanks!

0 likes
5 replies
jorgensolli's avatar

Resources are only for returning JSON data (i.e as an API). So passing this to a blade view will never resolve the resource.

2 likes
vincent15000's avatar

To solve this problem, I would first display the content of the different variables.

dd($htmlBlocks);
...
dd(HtmlBlockResource::collection($htmlBlocks));

Furthermore, as @jorgensolli said, it returns JSON data which will be difficult to explore in blade.

1 like
jorgensolli's avatar

A "hacky" workaround for this would be

return view('html-blocks.list', [
     'htmlBlocks' => HtmlBlockResource::collection($htmlBlocks)->toArray()
]);

Altho this is using really outside of the scope of what Resources are meant for.

2 likes
mstdmstd's avatar

@jorgensolli Adding of ->toArray() : raised error :

Too few arguments to function Illuminate\Http\Resources\Json\ResourceCollection::toArray(), 0 passed in /home/vagrant/code/landigator/app/Http/Controllers/HtmlBlockController.php on line 19 and exactly 1 expected

If Resource must be used with json returned, what else can be used here ? Just edit in blade file ?

rodrigo.pedra's avatar
Level 56

@mstdmstd

A resource's ->toArray() method expects the Request instance as a parameter. Try this:

return view('html-blocks.list', [
     'htmlBlocks' => HtmlBlockResource::collection($htmlBlocks)->toArray(request())
]);

Or if you already have the request in your controller's method

return view('html-blocks.list', [
     'htmlBlocks' => HtmlBlockResource::collection($htmlBlocks)->toArray($request)
]);

But as others said, this is not what resources were meant to. You will lose, for example, the ability to easily render the pagination links, as the view won't receive a Paginator instance anymore, but an array.

You will also need to iterate over records like this:

@foreach($htmlBlocks['data'] as $record)
    {{ $record['field']  }}<br>
@endforeach

All paginated collections wrap the list of records into a data key, and your records won't be objects anymore, so you will need to access their fields with array notation, note also that object values, such as dates like created_at and updated_at, won't be objects anymore, so you cannot call ->format(...) on them.

I see you want to transform data, by concatenating a suffix on that. My suggestion is that you either:

$htmlBlocks = HtmlBlock::query()
    ->getById(1)
    ->paginate(20)
    ->through(function (HtmlBlock $record) {
        $record->name = $record->name . '000000000';
        $record->active_label = $record->active_label . 'AAAAAAA';

        return $record;
    });

return view('html-blocks.list', ['htmlBlocks' => $htmlBlocks]);
2 likes

Please or to participate in this conversation.