Symfony - Transform Data before sending to view - php

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.

Related

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

PHP Fractal transformers - Multiple Transformers for a single model?

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

Symfony/Doctrine: Fetching entity fields from outside the database

I'm working on an ecommerce Symfony application, but I've been really struggling to find some information about how to create entities that retrieve some data from Doctrine, and some from an external source.
This is a website that's going to be selling the same items that are available inside of a brick-and-mortar store that already has a pre-existing inventory system.
My current situation is that this application needs to be able to retrieve price and stock information from an external source (the REST API of our in-store inventory system), while the majority of the data is handled by Doctrine.
For example, I have a Product class that looks like this:
class Product
{
protected $id;
protected $title;
protected $description;
protected $quantity;
protected $price
}
I would like the first three fields to be handled by Doctrine like any other entity (which I already have set up, and there's tons of documentation on), but the last two to be retrieved based on an arbitrary data source (the REST API of our backend data, and this needs to be able to change as the store grows and their backend changes)
Ultimately, I want these product entities to be callable from any standard doctrine query and have all the fields fully available like any other entity. (including price and quantity)
I'm wondering if anybody can suggest how this problem would be solved in the Symfony ecosystem.
At this point I'm looking at a Doctrine postLoad event subscriber that manipulates the entities before they're returned, but I'm wondering if that's the way to go, and how to structure the code to do it. (I'm guessing I first need a separate bundle that exposes a "price" service, so I can do $Service->getPrice($ProductID), then where would I place that getPrice call? I feel like it isn't something that belongs inside of the entity class itself (since that classes purpose is only to define what the entity is, not how to make one), but that's what Doctrine docs seem to suggest)
I've asked a similar question here, but did not get very clear responses so I'm hoping that simplifying the problem might help.
I would create a service to access your REST API data and then inject it into Doctrine EventSubscriber. Inside that subscriber I would handle postLoad event to load data from REST API.
This service can be a part of an existing bundle.

Symfony2 Doctrine Change Value on Entity Load

I have a database structure which has a field content. In the database this is a BLOB (so a string). content contains a JSON-encoded string.
When I load this, I would like to load it in to a specific Content object (with a different Content subclass for each possible format of the JSON).
Are there any events or anything which I can hook up so I can catch the value right before the Entity is built (so I can have setContent() type-hint the Content class instead of having to be generic, which I'd have to do if the information is loaded in to the Entity before I intercept).
Any ideas?
A bit more details. Basically what I imagine is having some sort of Factory class which takes a JSON string and converts it to a proper object.
{
body: "ABC",
value: 5
}
Goes to an object of a class like this:
class MyContent extends Content
{
protected $body;
protected $value;
}
I can't use typical object mapping because it's a JSON string to an object.
Further clarification
Basically, I have an entity named Box. Box has a content value, which is supposed to be an instance of Content.
Under normal circumstances, if Content was a normal database Entity, I would just hook up a One-to-One relationship between Box and Content, which would load Content properly in to the Box without needing to do anything special.
However, in this case, Content can have many forms. To handle this, it is stored as a JSON object in a BLOB field in Box's table. This means when Doctrine tries to load Box, it will try to load a string.
I could simply have Box::setContent() accept any parameter and deal with it accordingly based on if it is a string or Content object.
However, I'd like it so when it is used it is always a Content object, so I want type-hinting for the function (i.e., Box::setContent(Content $content)). The problem is this would prevent Doctrine from giving that field a string.
Which is why I want to intercept the value Doctrine has for content and replace it with a proper object before it loads it in to the entity Box.
I don't think any of the Doctrine events do exactly what I want, so it may not really be possible. =S
You should be able to add code to the entities get method to do this. You can also check out the lifecycle call backs for doctrine: http://docs.doctrine-project.org/en/2.0.x/reference/events.html#lifecycle-callbacks
You can use JMSSerializer to create entities from JSON - https://github.com/schmittjoh/JMSSerializerBundle.
And I can`t understand you question, but maybe you can use json_array type - http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#doctrine-mapping-types
You need to load data from DB and than create entities? Or load entities with some field that have nested entity deserialized from JSON?
Ultimately what I ended up doing was just creating different tables and Entities for each possible Content type and then using Doctrine's inheritence to let Doctrine handle them. Not idea (since there may be many, many types which means more tables and I can't just dynamically constructor new types), but it works well for now.
Doctrine Inheritence

Categories