findBy() foreignKey is not working - symfony

There is a relationship between the rubric and brand table (Many rubric to One brand).
Here is my code
$dbChoices = $this->getConfigurationPool()
->getContainer()
->get('Doctrine')
->getManager()
->getRepository('RibambelMainBundle:RubricMenu')
->findBy(array('brand_id' => 2));
Everytime this part is run, I got the following error:
Unrecognized field: brand_id
The brand_id column is found in the rubric table.
Anyone who can help me with this or show me another way of doing it?
class RubricMenu
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Title", type="string", length=255)
*/
private $title;
/**
* #var int
*
* #ORM\Column(name="position", type="integer")
*/
private $position;
/**
* #ORM\ManyToOne(targetEntity="Brand")
* #ORM\JoinColumn(name="brand_id", nullable=false)
*/
private $brand;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $title
*
* #return RubricMenu
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set position
*
* #param integer $position
*
* #return RubricMenu
*/
public function setPosition($position)
{
$this->position = $position;
return $this;
}
/**
* Get position
*
* #return int
*/
public function getPosition()
{
return $this->position;
}
/**
* Set brand
*
* #param \Ribambel\MainBundle\Entity\Brand $brand
*
* #return RubricMenu
*/
public function setBrand(\Ribambel\MainBundle\Entity\Brand $brand = null)
{
$this->brand = $brand;
return $this;
}
/**
* Get brand
*
* #return \Ribambel\MainBundle\Entity\Brand
*/
public function getBrand()
{
return $this->brand;
}
}

Searching by a foreign key simply does not make sense from an object point of view. brand_id is not a field of your RubricMenu entity, brand is.
If you have a Brand entity, then you can use findBy (or the magic method findByBrand) like this: (with $myBrand an instance of Brand)
$repository->findBy(['brand' => $myBrand]);
// OR
$repository->findByBrand($myBrand);
If you simply have the id of your target entity, you can use the IDENTITY DQL function but in that case you cannot use findBy directly as it expects a valid field name. Thus, you will need to add a method in your RubricMenu repository. Your method could look like this:
public function findByBrandId($brandId)
{
$qb = $this->createQueryBuilder('rm');
$qb->where('IDENTITY(rm.brand) = :brandId')
->setParameter('brandId', $brandId);
return $qb->getQuery()->getResult();
}
On a side note, as pointed out by #l.g.karolos's answer, doing
$repository->findBy(['brand' => $brandId]);
// OR
$repository->findByBrand($brandId);
will also work as the findBy method internals will be able to resolve that the given parameter is an ID of a Brand entity, thus it will produce the same query as if you had given the corresponding Brand instance.

Based on your entity you should do the following.
$dbChoices = $this->getConfigurationPool()
->getContainer()
->get('Doctrine')
->getManager()
->getRepository('RibambelMainBundle:RubricMenu')
->findBy(array('brand' => 2));

i thing you can do:
$dbChoices = $this->getConfigurationPool()
->getContainer()
->get('Doctrine')
->getManager()
->getRepository('RibambelMainBundle:RubricMenu')
->findBy(array('brand' => $brand));
if you have $brand object (...\Entity\Brand)
Example on https://www.wanadev.fr/56-comment-realiser-de-belles-requetes-sql-avec-doctrine/ :
$user = …;
$category = …;
$em = $this->container->get("doctrine.orm.default_entity_manager");
$entities = $em->getRepository(MyClass::class)->findBy([
"user" => $user,
"category" => $category,
]);

Related

Symfony rest api

I'm developing a rest api application with symfony in backend.
My problem is that when I try to lauch a GET request, the application runs without giving any response even after even after some ten minutes.
this is the request method:
/**
* CounterRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class CounterRepository extends \Doctrine\ORM\EntityRepository
{
/**
* #param string $name
* #param int $date
* #return mixed
* #throws \Exception
*/
public function getValuesByNameAndDate(string $name, int $date)
{
$query = $this
->createQueryBuilder('c')
->leftJoin('c.values', 'v', 'WITH')
->addSelect('v')
->where('c.name = :name')
->andWhere('v.date = :date')
->setParameters(
array(
'date' => $date,
'name' => $name
)
)
->getQuery();
return $query->getResult();
}
}
The CounterValue Entity:
/**
* CounterValue
*
* #ORM\Table(name="counter_value")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CounterValueRepository")
*/
class CounterValue
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var float
*
* #ORM\Column(name="value", type="float")
*/
private $value;
/**
* #var int
*
* #ORM\Column(name="date", type="integer")
*/
private $date;
/**
* #var Counter
*
* #ORM\ManyToOne(targetEntity="Counter", inversedBy="values")
* #ORM\JoinColumn()
*/
private $counter;
/**
* #var City
*
* #ORM\ManyToOne(targetEntity="City", inversedBy="values"))
* #ORM\JoinColumn()
*/
protected $city;
public function __construct()
{
$date = new \DateTime('-1 day');
$this->date = strtotime($date->format('d-m-Y'));
}
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set value.
*
* #param float $value
*
* #return CounterValue
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* Get value.
*
* #return float
*/
public function getValue()
{
return $this->value;
}
/**
* Set date.
*
* #param int $date
*
* #return CounterValue
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date.
*
* #return int
*/
public function getDate()
{
return $this->date;
}
/**
* #return Counter
*/
public function getCounter(): Counter
{
return $this->counter;
}
/**
* #param Counter $counter
*/
public function setCounter(Counter $counter): void
{
$this->counter = $counter;
}
/**
* #return City
*/
public function getCity(): City
{
return $this->city;
}
/**
* #param City $city
*/
public function setCity(City $city): void
{
$this->city = $city;
}
}
/**
* Counter
*
* #ORM\Table(name="counter")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CounterRepository")
*/
class Counter
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=false)
*/
private $name;
/**
* #var XmlFile
*
* #ORM\ManyToOne(targetEntity="XmlFile", inversedBy="counters", cascade={"remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $xmlFile;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="CounterValue", mappedBy="counter", cascade={"persist"})
*/
private $values;
public function __construct()
{
$this->values = new ArrayCollection();
}
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name.
*
* #param string $name
*
* #return Counter
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name.
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set xmlFile
*
* #param XmlFile $xmlFile
*/
public function setXmlFile(XmlFile $xmlFile)
{
$this->xmlFile = $xmlFile;
}
/**
* Get xmlFile
*
* #return XmlFile
*/
public function getXmlFile(): XmlFile
{
return $this->xmlFile;
}
/**
* #return ArrayCollection
*/
public function getValues(): ArrayCollection
{
return $this->values;
}
/**
* #param ArrayCollection $values
*/
public function setValues(ArrayCollection $values): void
{
$this->values = $values;
}
/**
* Add $value
*
* #param CounterValue $value
*/
public function addValue(CounterValue $value)
{
$value->setCounter($this);
if(!$this->values->contains($value)){
$this->values->add($value);
}
}
}
And finally my method in controller
$em = $this->get('doctrine.orm.entity_manager');
$counterRep = $em->getRepository('AppBundle:Counter');
return $counterRep->getValuesByNameAndDate('L.IRATHO.E2G.CSFB.ExecSuccOut', 1533600000);
Just return a Json response like this.
public function listAction(Request $request)
{
try
{
$em = $this->get('doctrine.orm.entity_manager');
$counterRep = $em->getRepository('AppBundle:Counter')->getValuesByNameAndDate('L.IRATHO.E2G.CSFB.ExecSuccOut', 1533600000);
return new JsonResponse(['success' => true, 'code' => Response::HTTP_OK, 'data' => $counterRep]);
}
catch (\Exception $exception)
{
return new JsonResponse(['success' => false,'code' => $exception->getCode() ,'message' => $exception->getMessage()]);
}
}
Controller action should return instance of
Symfony\Component\HttpFoundation\Response
You try to return result of query builder $query->getResult()
You need to change it to something like
public function counterValuesAction(Request $request) {
try {
$em = $this->get('doctrine.orm.entity_manager');
$counterRep = $em->getRepository('AppBundle:Counter');
$values = $counterRep->getValuesByNameAndDate('L.IRATHO.E2G.CSFB.ExecSuccOut', 1533600000);
} catch (\Exception $e) {
return new Response($values);
}
}
Solution for Symfony 4+:
<?php
namespace App\Controller;
class CounterController extends AbstractController
{
public function listAction(
CounterRepository $repository // DI works like this in Controllers...
) {
$result = $repository->getValuesByNameAndDate('L.IRATHO.E2G.CSFB.ExecSuccOut', 1533600000);
// use JsonResponse object to create JSON response
return $this->json($result, Response::HTTP_OK);
}
}
// routes.yaml
counter_list:
path: /counter
controller: App\Controller\CounterController::listAction
methods: GET
Clear cache and try to send GET request to http://your-dev-host/counter
How does it work?
Controller
You need to create controller CounterController class with action function listAction. It is good practice to add Action postfix to action function.
You can define services or other DI objects as parameters in action functions. DI will set it. For example:
class MyController extends AbstractController
{
public function listAction(
Request $request,
SerializerInterface $serializer,
ValidatorInterface $validator,
CounterRepository $repository
) {
// ...
}
}
In order to send good response with JSON and all headers that is needed you need to use AbstractController::json function. It creates JsonResponse object. You can check it implementation.
More information about symfony controllers you can find in this article https://symfony.com/doc/current/controller.html
Routing
Next step is to create route for your new controller action. You can do it in 2 ways:
Adding record to config/routes.yaml file as i did
Use annotations (Annotations is bad practice because comments should not break programm)
More information about routing you can find in this article https://symfony.com/doc/current/routing.html
It does not work for me! How can I debug it?
First, dont panic and read error message. Also, you can check if routing works well. You can do it using command
$ bin/console debug:router
----------------------- -------- -------- ------ -------------------------------------
Name Method Scheme Host Path
----------------------- -------- -------- ------ -------------------------------------
_preview_error ANY ANY ANY /_error/{code}.{_format}
register_token POST ANY ANY /auth/register
refresh_token POST ANY ANY /auth/refresh
auth_login POST ANY ANY /auth/login
restroom_list GET ANY ANY /api/v1/restroom
----------------------- -------- -------- ------ -------------------------------------
In table you need to check your new url and how Symfony sees it.
Second, try to send request to this URL using curl and check response.
$ curl http://localhost/auth/login

Symfony Serialize doctrine entity

I have a simple entity class:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="CompanyUserRepository")
* #ORM\Table(name="company_users")
*/
class CompanyUser
{
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $firstName;
/**
* #ORM\Column(type="string", length=100)
*/
private $lastName ;
/**
* #ORM\OneToMany(targetEntity="Score", mappedBy="user")
*/
private $scores;
/**
* Constructor
*/
public function __construct()
{
$this->scores = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set firstName
*
* #param string $firstName
*
* #return CompanyUser
*/
public function setFirstName($firstName)
{
$this->firstName = $firstName;
return $this;
}
/**
* Get firstName
*
* #return string
*/
public function getFirstName()
{
return $this->firstName;
}
/**
* Set lastName
*
* #param string $lastName
*
* #return CompanyUser
*/
public function setLastName($lastName)
{
$this->lastName = $lastName;
return $this;
}
/**
* Get lastName
*
* #return string
*/
public function getLastName()
{
return $this->lastName;
}
/**
* Add score
*
* #param \AppBundle\Entity\Score $score
*
* #return CompanyUser
*/
public function addScore(\AppBundle\Entity\Score $score)
{
$this->scores[] = $score;
return $this;
}
/**
* Remove score
*
* #param \AppBundle\Entity\Score $score
*/
public function removeScore(\AppBundle\Entity\Score $score)
{
$this->scores->removeElement($score);
}
/**
* Get scores
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getScores()
{
return $this->scores;
}
}
The problem comes when I try to get all users and serialize them in json:
/**
* #Route("/api/getUsers", name="getUsers")
*/
public function getUsers(Request $request){
$users = $this->getDoctrine()
->getRepository('AppBundle:CompanyUser')
->findAll();
$serializer = $this->get('serializer');
$data = $serializer->serialize($users, 'json');
return new Response($users);
}
I get A circular reference has been detected (configured limit: 1).
When I remove the getScores getter everything works fine. I need to get only the id, firstName and lastName. Is there a way to not serialize the other objects?
Well, it is a common thing to handle with circular references when serializing entities with relations.
Solution no. 1: Implements serializable interface and make relations attributes are not serialize/unserialize (most cases, it is a valid solution)
Solution no. 2: The setCircularReferenceLimit() method of this normalizer sets the number of times it will serialize the same object before considering it a circular reference. Its default value is 1. So, before calling serialize() method, do this:
public function getUsers(Request $request){
$users = $this->getDoctrine()
->getRepository('AppBundle:CompanyUser')
->findAll();
$serializer = $this->get('serializer');
$serializer->setCircularReferenceLimit(2); // Change this with a proper value for your case
$data = $serializer->serialize($users, 'json');
return new Response($data);
}
**** UPDATE ****
As #Derek says in his comment, solution no. 2 can be invalid in some versions of Symfony. Then you can try to set a handler for circular references this way:
$encoder = new JsonEncoder();
$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getName(); // Change this to a valid method of your object
});
$serializer = new Serializer(array($normalizer), array($encoder));
var_dump($serializer->serialize($org, 'json'));
This should return your entity value instead to iterate over relations.

Doctrine returns many-to-many collection in incorrect order

I'm starting to struggle with finding a solution for this online/offline so maybe someone has an answer or suggestion of best approach.
The problem is that a Question entity has a many-to-many relation tags which should return Tag entities in alphabetical order. The generated SQL is correct, but the collection which is returned doesn't follow the order.
I'm starting to lean towards using:
a) lifecycle events to call a method which will sort the tags collection.
b) on getTags() method call a method which will check if collection was sorted (for performance to avoid multiple sorts) and then sort the collection if it's the first time.
Does anyone know why collection is not sorted or which solution will be best?
Some info of code:
Generated SQL
SELECT
q0_.id AS id0,
q0_.question AS question1,
t1_.id AS id2,
t1_.name AS name3
FROM question q0_
LEFT JOIN questions_tags q2_ ON q0_.id = q2_.question_id
LEFT JOIN tag t1_ ON t1_.id = q2_.tag_id
ORDER BY
q0_.question ASC,
t1_.name ASC
Available data
INSERT INTO `question` (`id`,`question`) VALUES (1,'Who are you?');
INSERT INTO `questions_tags` (`question_id`,`tag_id`) VALUES (1,1);
INSERT INTO `questions_tags` (`question_id`,`tag_id`) VALUES (1,2);
INSERT INTO `questions_tags` (`question_id`,`tag_id`) VALUES (1,3);
INSERT INTO `tag` (`id`,`name`) VALUES (1,'personal');
INSERT INTO `tag` (`id`,`name`) VALUES (2,'jobs');
INSERT INTO `tag` (`id`,`name`) VALUES (3,'achievements');
Partial dump of getQuestions() method
Doctrine\ORM\PersistentCollection {#3131
-owner: AppBundle\Entity\Question {#3118
-id: 1
-question: "Who are you?"
-tags: Doctrine\ORM\PersistentCollection {#3131}
}
-coll: Doctrine\Common\Collections\ArrayCollection {#3127
-_elements: array:3 [
0 => AppBundle\Entity\Tag {#3121
-id: 1
-name: "personal"
}
1 => AppBundle\Entity\Tag {#3123
-id: 2
-name: "jobs"
}
2 => AppBundle\Entity\Tag {#3074
-id: 3
-name: "achievements"
}
]
}
}
Question entity
<?php
namespace AppBundle\Entity;
use AppBundle\Entity\Tag;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Question
*
* #ORM\Table(name="question")
* #ORM\Entity(repositoryClass="AppBundle\Entity\QuestionRepository")
*/
class Question
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="question", type="text")
*/
private $question;
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Tag", inversedBy="questions", cascade={"persist"})
* #ORM\JoinTable(name="questions_tags")
* #ORM\OrderBy({"name"="ASC"})
*/
private $tags;
public function __construct()
{
$this->tags = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set question
*
* #param string $question
* #return Question
*/
public function setQuestion($question)
{
$this->question = $question;
return $this;
}
/**
* Get question
*
* #return string
*/
public function getQuestion()
{
return $this->question;
}
/**
* Add tags
*
* #param \AppBundle\Entity\Tag $tags
* #return Question
*/
public function addTag(Tag $tags)
{
$this->tags[] = $tags;
return $this;
}
/**
* Remove tags
*
* #param \AppBundle\Entity\Tag $tags
*/
public function removeTag(Tag $tags)
{
$this->tags->removeElement($tags);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
}
Tag entity
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Tag
*
* #ORM\Table(name="tag")
* #ORM\Entity(repositoryClass="AppBundle\Entity\TagRepository")
*/
class Tag
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=128)
*/
private $name;
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Question", mappedBy="tags")
*/
private $questions;
public function __construct()
{
$this->questions = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Tag
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Add questions
*
* #param \AppBundle\Entity\Question $questions
* #return Tag
*/
public function addQuestion(\AppBundle\Entity\Question $questions)
{
$this->questions[] = $questions;
return $this;
}
/**
* Remove questions
*
* #param \AppBundle\Entity\Question $questions
*/
public function removeQuestion(\AppBundle\Entity\Question $questions)
{
$this->questions->removeElement($questions);
}
/**
* Get questions
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getQuestions()
{
return $this->questions;
}
public function __toString()
{
return $this->name;
}
}
QuestionRepository
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\EntityRepository;
class QuestionRepository extends EntityRepository
{
/** #return Question[] */
public function getQuestions()
{
return $this->createQueryBuilder('q')
->select(['q', 't'])
->leftJoin('q.tags', 't')
->orderBy('q.question', 'ASC')
->getQuery()
->execute()
;
}
}
EDIT 2015-03-27:
For the time being I chose to extend the question entity with sort method:
<?php
// ...
class Question
{
// ...
/** #var boolean a flag to check if tags collection was sorted */
private $isTagsSorted = false;
// ...
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
$this->sortTagsAlphabetically();
return $this->tags;
}
/** #return void */
private function sortTagsAlphabetically()
{
if ($this->isTagsSorted) {
return;
}
$tags = $this->tags->toArray();
usort($tags, function ($a, $b) {
return $a->getName() > $b->getName();
});
$this->tags = new ArrayCollection($tags);
}
}
You need a subquery to achieve this, because the order by affect the main query so obviously it will try to order first by question it does it and then try to order the questions by tag (not the tags). So something like this should do it :
SELECT
q0_.id AS id0,
q0_.question AS question1,
t1_.id AS id2,
t1_.name AS name3
FROM question q0_
LEFT JOIN questions_tags q2_ ON q0_.id = q2_.question_id
LEFT JOIN (select * from tag t1_ ORDER BY t1_.name ) t1_
ON t1_.id = q2_.tag_id
ORDER BY
q0_.question ASC,
t1_.name ASC
For the DQL i am sorry but i think you will have to do it the old fashion way NativeSql since doctrine doesnt support joining subqueries with dql :
https://groups.google.com/forum/#!msg/doctrine-user/0rNbXlD0E_8/xMNiQgp9c3QJ
But nativesql would be fine :) also :
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html
Just use the query i gave you, change it a bit to be readable then use :
$sql = "your query"
$connection = $this->getEntityManager()->getConnection();
$query = $connection->prepare($sql);
$query->execute();
$results = $query->fetchAll();
return $results;
The annotation of ordering is used only if the content is not already fetched, as example if you have fetch from the dm only the .. if you call the get.. method the result is sorted.
In your case, you get all the data in one shot, so the annotation doesn't work as expected.
In your case you can add a mehod in the Tag entity for sort the data on the fly, as example:
public function getSortedTags()
{
$criteria = Criteria::create()
->orderBy(array("name" => Criteria::ASC));
return $this->tags->matching($criteria);
}
Hope this help

Symfony 2 - findall() too many DB queries

why Symfony2 performs 40 DB queries if I use following code:
$em = $this->getDoctrine()->getManager();
$records = $em->getRepository('MyWebBundle:Highlight')->findAll();
I thought that findAll() method returns only all items from Highlight entity and associations to other entities replaces Proxy objects. But now findAll() method gettings all associations entities.
Do you know where is the problem ?
indexAction
public function indexAction() {
$em = $this->getDoctrine()->getManager();
$records = $em->getRepository('MyWebBundle:Highlight')->findAll();
$csrf = $this->get('security.csrf.token_manager');
$token = $csrf->refreshToken(self::FORM_TOKEN_ID);
$params = array(
"data" => array(
"all" => $records,
),
"token" => $token->getValue(),
"static" => array(
"add" => $this->generateUrl("admin_highlight_add"),
"edit" => $this->generateUrl("admin_highlight_edit"),
"del" => $this->generateUrl("admin_highlight_del"),
),
);
$ser = $this->get('jms_serializer');
$jsonContent = $ser->serialize($params, 'json');
return array('jsonContent' => $jsonContent);
}
Highlight entity
namespace My\WebBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;
/**
* Highlight
*
* #JMS\ExclusionPolicy("none")
* #ORM\Table()
* #ORM\Entity(repositoryClass="My\WebBundle\Entity\HighlightRepository")
*/
class Highlight {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="abbreviation", type="string", length=8, unique=true)
*/
private $abbreviation;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=80, nullable=true)
*/
private $description;
/**
* #var string
*
* #ORM\Column(name="color", type="string", length=7)
*/
private $color;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="Goods", mappedBy="highlight")
*/
private $goods;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="Calibration", mappedBy="highlight")
*/
private $calibrations;
/**
* Constructor
*/
public function __construct() {
$this->goods = new \Doctrine\Common\Collections\ArrayCollection();
$this->calibrations = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId() {
return $this->id;
}
/**
* Set abbreviation
*
* #param string $abbreviation
* #return Highlight
*/
public function setAbbreviation($abbreviation) {
$this->abbreviation = $abbreviation;
return $this;
}
/**
* Get abbreviation
*
* #return string
*/
public function getAbbreviation() {
return $this->abbreviation;
}
/**
* Set description
*
* #param string $description
* #return Highlight
*/
public function setDescription($description) {
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription() {
return $this->description;
}
/**
* Set color
*
* #param string $color
* #return Highlight
*/
public function setColor($color) {
$this->color = $color;
return $this;
}
/**
* Get color
*
* #return string
*/
public function getColor() {
return $this->color;
}
/**
* Add goods
*
* #param \My\WebBundle\Entity\Goods $goods
* #return Highlight
*/
public function addGood(\My\WebBundle\Entity\Goods $goods) {
$this->goods[] = $goods;
return $this;
}
/**
* Remove goods
*
* #param \My\WebBundle\Entity\Goods $goods
*/
public function removeGood(\My\WebBundle\Entity\Goods $goods) {
$this->goods->removeElement($goods);
}
/**
* Get goods
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getGoods() {
return $this->goods;
}
/**
* Add calibrations
*
* #param \My\WebBundle\Entity\Calibration $calibrations
* #return Highlight
*/
public function addCalibration(\My\WebBundle\Entity\Calibration $calibrations) {
$this->calibrations[] = $calibrations;
return $this;
}
/**
* Remove calibrations
*
* #param \My\WebBundle\Entity\Calibration $calibrations
*/
public function removeCalibration(\My\WebBundle\Entity\Calibration $calibrations) {
$this->calibrations->removeElement($calibrations);
}
/**
* Get calibrations
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCalibrations() {
return $this->calibrations;
}
}
Highlight repository is empty
I think the problem comes from the serializer. Since you serializer highliths, each of them has their properties serialized as well which means that lazy query will be performed to retieved Goods which will be also serialized.
You should then prevent this behaviour by adding annotations to highlight's goods property as this
use ...
use JMS\SerializerBundle\Annotation\ExclusionPolicy;
use JMS\SerializerBundle\Annotation\Exclude;
/**
* ...
* #ExclusionPolicy("none")
*/
class Highlight
{
/**
* ...
* #Exclude
*/
private $goods;
}
You can have further details about exclusion stratigies from JMSSerializer doc
findAll itself does not perform many queries. Queries are executed when you access related entity via getters. As relation are not fetched eagerly, they first time are fetched when you are acessing them.
I think serializer access all children to send your object.
See Doctrine documentation
Whenever you have a managed entity instance at hand, you can traverse
and use any associations of that entity that are configured LAZY as if
they were in-memory already. Doctrine will automatically load the
associated objects on demand through the concept of lazy-loading.
To prevent this either disable children serialization or use fetch EAGER or build a DQL query, which prefetch all the children alongside with parents, like (just sample, not valid DQL)
SELECT Highlight, Good, Calibration
FROM Highlights Highlight
LEFT JOIN Highlight.googs Good
LEFT JOIN Goog.calibrations Calibration
WHERE ...

How to customise form rendering when based on entity field in symfony 2?

I have created a form based on an entity field. This form is composed of checkboxes that allow user to choose an entity (here 'car').
This works fine but I need to customize the rendering to get extra informations. Currently, the only information that is displayed is the 'id' attribute.
In my case, I would like to display extra entity informations in the form such as color, brand etc ...
Does anyone know how to proceed ?
The controller :
public function chooserAction() {
//symfony.com/doc/current/reference/forms/types/entity.html
$cars = $this->getDoctrine()
->getRepository('CarBundle:Car')
->find(1);
$formBuilder = $this->createFormBuilder();
/*
foreach ($cars as $car) {
$formBuilder->add($car->getId() ,'checkbox')->getForm();
}
*/
$formBuilder->add('cars', 'entity', array(
'class' => 'CarBundle:Car',
'property' => 'id',
'expanded' => 'true',
'multiple' => 'true',
));
$formBuilder->add('save', 'submit');
$form = $formBuilder->getForm();
$request = $this->get('request');
$form->handleRequest($request);
if ($form->isValid()) {
echo "ok";
// return $this->redirect($this->generateUrl('car_show', array('id' => $car->getId())));
}
return $this->render('CarBundle:Car:chooser.html.twig', array('form' => $form->createView()));
}
The entity :
<?php
namespace Foobar\CarBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Car
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Foobar\CarBundle\Entity\CarRepository")
*/
class Car
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="brand", type="string", length=255)
*/
private $brand;
/**
* #var string
*
* #ORM\Column(name="color", type="string", length=255)
*/
private $color;
/**
* #var integer
*
* #ORM\Column(name="power", type="integer")
*/
private $power;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Car
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set brand
*
* #param string $brand
* #return Car
*/
public function setBrand($brand)
{
$this->brand = $brand;
return $this;
}
/**
* Get brand
*
* #return string
*/
public function getBrand()
{
return $this->brand;
}
/**
* Set color
*
* #param string $color
* #return Car
*/
public function setColor($color)
{
$this->color = $color;
return $this;
}
/**
* Get color
*
* #return string
*/
public function getColor()
{
return $this->color;
}
/**
* Set power
*
* #param integer $power
* #return Car
*/
public function setPower($power)
{
$this->power = $power;
return $this;
}
/**
* Get power
*
* #return integer
*/
public function getPower()
{
return $this->power;
}
}
The view :
car chooser
{{ form(form) }}
You could create a toString() method in your Car entity.
public function __toString()
{
return '' . $this->getName();
}
If you want more thinks like pictures you could follow that http://symfony.com/doc/current/cookbook/form/form_customization.html

Resources