Can I use transformers to transform data coming from API rather than from database?
Asked Answered
B

2

11

I have been using laravel to build my APIs. I use transformers to tranform data from model object.

Now instead of database, I have a response coming from an API as the data source and I want to transform that data back to a user, but I am unable to do so.

My Controller

 public function rocByName(Request $request)
    {
        try {
            $this->roc_by_name_validator->with( $request->all() )->passesOrFail();
            $company_name = $request->input('company_name');
            $result = $this->my_service->getDetailsByName($company_name); //$result has the response object from the API which I want to transform and give it as a response.

             return $this->response->collection($result,new OnboardingTransformer()); //Tried using tranformer like this
        }
        catch (ValidatorException $e) {

            dd($e);

        }

    }

My Transformer

<?php

namespace Modules\Onboarding\Transformers;

use League\Fractal\TransformerAbstract;
use App\Entities\OnboardingEntity;  //I dont have an entity since the response is coming from an API!! What will give here?

/**
 * Class OnboardingTransformerTransformer
 * @package namespace App\Transformers;
 */
class OnboardingTransformer extends TransformerAbstract
{

    /**
     * Transform the \OnboardingTransformer entity
     * @param \OnboardingTransformer $model
     *
     * @return array
     */
    public function transform(OnboardingEntity $data_source) 
    {
        return [
            'company_name'         => $data_source->company_name,
        ];
    }
}

Here the OnboardingEntity refers to data coming from database ideally. Here I am not fetching data from database, instead my data is from an API source. How do I go about it. I am little consfused here. Can someone give a solution?

$result has the following response

[
    [
        {
            "companyID": "U72400MHTC293037",
            "companyName": "pay pvt LIMITED"
        },
        {
            "companyID": "U74900HR2016PT853",
            "companyName": "dddd PRIVATE LIMITED"
        }
    ]
]
Blodgett answered 6/7, 2017 at 6:56 Comment(8)
I believe you dont need to convert it into collection. you ca directly pass the array to transformers.Labourer
@AdnanMumtaz Thats also fine. Can you add a sample code in the answer?Blodgett
$result = $this->my_service->getDetailsByName($company_name) are you recieving collection or array in $resultsLabourer
@AdnanMumtaz I have updated the question with a sample response coming in $result. Please check. Its an arrayBlodgett
@ companyName how a company name can be a integer?Labourer
@AdnanMumtaz Please ignore. That was a typo there. Its a stringBlodgett
is it working fine now?Labourer
@AdnanMumtaz But you didn't give an answer to my question. I dont have an entity, what will I use instead of that?Blodgett
R
2

$this->response->collection is meant to get a collection of objects, not the array. Then all of this objects is going to transformer that is transform OnboardingEntity objects as you want. So first you should transform your input array into collection of objects. The example how i did it above (you should change it to your own input array)

$data = json_decode('[
    [
        {
            "companyID": "U72400MHTC293037",
            "companyName": "pay pvt LIMITED"
        },
        {
            "companyID": "U74900HR2016PT853",
            "companyName": "dddd PRIVATE LIMITED"
        }
   ]
]');  

$data = collect( array_map( function($ob){
    return (new OnboardingEntity($ob));
}, $data[0]));

And then pass this collection of OnboardingEntity objects to $this->response->collection method, like here $this->response->collection($data,new TestTransformer());

Rizas answered 13/7, 2017 at 9:17 Comment(3)
How will I create an entity OnboardingEntity if the fields of the objects changes from response to response? Do I have to create models for each and every response?Blodgett
@Blodgett it's not neccessary, but i'll highly recomend you do this. If you dont want to create models for all response arrays entities you have to remove parameter type in transform method, than it'll recieve stdClass object and you'll be able to access properties thru -> operator. $data=collect($data[0]);//convert to stdClass collection and transform function will look:public function transform($data_source) { return [ 'company_name' => $data_source->companyName, ]; } whatever you'll need to create transformers for all types of response, cause they have diff fieldsRizas
this answer is not clear..wonder why it is upvoted..did it work for anybody?Caseinogen
I
2

You may want to send common data structure to Fractal as sources of data are different. Array is best possible type for you.

Consider this when you are fetching data from Eloquent(DB):

 $result = $yourModel->get(); // This will return you with a collection object.

Before passing this object to fractal convert it to array.

 $this->response->collection($result->toArray(),new OnboardingTransformer());

In case of first or single model object. check for null before calling toArray().

 $result = $yourModel->first();
 if($result){
      $result = $result->toArray(); 
 }
 // Fractal itself can handle null 

Now for second scenario where data is coming from external source like API or file.

 $result = $this->my_service->getDetailsByName($company_name);
 // Try converting your response object to array from within

You can do this with json_decode(<Body of response>, true). And then pass this array to Fractal.

Why Array?
Because source of data could be anything from Database to File, from Cache to APIs. Format could be JSON or XML. Converting all these to array comes built in PHP.

Isis answered 14/7, 2017 at 5:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.