Search code examples
laravellaravel-resource

Why my resource do not return all meta data having "with" method?


In lumen 8 app I use resources and reading here https://laravel.com/docs/8.x/eloquent-resources

I try to use “with” method, as I want to add some meta data to any request and I have no this meta data in returned data :

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
use App\Models\Page As PageModel;
use App\Http\Resources\User as UserResource;


    class Page extends JsonResource
    {
        public function toArray($request)
        {
            return [
                'id' => $this->id,
                'title' => $this->title,
                ...
                'created_at' => $this->created_at,
            ];
        }
    
        public function with($request)
        {
            \Log::info( '-1 unction with ::' . print_r( 1, true  ) ); // I DO NOT SEE THIS LOGGINHG line
    
            return [
                'meta' => [
                    'version'=>getAppVersion()
                ]
            ];
        }
    
    }

In the referenced docs resource is declared a bit different from ResourceCollection:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
    public function toArray($request)
    {
        return parent::toArray($request);
    }

    public function with($request)
    {
        return [
            'meta' => [
                'key' => 'value',
            ],
        ];
    }
}

Could it be the issue and how can fix my resource to get all meta data ?

Updated block: UserCollection - that is collection https://laravel.com/docs/8.x/eloquent-resources my collection is Page and I use it in controller as :

namespace App\Http\Controllers;

use Carbon\Carbon;
use App\Models\Page;
use Illuminate\Http\Request;
use App\Http\Resources\Page as PageResource;
use Config;
use App\Http\Requests\PageRequest;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Validator;

class PageController extends Controller
{
    public function index()
    {
        $pages = Page
            ...
            ->get();

        return $this->sendOkResponse(PageResource::collection($pages), '');

    }

sendOkResponse defined in Http/Controllers/Controller.php :

class Controller extends BaseController
{
    protected $requestData;

    public function __construct()
    {
        $request           = request();
        $this->requestData = $request->all();
    }

    public function sendOkResponse($responseResult, $message)
    {
        $response = [
            'success' => true,
            'data'    => $responseResult,
            'message' => $message,
        ];
        return response()->json($response, HTTP_RESPONSE_OK);
    }

I suppose PageResource is destroyed at PageController controller index method exit...

Updated block # 2: After some tests I found that Resource method “with” does not work if collection is returned and I need to use ->additional in controller like:

return (PageResource::collection($pages)) 
->additional([
    'meta' => [
        'version' => getAppVersion()
    ]
]);

But in cases when I return sinopgle element(ex store method) like

return (new PageResource($page));

method “with” works ok.

That exludes using of wrapper like sendOkResponse. Is is the only proper way?

Thanks in advance!


Solution

  • Laravel resources are intended to be returned directly from your controller's action method, not as part of an associative array representing JSON.

    When wrapping your responses with the sendOkResponse method, the resource is not being returned directly from the method and thus toArray is being called on your resource. The with method on your resources is being ignored.

    Try returning the resources directly from your controller's method. Use the additional method when constructing your resources to pass the extra attributes in the response. See: https://laravel.com/docs/8.x/eloquent-resources#adding-meta-data-when-constructing-resources.

    If you can control the API contracts, I'd recommend changing them to omit success entirely, this can be derived from the HTTP status code.