Access relationships in models

joselfonseca - 6 months ago

Hello all! I am having a bit of a problem accessing the relationships for a model, say i have a model with a field type repeater. I need to access the contents of the repeater in a controller to expose the stream + its relationships in an API, We have the API module but the way to get the info is not what we are looking for. Therefore we are creating our own endpoints. Say i have an endpoint /api/treatments and i want to espose the stream treatments that has 3 repeaters and a relation to other stream.

<?php

namespace Facelift\TreatmentsModule\Http\Controller\Api;

use Anomaly\Streams\Platform\Http\Controller\ResourceController;
use Facelift\TreatmentsModule\Treatment\Contract\TreatmentRepositoryInterface;

class TreatmentsController extends ResourceController
{

    protected $repository;

    public function __construct(TreatmentRepositoryInterface $repository)
    {
        parent::__construct();
        $this->middleware(['throttle:60,1', 'auth:api']);
        $this->repository = $repository;
    }

    public function index()
    {
        $treatments = $this->repository->all();
        dd($treatments);
        return response()->json($treatments->treatment_alias_name);
    }

}

In that dd i get a Treatments collection but i do not have access to the relationships. There is no method with in the repository to be able to eager load the relationships, and i have not been able to figure out the way to get them, in the compiled model the relationships are defined but if i try to access it it returns null, sale thing if i get the model from the repository, get the first record and try to access the relationship, comes back as null. Any help is appreciated. Thanks!

Answer

ryanthompson - 6 months ago

Hey there! You don't have to use the repository here. If you want to create your own repository method to eager load the model in your query you can do that - like allWithTreatments() or something.

But you can use the model directly or start a new query from the repository like $repository->newQuery()->where(foo, bar)->get(); for example.

You might need to override the toArray() or the __sleep() (used for JSON data definition) method on the model to loop / prepare the related data. Im not sure how that one will expose. Either way with a custom endpoint though you can definitely do it.

Hope this helps!

ryanthompson - 6 months ago

Hey there! You don't have to use the repository here. If you want to create your own repository method to eager load the model in your query you can do that - like allWithTreatments() or something.

But you can use the model directly or start a new query from the repository like $repository->newQuery()->where(foo, bar)->get(); for example.

You might need to override the toArray() or the __sleep() (used for JSON data definition) method on the model to loop / prepare the related data. Im not sure how that one will expose. Either way with a custom endpoint though you can definitely do it.

Hope this helps!

joselfonseca - 6 months ago

Thanks! i did it like this.

public function getForApi(array $params = [], $limit = 20)
    {
        $model = $this->model;
        if(array_key_exists('app_manipulations', $params)) {
            $params['app_manipulations'] = explode(',', $params['app_manipulations']);
            $model = $model->whereHas('treatmentAppManipulation', function($q) use ($params) {
                $q->whereIn('app_manipulation_string', $params['app_manipulations']);
            });
        }
        return $model
            ->with([
                'treatmentAliasName',
                'treatmentImage',
                'treatmentAppManipulation.appManipulationFacialAreaRelation'
            ])
            ->paginate($limit);
    }

And the controller

/**
     * List treatments in the API with some search criteria
     * /api/treatments
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function index(Request $request)
    {
        $treatments = $this->repository->getForApi($request->all(), $request->get('limit', 20));
        $treatmentsCollection = $treatments->getCollection();
        return fractal()
            ->paginateWith(new IlluminatePaginatorAdapter($treatments))
            ->collection($treatmentsCollection, new TreatmentTransformer())
            ->respond(200);
    }

ryanthompson - 6 months ago

That'll do it! Good job ^_^