2

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!

Petro Gromovo
  • 1,755
  • 5
  • 33
  • 91
  • Where and how are you instantiating this UserCollection and what parameter is passed? Does a collection exist after instantiating? – Eric Landheer Jul 08 '21 at 06:29
  • I provided additive info in Updated block. Is it all you requested? – Petro Gromovo Jul 09 '21 at 04:01
  • Yes, so you see the `\Log::info()` data in your log files? Does your PageCollection contain the data **before** calling the `sendOkResponse()`? – Eric Landheer Jul 09 '21 at 06:39
  • 1) No I do not see data by Log::info, so "with" method is not called. 2) No, as in line return $this->sendOkResponse(PageResource::collection($pages), ''); I use both, without any new method. Have I to init PageResource with new somehow? – Petro Gromovo Jul 09 '21 at 07:39
  • Could you add a screenshot of the result of `dd(PageResource::collection(Page::all()));` in your `index` function of `PageController`? – Eric Landheer Jul 09 '21 at 08:00
  • With line dd(PageResource::collection(Page::all())); I got hardly readable output with 200 code returned: https://prnt.sc/19pdyoz I try to use my log wrapper log function like : \Log::info( varDump(PageResource::collection(Page::all()), ' -1 PageResource::collection(Page::all())::') ); Output is huge, so link : https://pastebin.com/gbWgGR6u Hsa it all info you need ? – Petro Gromovo Jul 09 '21 at 10:15

1 Answers1

1

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.

brice
  • 1,801
  • 1
  • 10
  • 15
  • I define my class as : class Page extends JsonResource with command : php artisan make:resource PageResource But in your link UserCollection is used, I suppose it was created with command php artisan make:resource User --collection I prefer to use Resource based on JsonResource, as some requests 1 object, not collection. Has it matter ? – Petro Gromovo Jul 12 '21 at 04:00
  • Pls, look at Updated block # 2 – Petro Gromovo Jul 13 '21 at 11:45