Symfony Serialize doctrine entity - symfony

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.

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

findBy() foreignKey is not working

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,
]);

Symfony Doctrine return empty values

I use Symfony doctrine to set and get data from my MySQL database. I can push new data without any problem but when I try to get them with a findAll for exemple, I get an array with the good length but nothing in.
Here's my controller:
namespace KGN\CoreBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Doctrine\ORM\EntityManagerInterface;
use KGN\CoreBundle\Entity\Appointment;
use KGN\CoreBundle\Entity\Testy;
class AdminController extends Controller
{
public function indexAction()
{
return $this->render('KGNCoreBundle:Admin:index.html.twig');
}
public function aptAction()
{
$rep = $this->getDoctrine()
->getRepository('KGNCoreBundle:Testy');
$testy = $rep->findAll();
// return new Response('This is for show : '. count($testy) );
return new JsonResponse($testy);
}
public function createAction()
{
$em = $this->getDoctrine()->getManager();
$testy = new Testy();
$testy->setTitre('Magnifique');
$testy->setName('Helicoptere');
$em->persist($testy);
$em->flush();
return new Response('This is for create');
}
}
and what I get on my view page
[{},{}]
And it's true that there is 2 elements in my SQL table.
( I have create my entity with php bin/console doctrine:generate:entity without edition stuff in the "Testy" class or rep )
Entity/Testy
namespace KGN\CoreBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Testy
*
* #ORM\Table(name="testy")
* #ORM\Entity(repositoryClass="KGN\CoreBundle\Repository\TestyRepository")
*/
class Testy
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="titre", type="string", length=255)
*/
private $titre;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set titre
*
* #param string $titre
*
* #return Testy
*/
public function setTitre($titre)
{
$this->titre = $titre;
return $this;
}
/**
* Get titre
*
* #return string
*/
public function getTitre()
{
return $this->titre;
}
/**
* Set name
*
* #param string $name
*
* #return Testy
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
}
associed rep
namespace KGN\CoreBundle\Repository;
/**
* TestyRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class TestyRepository extends \Doctrine\ORM\EntityRepository
{
}
Hi The Function findAll Return the correct answer but its return as array of Objects
And JsonResponse can't desplay Object.
to fixe that you have to create a custom function in your repository that return An array exemple
public function getAll() {
$qb = $this->createQueryBuilder('u');
return $qb->getQuery()->getArrayResult();
}
$em = $this->getDoctrine()->getManager();
$records = $em->getRepository("KGNCoreBundle:Testy")->findAll();
Hope its help you

Cannot set form with populated Entity object get The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess

I have created the EntityClass:
<?php
namespace Rota\Bundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\component\OptionsResolver\OptionsResolverIntrerface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* RotaObj
*
* #ORM\Table()
* #ORM\Entity
*/
class RotaMain
{
public function __construct()
{
$this->rotaShifts = new ArrayCollection();
}
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="MyUserId", type="integer")
*/
private $myUserId;
/**
* #var date
*
* #ORM\Column(name="RotaStartDate", type="date")
*/
private $startDate;
/**
* #var date
*
* #ORM\Column(name="RotaReviewDate", type="date")
*/
private $reviewDate;
/**
* #var integer
*
* #ORM\Column(name="RotaRollingWeeks", type="integer")
*/
private $rollingWeeks;
/**
* #var integer
*
* #ORM\Column(name="restDayCount", type="integer")
*/
private $restDayCount;
/**
* #var integer
*
* #ORM\Column(name="totalDayCount", type="integer")
*/
private $totalDayCount;
/**
* #ORM\OneToMany(targetEntity="RotaShift",mappedBy="rotaMain",cascade={"persist"})
*/
protected $rotaShifts;
/**
* #var string
*
* #ORM\Column(name="shiftOrder",type="string",length=4000,nullable=true)
*/
private $shiftOrder;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set myUserId
*
* #param integer $myUserId
* #return RotaObj
*/
public function setMyUserId($myUserId)
{
$this->myUserId = $myUserId;
return $this;
}
/**
* Get myUserId
*
* #return integer
*/
public function getMyUserId()
{
return $this->myUserId;
}
/**
* Set startDate
*
* #param \DateTime $startDate
* #return RotaObj
*/
public function setStartDate($startDate)
{
$this->startDate = $startDate;
return $this;
}
/**
* Get startDate
*
* #return \DateTime
*/
public function getStartDate()
{
return $this->startDate;
}
/**
* Set reviewDate
*
* #param \DateTime $reviewDate
* #return RotaObj
*/
public function setReviewDate($reviewDate)
{
$this->reviewDate = $reviewDate;
return $this;
}
/**
* Get reviewDate
*
* #return \DateTime
*/
public function getReviewDate()
{
return $this->reviewDate;
}
/**
* Set rollingWeeks
*
* #param integer $rollingWeeks
* #return RotaObj
*/
public function setRollingWeeks($rollingWeeks)
{
$this->rollingWeeks = $rollingWeeks;
return $this;
}
/**
* Get rollingWeeks
*
* #return integer
*/
public function getRollingWeeks()
{
return $this->rollingWeeks;
}
/**
* Add rotaShifts
*
* #param \Rota\Bundle\Entity\RotaShift $rotaShifts
* #return RotaMain
*/
public function addRotaShift(\Rota\Bundle\Entity\RotaShift $rotaShift)
{
$this->rotaShifts[] = $rotaShift;
return $this;
}
/**
* Remove rotaShifts
*
* #param \Rota\Bundle\Entity\RotaShift $rotaShifts
*/
public function removeRotaShift(\Rota\Bundle\Entity\RotaShift $rotaShifts)
{
$this->rotaShifts->removeElement($rotaShifts);
}
/**
* Get rotaShifts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getRotaShifts()
{
return $this->rotaShifts;
}
/**
* Set restDayCount
*
* #param integer $restDayCount
* #return RotaMain
*/
public function setRestDayCount($restDayCount)
{
$this->restDayCount = $restDayCount;
return $this;
}
/**
* Get restDayCount
*
* #return integer
*/
public function getRestDayCount()
{
return $this->restDayCount;
}
/**
* Set totalDayCount
*
* #param integer $totalDayCount
* #return RotaMain
*/
public function setTotalDayCount($totalDayCount)
{
$this->totalDayCount = $totalDayCount;
return $this;
}
/**
* Get totalDayCount
*
* #return integer
*/
public function getTotalDayCount()
{
return $this->totalDayCount;
}
/**
* Set shiftOrder
*
* #param string $shiftOrder
* #return RotaMain
*/
public function setShiftOrder($shiftOrder)
{
$this->shiftOrder = $shiftOrder;
return $this;
}
/**
* Get shiftOrder
*
* #return string
*/
public function getShiftOrder()
{
return $this->shiftOrder;
}
}
This class holds collection of:
<?php
namespace Rota\Bundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* RotaShift
*
* #ORM\Table()
* #ORM\Entity
*/
class RotaShift
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $_id;
/**
* #var integer
*
* #ORM\Column(name="startTime", type="integer")
*/
private $_startTime;
/**
* #var integer
*
* #ORM\Column(name="endTime", type="integer")
*/
private $endTime;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=50)
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="RotaMain", inversedBy="rotaShifts")
*/
private $rotaMain;
/**
* Get _id
*
* #return integer
*/
public function getId()
{
return $this->_id;
}
/**
* Set _startTime
*
* #param integer $startTime
* #return RotaShift
*/
public function setStartTime($startTime)
{
$this->_startTime = $startTime;
return $this;
}
/**
* Get _startTime
*
* #return integer
*/
public function getStartTime()
{
return $this->_startTime;
}
/**
* Set endTime
*
* #param integer $endTime
* #return RotaShift
*/
public function setEndTime($endTime)
{
$this->endTime = $endTime;
return $this;
}
/**
* Get endTime
*
* #return integer
*/
public function getEndTime()
{
return $this->endTime;
}
/**
* Set name
*
* #param string $name
* #return RotaShift
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set rotaMain
*
* #param \Rota\Bundle\Entity\RotaMain $rotaMain
* #return RotaShift
*/
public function setRotaMain(\Rota\Bundle\Entity\RotaMain $rotaMain = null)
{
$this->rotaMain = $rotaMain;
return $this;
}
/**
* Get rotaMain
*
* #return \Rota\Bundle\Entity\RotaMain
*/
public function getRotaMain()
{
return $this->rotaMain;
}
}
I have then created a Form EntityType class for the RotaMain object as follows:
<?php
namespace Rota\Bundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class RotaMainType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder-> add('ReviewDate','date');
$builder->add('RollingWeeks','integer');
$builder->add('StartDate','date');
$builder->add('RestDayCount','integer',array('label' => 'Number of rest days'));
$builder->add('TotalDayCount','integer',array('label' => 'Total number of days in shift pattern'));
$builder->add('rotaShifts','collection',array('type'=> new RotaShiftType(),'label' => false,'allow_add' => true,));
$builder->add('Save','submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Rota\Bundle\Entity\RotaMain',
));
}
public function getName()
{
return 'rotaMain';
}
}
When I try to set a form with a fully populated RotaMain object:
$form = $this->createForm(new RotaMainType(),$RotaMain);
I get the following error:
The form's view data is expected to be of type scalar, array or an instance of
\ArrayAccess, but is an instance of class Rota\Bundle\Entity\RotaMain. You can avoid
this error by setting the "data_class" option to "Rota\Bundle\Entity\RotaMain" or by
adding a view transformer that transforms an instance of class
Rota\Bundle\Entity\RotaMain to scalar, array or an instance of \ArrayAccess.
I have set the data_class in the RotaMainType object so am not sure where I am going wrong? If I pass an empty RotaMain object to the form it builds as expected.
The population of RotaMain happens in the controller. The form is part one of two part process. If user has completed first part gone away and come back I want reutnr the first part fo them to review before going onto the second part of the process. Controller action:
public function setRotaAction(Request $request,$userId)
{
//Check to see if user has part set up a rota - return completed form for review
$RotaMainRepos = $this->getDoctrine()->getManager()->getRepository("RotaBundle:RotaMain");
$id = $this->getUser()->getID();
$criteria = array("myUserId"=>$id);
$result = $RotaMainRepos->findBy($criteria);
if($result == null)
{
$RotaMain = new RotaMain();
$RotaMain->setmyUserId($userId);
$form = $this->createForm(new RotaMainType(),$RotaMain);
}
else
{
$RotaMain = $result[0];
$rotashiftRepo = $this->getDoctrine()->getManager()->getRepository("RotaBundle:RotaShift");
$rotaShifts = $rotashiftRepo->findByRotaMain($RotaMain);
foreach($rotaShifts as $rotaShift)
{
$RotaMain->addRotaShift($rotaShift);
}
$form = $this->createForm(new RotaMainType(),$RotaMain);
}
$form->handleRequest($request);
if($form->isValid())
{
$early = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($early);
$shifts = $early->getRotaShifts();
foreach($shifts as $shift)
{
$shift->setRotaMain($early);
$em->persist($shift);
}
$em->flush();
$shiftOrder = new ShiftOrder($shifts,$early->getRestDayCount(),$early->getTotalDayCount());
return $this->render("RotaBundle:Default:shiftOrder.html.twig",array("shiftOrder" => $shiftOrder));
}
return $this->render('RotaBundle:Default:setRota.html.twig',array("form" => $form->createView(),));
}
You have to bind a newly created or existing entity/object of the same type as the configured data_class to your form.
If you don't set the variable you're passing to your form to an object of the expected data_class symfony won't create the object but throw this exception.
In your case you might want to use a SensioFrameworkExtraBundle's #ParamConverter to fetch your entity from database and have your controller cleaned up.
/**
* #Route("/whatever/{id}")
* #ParamConverter("rotaMain", class="RotaBundle:RotaMain", options={"mapping": {"MyUserId": "id"}})
*/
public function editAction(RotaMain $rotaMain, Request $request)
{
$form = $this->createForm(new RotaMainType(), $rotaMain);
$form->handleRequest($request);
if ($form->isValid()) {
//
}
}
... or ...
public function newAction(Request $request)
{
$form = $this->createForm(new RotaMainType(), $rotaMain = new RotaMain());
$form->handleRequest($request);
if ($form->isValid()) {
//
}
}
Found the answer to this - it was the way I was accessing and setting MyRotaShift entities in RotaMain. My addRotashift() function was not correctly adding rotaShifts to the Doctrine ArrayColleciton. On changing my controller code to:
foreach($rotaShifts as $rotaShift)
{
$RotaMain->getRotaShifts()->add($rotaShift);
}
it all works. Thought I was going mad for a while!!!
Turns out not mad but I should have read the Doctrine docs before pushing ahead. If I had I would have realized that is uses Lazy loading and saved myself a load of bother!!!
Have accepted nifr's answer as it provides a good way to do what I was trying to accomplish

Symfony 2 - Retrieve Entity with Json, return another Entity

I have a problem while json_encodeing a Entity.
public function jsonvoteAction($id) {
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('KorumAGBundle:AGVote')->findOneById($id);
$response = new Response(json_encode($entity, 200));
$response->headers->set('Content-Type',' application/json');
return $response;
}
This code returns me a the users entity
{"users":{"__isInitialized__":false,"id":null,"nickname":null,"pwd":null,"email":null,"firstname":null,"lastname":null,"poste":null,"addr1":null,"addr2":null,"pc":null,"country":null,"phone":null,"province":null,"acess":null,"site":null,"crew":null,"utilisateur":null}}
And when I var dymp my $entity, it returns both my AGVote and USers entity.
Here is my AGVote Entity
<?php
namespace Korum\AGBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Korum\AGBundle\Entity\AGVote
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class AGVote
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $question;
/**
* #ORM\Column(type="smallint")
*/
private $actif;
/**
* #ORM\ManyToOne(targetEntity="\Korum\KBundle\Entity\Users", cascade={"all"})
*/
public $users;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set question
* Nb : Only AG admin can set a question
* #param text $question
*/
public function setQuestion($question)
{
$this->question = $question;
}
/**
* Get question
*
* #return text
*/
public function getquestion()
{
return $this->question;
}
/**
* Set actif
*
* #param smallint $actif
*/
public function setActif($actif)
{
$this->actif = $actif;
}
/**
* Get actif
*
* #return smallint
*/
public function getActif()
{
return $this->actif;
}
/**
* Set Users
*
* #param Korum\KBundle\Entity\Province $Users
*/
public function setUsers(\Korum\KBundle\Entity\Users $users)
{
$this->users = $users;
}
/**
* Get Users
*
* #return Korum\KBundle\Entity\Users
*/
public function getUsers()
{
return $this->users;
}
}
Does anyone have an idea of what happened ?
I tried to install the JSMSerializerBundle but event with Metadata library at version 1.1.
When I want to clear my cache, it failed with error :
See :
JMSSerializerBundle Installation : Catchable Fatal Error: Argument 1 passed to JMSSerializerBundle\Twig\SerializerExtension::__construct()
By default, json_encode only uses public properties.
So it serialized the only public property of AGVote: $users. The content of $users was an instance of User; which public fields were serialized.
You could work around these by adding a toArray() method to your entities, and then doing json_encode($entity->toArray()), but i highly recommend you to have a look and use the JMSSerializedBundle.

Resources