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).
Related
I have defined two different entity managers in doctrine.yaml
entity_managers:
EM1:
naming_strategy: doctrine.orm.naming_strategy.underscore
mappings:
App\EM1:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/BC1/Domain/Entity'
prefix: 'BC1\Domain\Entity'
alias: App\EM1
EM2:
naming_strategy: doctrine.orm.naming_strategy.underscore
mappings:
App\EM2:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/BC2/Domain/Entity'
prefix: 'BC2\Domain\Entity'
alias: App\EM2
and I am injecting a Doctrine EntityManagerInterface in my service:
service.yaml
DoctrineRepository:
class: BC\Infrastructure\Persistence\DoctrineRepository
arguments:
- "#Doctrine\\ORM\\EntityManagerInterface"
DoctrineRepository.php
public function __construct(
EntityManagerInterface $client
) {
$this->entityManager = $client;
}
I want to be able to select which Entity Manager previously defined (EM1, EM2) I want to use when using DoctrineRepository. Idealy it would be something like:
$this->entityManager->useEntityManager('EM2');
Do I need to inject another service instead of a Doctrine\ORM\EntityManagerInterface? I have debugged the entity managers load and I have found that it automatically assigns the first one when generating cache:
cache/dev/getDoctrineRepositoryService.php:
return $this->privates['DoctrineRepository'] = new BC\Infrastructure\Persistence\DoctrineRepository(($this->services['doctrine.orm.EM1_entity_manager'] ?? $this->load('getDoctrine_Orm_EM1EntityManagerService.php')));
Any help would be apreciated, thanks.
I think I found another solution. Instead of injecting an EntityManagerInterface, I have injected #Doctrine itself (it injects a Doctrine\Bundle\DoctrineBundle\Registry object), and from that object you can do a $object->getManager($manager) so select the entity manager you want
Since you have two services that implements the same interface you need to help autowiring of Symfony.
Like explained in the docs:
you can create a normal alias from the TransformerInterface interface to Rot13Transformer, and then create a named autowiring alias from a special string containing the interface followed by a variable name matching the one you use when doing the injection
In your case
# the ``App\EM2`` service will be
# injected when an ``Doctrine\ORM\EntityManagerInterface``
# type-hint for a ``$em2Manager`` argument is detected.
Doctrine\ORM\EntityManagerInterface $em2Manager: '#App\EM2'
# If the argument used for injection does not match, but the
# type-hint still matches, the ``Doctrine\ORM\EntityManagerInterface``
# service will be injected.
Doctrine\ORM\EntityManagerInterface: '#App\EM1'
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
I have an application where the users (clients) can activate different modules.
On the search, the user should be able to search a value in the entire index (for the modules he has activated).
The problem is that I also need to boost some field.
Currently I have this.
mapping.yml
indexes:
traveler:
client: default
finder: ~
types:
Country:
mappings:
name: { boost: 10 }
code:
# additional info (irrelevant)
persistence:
driver: orm
model: CoreBundle\Entity\Country
provider: ~
listener: ~
finder: ~
serializer:
groups: [Default, elastica]
Places:
mappings:
name:
address:
type: "object"
properties:
city: ~
region: ~
country: ~
persistence:
driver: orm
model: CoreBundle\Entity\Places
provider: ~
listener: ~
finder: ~
serializer:
groups: [Default, elastica]
And in my service I have this :
$index = $this->get('fos_elastica.finder.traveler');
$query = new \Elastica\Query\QueryString($search);
# if the client has the module activated
foreach ($this->getClient()->getServices() as $service) {
switch ($service->getService()->getTag()) {
case "countries":
$filters->addShould(
new Type('Country')
);
break;
case "places":
$filters->addShould(
new Type('Places')
);
break;
}
}
$query = new \Elastica\Query\Filtered($query, $filters);
// set result limit
$globalQuery = new Query();
$globalQuery->setQuery($query);
$globalQuery->setSize($limit);
// return result
return $index->find($query);
Now, for example, if I search "Germany", the "Country" result should be first in the result set, because I applied a boost to it in the yml mapping.
Instead, the first 5 or 6 results are for "Places" which have in their country address "Germany".
The boost is not applied (I tried with higher values, removing it ... results are not changed).
I found a way where it works, if I change my service like this, but I would prefer that it use the boost property defined in the mapping.
$query = new QueryString($search);
$query->setFields(array(
'_all',
'Country.name^10'
));
Am I doing something wrong ?
Is there another way to do this ?
Thanks !
I use FOSElasticaBundle in my Symfony 2 project. Since today reindexing is resulting in the below error:
index: /app/hotel/1 caused MapperParsingException[failed to parse
[priceFrom]]; nested: NumberFormatException[For input string:
"410.00"];
In my doctrine orm yml the priceFrom field is defined as followed:
priceFrom:
type: decimal
nullable: true
precision: 7
scale: 2
comment: ''
column: price_from
My fos_elastica config looks like this (config.yml):
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
app:
types:
hotel:
mappings:
id: ~
active: ~
priceFrom: { type: integer }
persistence:
driver: orm
model: XXX\XXXBundle\Entity\Hotel
provider: ~
listener:
immediate: ~
finder: ~
The command I use to reindex: php app/console fos:elastica:populate
The above setup has worked until now. I hope someone can point my to the good direction to solve this problem.
Versions:
ruflin/elastica (2.1.0)
friendsofsymfony/elastica-bundle (v3.1.5)
symfony/symfony (v2.6.11)
PS: No other entities in my project are using a priceFrom field.
In mappings, you define PriceFrom as integer but then you pass a decimal.
I haven't tested it but it definitely seems the major candidate as the culprit.
Francesco Abeni is right with answer. If you are already pushed something in ES as integer (or ES defined it as integer) it will generate exception when you will try to save decimal data here.
I always explicitly specify type in mapping like:
id: {"type" : "integer"}
shop_id: {"type" : "integer"}
source: {"type" : "string", "index" : "not_analyzed"}
There I see two ways to solve problem.
index alias and index merge
specify type in mapping; kill index; populate in again
I used second variant on a dev :)
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.