Framework: API resources toArray does not work together with whenLoaded()

Created on 12 Feb 2018  路  4Comments  路  Source: laravel/framework

  • Laravel Version: 5.5.34
  • PHP Version: PHP 7.1.11

Description:

When calling toArray() on an API Resource that uses the whenLoaded() helper method and that particular relation is not loaded, an ErrorException is thrown.

Trying to get property of non-object in ResourceCollection.php (line 48)

Steps To Reproduce:

  1. Create an API Resource that conditionally loads a relation using the whenLoaded() helper method.
  2. Make sure the particular relation is not loaded.
  3. Manually call the toArray() method on the resource.
  4. The above described exception will be thrown.

Most helpful comment

I had a similar problem and I fixed it by wrapping all my custom code related to the relation inside the "relationLoaded" conditional, for example:

if ($this->relationLoaded('relation-name')) {
  // call the toArray() method here
}

All 4 comments

I had a similar problem and I fixed it by wrapping all my custom code related to the relation inside the "relationLoaded" conditional, for example:

if ($this->relationLoaded('relation-name')) {
  // call the toArray() method here
}

Despite being marked public, I don't believe resource toArray() methods were ever meant to be invoked in app code. The framework has no unit tests directly calling that method. There are only integrations tests making assertions on HTTP response JSON. The docs also don't demonstrate an example call to $resource->toArray($request): https://laravel.com/docs/5.7/eloquent-resources

Since the constructor of ResourceCollection never assigns a wrapped collection when MissingValue is passed in (for a relation not loaded), this would likely be the framework fix in your use case:

public function toArray($request)
{
    if (! $this->collection) {
        return [];
    }

    return $this->collection->map->toArray($request)->all();
}

But I don't see how that change could be covered by an integration test. ConditionallyLoadsAttributes already removes such a ResourceCollection item when resolving the HTTP response.

@derekmd is right. I don't think it's meant to be used like this.

For anyone still stumbling across this: Use $resource->resolve() instead of $resource->toArray(null). This works like a charm, even together with whenLoaded().

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lzp819739483 picture lzp819739483  路  3Comments

YannPl picture YannPl  路  3Comments

RomainSauvaire picture RomainSauvaire  路  3Comments

PhiloNL picture PhiloNL  路  3Comments

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments