swisnl / json-api-client

A PHP package for mapping remote {json:api} resources to Eloquent like models and collections.
MIT License
205 stars 24 forks source link

Children of repository are only `Item`s? #70

Closed iwasherefirst2 closed 4 years ago

iwasherefirst2 commented 4 years ago

Detailed description

I have one repository CongressRepository and two Items, CongressItem & SpeakerItem. A CongressItem has many SpeakerItems.

If I fetch the children of CongressRepository, then they seem to be of Item class and not a class of CongressItem.

I am not sure if this is a bug or if I am just not using it right.

    $repository = app(App\Repositories\CongressRepository::class);
    $document = $repository->all();
    if ($document->hasErrors()) {
        // do something with errors
    } else {
        $congresses = $document->getData();
        $congress = $congresses->first(); // <- this is  an instance of `Item`, not of `CongressItem` 
       $congress->speakers()->getLinks() // <- This fails

The last command fails with this error message:

Symfony\Component\Debug\Exception\FatalThrowableError Call to undefined method Swis\JsonApi\Client\Item::speakers()

This also causes other issues, like if only the link of speaker is provided by the API, then $congress->speakers is null.

Context

This is the output when calling the api /api/v1/congresses:

grafik

This is my CongressItem class:


<?php

namespace App\Items;

use Swis\JsonApi\Client\Item;

class CongressItem extends Item
{
    protected $type = 'congress';

    protected $availableRelations = ['speakers'];

    public function speakers()
    {
        return $this->hasMany(SpeakerItem::class);
    }
}

And my CongressRepository

<?php

namespace App\Repositories;

use Swis\JsonApi\Client\Repository;

class CongressRepository extends Repository
{
    protected $endpoint = 'congresses';
}

What I tried so far

I also tried to bind the TypeMapperServiceProvider and explicitly added the items there:

    protected $items = [
        \App\Items\CongressItem::class,
        \App\Items\SpeakerItem::class,
    ];

but this didn't help either. Also, as far as I understood the docs, I don't have to do this step because I am extending the class from Item.

Your environment

Using Laravel v6.4.1 on Ubuntu 18.04 with Homestead v9.4.0 & Vagrant 2.2.5. PHP Version is 7.3

iwasherefirst2 commented 4 years ago

Fixed it. There were two things that I did wrong:

  1. I actually misinterpreted the docs, even if you extend from Item you have to use TypeMapperServiceProvider (I thought its only necessery if one implements the interface and creates a custom item class).

  2. I followed the instructions here and create for each item a typein singular, however, in this backend tutorial the type is in plural. You see above congress is used in Item but congresses is used in API. I had to change it to congresses in the item, now it works.

JaZo commented 4 years ago

Hi @iwasherefirst2, good to hear you found it out! Indeed every custom item should be registered with the TypeMapper and the type should correspond with the type used by the API.