PHP Fractal transformers - Multiple Transformers for a single model? - php

Is it better to have multiple Transformers over a single transformer per model?
e.g.
I want to exclude a fields from the JSON response when listing items. Although when retrieving a single item I want all fields. Would a PostListTransformer and a PostTransformer be appropriate, or should i use the "includes" feature of Fractal?
Also I would like the ability to include extra fields AND relations in the PostListTransformer.
Examples will be well regarded, Laravel Eloquent is the ORM.

What you could do is add a $fields property that gets populated with the fields you only need through your transformer's constructor method, then create a method that uses those fields (if any exist) to filter out your transform() method output. You can find some code for it in one of the closed issues in the fractal github repo
https://github.com/thephpleague/fractal/issues/226#issuecomment-156802672

Related

Laravel collection: pluck before serialization

I have a laravel Model with a one to many relationship which the user can edit via a multiple select tag.
Before exporting the model as a JSON, I use the "pluck" method to get an array of related IDs instead of an array of models, so that they can be used in the select tag and later be synced again with the "sync" method of Laravel.
However the result of "pluck()" seemingly doesn't persist over serialization. The following code doesn't work -upon serialization, "relationship" becomes again an array of objects-
$model->relationship = $model->relationship->pluck('id');
This one, however, does what it should: somePropertyIHaveJustCameUpWith is an array of IDs
$model->somePropertyIHaveJustCameUpWith = $model->relationship->pluck('id');
1) Why does this happen?
2) I have seen there is this resources way in the documentation, but creating an entire new class for something that could be solved with a single line of code feels like a bit overkill. Isn't there a cleaner way to do that?
I think this is likely a result of the way the model implements toArray().
The you can trace the steps taken, but eventually the relations are read from the $this->relations property on the Model, not from each individual relationship.
So, instead of setting the value of your relation directly like:
$model->relationship = $newValue
... you could try setting it using:
$model->setRelation('relationship',$newValue)
This will update the $model->relations property.
This should allow the toArray() method to get the new value that you set when serializing.
Note that the toJson() method in turn calls the toArray() method when serializing. So either approach will be the same result.

Symfony - Transform Data before sending to view

Hi !
i'd like to transform data before sending it to the view. The view is json response using FOSRestBundle.
For example, I have a Product entity with field Category, that is a reference to a Category Entity. On the output, i'd like to not to display json with the whole category, but rather only its ID field.
Of course, you can further process the entity in the Controller to return only specific field from the category, but..
I wanted to ask, if there's any "standard" solution how to do that, maybe using annotation?
Thank you
I reckon the best practice or standard way to achieve what you want (filtering/processing entity data before return as JSON to view), is to make use of serializer. You can consider using the Symfony Serializer Bundle: http://symfony.com/doc/current/components/serializer.html or the JMS Serializer: http://jmsyst.com/libs/serializer.
I myself recommend the JMS one, it has really good documentation, the definition is completely controlled through annotation, and a well-thought events system and a few feature I can list as follows:
-- Expose / Exclude specific entity attributes.
-- Create Virtual Property (attributes) for the entity once it converted to JSON. (So for example if you have Entity Product with attribute Price and you want to have a calculated field in the JSON object call taxPrice you can achieve it).
-- Access Control who can access which attributes/entities by categorising attributes to different groups.
-- Pre Serialization and Post Serialization events so you can tweak the data even further.
I can say the Serializer works so well with the Forest Bundle that once you get used to it, you can hardly write your project the different way :D.

How to load an entity in Symfony without special fields

i want to load an entity in my Controller, but dont want that the entity contains all fields. I did that before with the Jms-Serializer, where you can use the Groups Annotations, to avoid loading special fields. But i there you have to serialize your object to json/xml etc.
And i dont want it serialized, i just want that groups function. I searched this site and the internet, but didnt found any solution for my problem.
Hope that someone understand what i mean and got an idea :)
There are a couple of possibilities:
Use partial objects (which will deliver objects where only specified attributes will be filled during hydration): http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/partial-objects.html#partial-objects
This is dangerous and you should be extra careful, because it looks like a fully loaded entity from all perspectives. You have to know why a field is null - just because it's null or because it simply hasn't been filled during hydration.
Don't hydrate objects but query for an array as hydration result (by that again you can specify which array keys you would like to get back): http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#array-hydration
Use this for performance-sensitive queries where you need a lot of read-only data and complex joins. But be aware that you don't have any entities you can manage with Doctrine (e.g. updating, deleting etc.).
Use DTOs which are objects but non-Doctrine-managed entities, there again you can specify what you would like to get hydrated with the NEW syntax: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#new-operator-syntax
Basically the same advise as in 2) but this time you'll get objects. So you can use all your OOP wisdom.
Create your own custom hydration mode - there you can define on your own how entities should be hydrated: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes
Very advanced level. Only useful if you need a special hydration mode for several entities and really no other option delivers at performance and quality as you require it.
You can use partial objects, but you should be careful. For example:
$q = $em->createQuery("select partial u.{id,name,otherField} from MyApp\Entity\User u");
You can read more here: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/partial-objects.html

Apigility+Doctrine: custom response

I have a project running on Apigility + Doctrine. From a scratch (automatically without writing extra code), I can retrieve entities and collections with pagination, filtering, etc.
This is perfect when retrieving DB rows, however, most services need to return much more data. For example: a to-do list where the "tasks" have parents, if you want to retrieve this like a tree, you´ll have to process it first. Very often I need flags to tell the frontend how to process data or keys to display or hide stuff. Sometimes it is useful to retrieve extra information that is not expressed in the database as FK or PK, etc.
So far, with Apigilty+Doctrine, if I want to add ANY information to the output, I have to modify the Entity, set up the correct keys, and it works. However, from the previous examples you can see that the data that I need is NOT coming from the database or I cannot simply express the relation as a DB dependency.
Questions:
What is the correct way of doing this?
Is there are documentation about this problem?
How can I customize my output keeping a correct HAL structure?
By default, the Entity values will be given as response as is. If you want to modify the value (eg: retrieving parent data, retrieving child data, or modifying the data format) you should create a Hydrator for this Entity, and custom Hydrator Strategy for this Entity value.
Here is Hydrator example from my Apigility and Doctrine project
https://github.com/aqilix/zf3-apigilty-oauth2/blob/1.0.1/module/User/src/V1/Hydrator/UserProfileHydratorFactory.php

Should models representing a single row return data generated using multiple rows?

Some background:
This is for an MVC application built without using any frameworks, but follows the MVC paradigm.
I am using an ORM library called RedBean to talk to the database.
While RedBean represents data using "beans", it supports wrapping them into a model, so custom functions may be provided by the model:
$account = R::dispense('account');
$account->name = "john";
R::store($account);
$account->getFormattedLastUpdatedTime('America/New_York');
Now the question:
Currently, each instance of the model would represent 1 row in the database. If I have a collection of accounts, then I would have an array of "account" models.
In the application, I have a feature for custom profile fields (don't worry, I am not using EAV though :)). One of the tables stores metadata for those fields (name, description etc) for generating the form fields for those custom profile fields. Once again, each row of the metadata represents 1 form field and each row is represented by 1 model.
I now wish to write a method to convert all those rows into a form object which can then be used for rendering and processing the form. But, where should this method live? My initial thought was to place it in the model representing the custom profile field metadata.
Clarification: This function would not be in the account model, but instead in the profile_fields_meta model.
Problem
As each model should represent 1 row, it seems a bit "dirty" to have the model return an object that would be generated from MULTIPLE rows in the database. Am I correct to say this is not the best way to do it? What do you recommend I do instead?
It would be right to have extended ArrayObject (http://php.net/manual/en/class.arrayobject.php) or other container class to run methods for collection.
Try to modify query methods to return data in your custom collection class instead of array if specified.
There's nothing inherent to MVC that says "each model [instance] should represent one row." Often in MVC frameworks the model (as seen by the controller, at least) is entirely ignorant of the data store and doesn't have any concept of or direct mapping to a "row." This isn't necessarily the case with ORMs but a model needn't adhere to an ORM's constraints.
However, though it's hard to tell without knowing more about your schema and implementation, the functionality you're describing doesn't sound appropriate for your Account model. In fact, it sounds to me like you should consider having a "FormField" model such that, in Rails parlance, Account "has many" FormFields.
And for the record, EAV isn't always bad, it's just often misused.

Categories