JMSSerializer not serializing entity - symfony

I am trying to get a serialized entity response using the JmsSerializerBUndle and the FOSRestBundle. unfortunatly i'm unable to do so because i'm having problems
with the response.. i'm not sure the system recognizes the file Entity.SearchEngine.yml
Any Ideas how I could find why its not working?
#src\example\CoreBundle\Resources\config\serializer\Entity.SearchEngine.yml
Example\CoreBundle\Entity\SearchEngine:
exclusion_policy: ALL
properties:
id:
expose: true
groups: [search.list,search.details]
has_product_flight:
expose: true
groups: [search.details]
selfLink:
expose: true
groups: [self.link]
Rest action (using the FOSRestBundle):
/**
* GET /search/engines
*
* #return array
* #Rest\View(serializerGroups={"search.details", "self.link"})
*/
public function getSearchEnginesAction()
{
$searchEngineManager = $this->get('search_manager');
return $searchEngineManager->getSearchEngineList();
}
the response im getting is
{
0: { }
}

First, is SerializerBundle configured correctly? You should supply config for paths to your .ymls and corresponding namespaces, like this:
jms_serializer:
metadata:
auto_detection: true
directories:
ExampleCoreBundle:
namespace_prefix: "Example\\CoreBundle"
path: "#ExampleCoreBundle/Resources/config/serializer/"
Be sure to check that your search.manager service returns instances of SearchEngine. Also, I'm not sure if dots are supported in group names.

Related

Empty relations when serializing with JMSSerializer

I am having troubles while writing a controller-action inside a Symfony project, that should return data (in this particular case orders of a web-shop). Yeah ... It's a kind of a REST-API. That route just get's called from some JavaScript. And the data has to be visualized on the client-side.
The Problem:
I cannot find out, why the serialization of related entities results in empty objects. In this example it is the user of an order, which is empty.
This is a sample output:
orders: [
{
id: 2,
created: '2016-05-04T11:40:27+00:00',
user: {},
}
]
When I do something like
$orders = $this->getDoctrine()->getRepository('AppBundle:Order')
->findAllCompleted();
$serializationContext->setSerializeNull(true);
$serializationContext->setGroups(['statistics']);
$json = $serializer->serialize($orders, 'json', $serializationContext);
$response = new Response($json, $statusCode, [
'Content-Type' => 'application/json',
]);
return $response;
... i get a nice JSON response from the server, but every related entity of each order, like let's say user is {} (empty).
Even if I dump the related entity before it gets serialized like so:
[...]
$myOrder = array_filter($orders, function($order) {
if ($order->getId() == 2) {
return true;
}
return false;
});
dump($myOrder[0]->getUser());
die();
... it results in an empty (unhydrated) entity.
But if I change this debugging code to:
$myOrder = array_filter($orders, function($order) {
if ($order->getId() == 2) {
return true;
}
return false;
});
dump($myOrder[0]->getUser()->getUsername());
die();
... I get a clear output (string) with the value of the username of that entity.
So I think the issue is about a non hydrated entity, and not the serializer or its wrong configuration.
How can I get the JMSSerializer to take care of the hydration of those related entities?
I didn't find any hint in the docs ...
BTW, this are the JMS entity configs of order and user.
AppBundle\Entity\User:
exclusion_policy: ALL
properties:
userMeta:
expose: true
address:
expose: true
username:
expose: true
email:
expose: true
isReseller:
expose: true
acceptPublicOrders:
expose: true
vatNumber:
expose: true
taxRate:
expose: true
AppBundle\Entity\Order:
exclusion_policy: NONE
properties:
id:
groups: ['statistics']
user:
groups: ['statistics']
configuration:
groups: ['statistics']
created:
groups: ['statistics']
invoiceItems:
groups: ['statistics']
exclude: true
I think your problem is caused by doctrine lazy loading maybe you can try to change the fetch mode of the User association to EAGER in your Order entity
#ManyToOne(targetEntity="Cart", cascade={"all"}, fetch="EAGER")
By default i think it doesn't fetch the associations unless you call it directly like you did here
dump($myOrder[0]->getUser()->getUsername());
https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref-onetoone
Or this if you use DQL
14.7.6.6. Temporarily change fetch mode in DQL
http://doctrine-orm.readthedocs.io/en/latest/reference/dql-doctrine-query-language.html#temporarily-change-fetch-mode-in-dql
Edit : i was wrong
I made some tests everything worked fine with lazy loading or eager until i tried with groups, even if the fields are exposed you don't use the Default group so it only take the things with the 'statistics' group on it
Try to add the default group here
$serializationContext->setGroups(['Default','statistics']);
Or add the statistics group on your user fields both worked for me

JMS Serializer Config

I am using this in config.yml:
# JMSSerializer Configuration
jms_serializer:
#parameters:
#jms_serializer.camel_case_naming_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy
metadata:
cache: file
debug: "%kernel.debug%"
file_cache:
dir: "%kernel.cache_dir%/serializer"
auto_detection: true
directories:
AppBundle:
namespace_prefix: "AppBundle"
path: "%kernel.root_dir%/config/serializer/AppBundle"
And this in Entity.Category.yml:
AppBundle\Entity\Category:
exclusion_policy: ALL
But when i try to send request, i receive this error:
Expected metadata for class AppBundle\Entity\Category to be defined
in /var/www/test/app/config/serializer/AppBundle/Entity.Category.yml.
How can I solve this issue?
You forgot about TAB at 2 line.
It looks like you are getting an incorrect path to your project files with %kernel.root_dir%. Make sure that /var/www/test/app is the correct path to your project. Check your PHP __DIR__ constant and try replacing `%kernel.root_dir% with what that says as well as what you think the path should be.
Also, instead of defining your exclusion policy in a config file you should just be able to annotate your entity like so and expose things as needed:
use JMS\Serializer\Annotation as JMS;
/**
* Class ExampleEntity
*
* #JMS\ExclusionPolicy("all")
* #ORM\Entity()
*/
class ExampleEntity
{
}
JMS annotations are found here.

Having mapping issues when trying to save monolog logs into Elasticsearch use ElasticsearchHandler

I'm trying to start sending my logs into elastic search using monolog. (I'm using Symfony2).
I've set up monolog like this:
monolog:
handlers:
elasticsearch:
elasticsearch:
host: %logger_elastic_host%
port: %logger_elastic_port%
type: elasticsearch
level: info
It worked only few minutes until it broke with this error messages(a fatal error, I removed useless stuff):
create: /monolog/logs/AVQKYsGRPmEhlo7mDfrN caused
MapperParsingException[failed to parse [context.stack.args]]; nested:
ElasticsearchIllegalArgumentException[unknown property [class]];
I've been looking with my collegue how to fix that. What we found out is:
Elastic search receive the first logs and automatically build a mapping
We send new logs with another mapping or slightly different to what was sent before and it breaks.
In this case it's breaking here: context.stack.args.
The problem is that the context will always be very different.
What we would like is:
is anyone out there using Monolog to log to Elasticsearch
How do you guys manage to avoid this issue. (How can we manage to avoid it)?
thanks guys.
This is happening because ES creates a mapping from the first document. If any document that is inserted after has the same property but with other type/format then ES will throw an error.
A solution is to create a custom monolog formatter and register it:
config.yml:
elasticsearch:
type: elasticsearch
elasticsearch:
host: elasticsearch
ignore_error: true
formatter: my_elasticsearch_formatter
This line will make Monolog\Handler\ElasticSearchHandler ignore any other errors from Ruflin's Elastica package:
ignore_error: true
Then register a service with this name: my_elasticsearch_formatter:
<service id="my_elasticsearch_formatter" class="AppBundle\Services\MyFormatter">
<argument type="string">monolog</argument>
<argument type="string">logs</argument>
</service>
first argument is the index name, second arg is the type.
And the formatter class:
<?php
namespace AppBundle\Services;
use function json_encode;
use Monolog\Formatter\ElasticaFormatter;
use function var_dump;
class MyFormatter extends ElasticaFormatter
{
/**
* #param string $index
* #param string $type
*/
public function __construct($index, $type)
{
parent::__construct($index, $type);
}
/**
* #param array $record
* #return array|\Elastica\Document|mixed|string
*/
public function format(array $record)
{
$record['context'] = json_encode($record['context']);
return parent::format($record);
}
}
The downside of this solution is that it will json_encode the context. You will not be able to filter by inner properties of the context in ES but at least you will not lose important information about your logs.

How to get groups working for JMSSerializerBundle and FOSRestBundle?

I am trying to set up different groups to achieve different types of serialization of my entities depending on the context.
My config looks like this:
My\FooBundle\Entity\Asset:
exclusion_policy: ALL
access_type: public_method
properties:
id:
access_type: property
expose: true
groups: [fnord]
name:
expose: true
path:
expose: true
isInQuarantine:
expose: true
groups: [baz]
I expect that the group having properties should not be exposed unless the group is set.
I am trying to set the group in my controller via:
$view->setSerializationContext(SerializationContext::create()->setGroups(array('fnord')));
Yet there is no effect on what is exposed and what isn't. Even if I do not try to change the SerializationContext, the groups options seems to be always ignored.
I know that my config is working because I can toggle the properties via the expose flag.
Yet what am I doing wrong here?
I know this question is a bit old, but it may help others.
I encountered a similar issue.
This was because I had in my controler (that extends FOSRestControler) a method with multiple calls to
$this->getView()
You have to notice that this method creates a new View object.
That means, if you call multiple getView methods, the context get reset.
Have a look at the following code that worked for my app :
use FOS\RestBundle\Controller\FOSRestController as Controller;
class RestController extends Controller
{
public function getUserAction($username)
{
$view = $this->view();
$view->setSerializationContext(SerializationContext::create()->setGroups(array('Product')));
$user = $this->getDoctrine()->getManager()->getRepository('VendorUserBundle:User')->findOneByUsername($username);
if(!is_object($user))
{
throw $this->createNotFoundException();
}
$view->setData($user);
return $view;
}
}
In Model.User.yml file :
FOS\UserBundle\Model\User:
exclusion_policy: ALL
properties:
username:
expose: true
groups: [fnord]
email:
expose: true
groups: [Product]
enabled:
expose: true
groups: [Product]
roles:
expose: true
groups: [Product]
Gives the following output :
{"email":"guiguiboy#xxx.com","enabled":true,"roles":["ROLE_XXX"]}
I didn't have any cache related problems (dev env used).

Configuring the Translatable Doctrine2 extension with Symfony2 using YAML

In a nutshell
I'm writing a Symfony2 / Doctrine2 app and have installed and configured the Translatable extension provided by StofDoctrineExtensionsBundle using YAML, however no additional translation table(s) are generated and the following exception is thrown when attempting to work with entities that have translatable properties:
No mapping file found named '/var/www/my-project/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/Translation.orm.yml' for class 'Gedmo\Translatable\Entity\Translation'.
In more detail
I'm trying to get the Translatable extension working in my Symfony2 / Doctrine2 application that is provided by the StofDoctrineExtensionsBundle, however most of the available documentation I can find mainly targets the usage of annotations for configuration, but I'm going with YAML because that's how I have configured everything else.
My configuration
I have added the following to my composer.json file and have ran the composer update command: "stof/doctrine-extensions-bundle": "dev-master" and the bundle is registered in my app/AppKernel.php file.
My app/config/config.yml file has the following configuration:
doctrine:
orm:
auto_generate_proxy_classes: %kernel.debug%
auto_mapping: true
mappings:
gedmo_translatable:
type: yml
prefix: Gedmo\Translatable\Entity
dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
alias: GedmoTranslatable
is_bundle: false
stof_doctrine_extensions:
default_locale: en_GB
translation_fallback: true
orm:
default:
timestampable: true
translatable: true
I have then defined an entity in YAML:
Foo\ContentBundle\Entity\Article:
type: entity
repositoryClass: Foo\ContentBundle\Repository\ArticleRepository
table: article
gedmo:
translation:
locale: locale
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
name:
type: string
length: 64
gedmo:
- translatable
content:
type: text
gedmo:
- translatable
# ... #
oneToMany:
# ... #
I have then ran the console command php app/console doctrine:generate:entities FooContentBundle to generate the entity classes, and have manually added the locale property and setter:
class Article
{
/* ... */
private $locale;
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
/* ... */
}
After running php app/console doctrine:schema:update --force, my article table is created along with its associations, but nothing relating to translations (I'm assuming a table is supposed to be created for this...)
Then, when working with an entity that is translatable, I'm getting the exception:
No mapping file found named '/var/www/my-project/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/Translation.orm.yml' for class 'Gedmo\Translatable\Entity\Translation'.
The YAML file that the exception is referencing does not exist in the path that it's looking for it within, neither could I find it anywhere else.
Does anyone have any ideas as to where I'm going wrong?
Update: After further investigation...
Running php app/console doctrine:mapping:info displays all of my entities and nothing relating to translations, however, if I update the gedmo_translatable: part of my app/config/config.yml file and change type: yml to type: annotation then run the command again, I get the following listed:
[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation
[OK] Gedmo\Translatable\Entity\Translation
[OK] Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation
At which point, I can update my schema, and I have a new ext_translations table. However, nothing is being inserted into it when working with my entities, presumably because it's now expecting configuration by annotation rather than YAML, changing my config back to type: yml starts throwing the exception again, as expected.
After trying things that the documentation suggests will not work, i.e. mixing both annotation and YAML configurations in the same bundle, it would appear I have things working. The whole thing feels like a bug or an incomplete implementation, however I may be doing something incorrectly. Here's what's working...
Setting the following in app/config/config.yml: doctrine.orm.mappings.gedmo_translatable.type: annotation
Setting the translatable configuration in my YAML schema definition as outlined in my original question, as well as as an annotation in my class file:
/* ... */
use Gedmo\Mapping\Annotation as Gedmo;
/* ... */
class Article
{
/* ... */
/**
* #Gedmo\Translatable
* #var string $name
*/
private $name;
/**
* #Gedmo\Locale
*/
private $locale;
public function setTranslatableLocale($locale)
{
$this->locale = $locale;
}
/* ... */
}
After doing this, the additional table is created and translations are being inserted into it when persisting the entity.

Resources