I'm working on a Symfony2 project using Doctrine.
I created a function to retrieve stocks items.
It works well if my database contains less than 50 000 rows.
However, my project needs to deal with more than 2 000 000 rows and If I use the following request, It needs more than 1 minutes to display my page.
Repository (StockRepository.php) :
public function findAllQuery() {
$query = $this->createQueryBuilder('s')
->select(array('s','st','p'))
->join('s.store','st')
->join('s.product','p')
->orderBy('st.name','ASC');
return $query;
}
Controller (StockController.php) :
public function indexAction() {
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('LiveDataShopBundle:Stock')->findAllQuery();
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$entities, $this->get('request')->query->get('page', 1), 50
);
return array(
'pagination' => $pagination,
);
}
Entity (Stock.php) :
<?php
namespace LiveData\Bundle\ShopBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/** * Stock * * #ORM\Table() *
#ORM\Entity(repositoryClass="LiveData\Bundle\ShopBundle\Entity\StockRepository")
*/ class Stock {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \stdClass
*
* #ORM\ManyToOne(targetEntity="Store", inversedBy="stocks")
* #ORM\JoinColumn(name="store_id", referencedColumnName="id", onDelete="set null")
*/
private $store;
/**
* #var integer
*
* #ORM\Column(name="quantity", type="integer")
*/
private $quantity;
/**
* #var \stdClass
*
* #ORM\ManyToOne(targetEntity="Product", inversedBy="stocks")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id", onDelete="set null")
*/
private $product;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set store
*
* #param \stdClass $store
* #return Stock
*/
public function setStore($store)
{
$this->store = $store;
return $this;
}
/**
* Get store
*
* #return \stdClass
*/
public function getStore()
{
return $this->store;
}
/**
* Set quantity
*
* #param integer $quantity
* #return Stock
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
/**
* Get quantity
*
* #return integer
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* Set product
*
* #param \stdClass $product
* #return Stock
*/
public function setProduct($product)
{
$this->product = $product;
return $this;
}
/**
* Get product
*
* #return \stdClass
*/
public function getProduct()
{
return $this->product;
} }
Any idea to reduce the process time ?
Thanks in advance !
I do not know much about doctrine 2 only doctrine 1. Like i see in your code you only displaying 50 at one time. If this is the case than try to do a count(*) on stocks put this into the paginator and load only 50 (offset and limit) per page. That should help a lot.
Or use sphinx/solr. But i think the problem is the big amout of data that has to be moved from db to doctrine2/symphony2 (2.000.000 rows), try to debug and get futher informations.
If your problem is in mapping from db to objects, try to enable apc (for example) cache:
#app/config/config.yml
doctrine:
orm:
metadata_cache_driver: apc
query_cache_driver: apc
Related
I have below a query build with eloquent on laravel, it is very slow (50 points it take to show around 10 second), i can't understand if it a problem of the query construct or some missing index on table, some advise?
thanks
Points model (around 5000 records on the table)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use OwenIt\Auditing\Contracts\Auditable;
class Points extends Model implements Auditable
{
use \OwenIt\Auditing\Auditable;
use SoftDeletes;
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps = false;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'points';
/**
* The database primary key value.
*
* #var string
*/
protected $primaryKey = 'id';
/**
* Attributes that should be mass-assignable.
*
* #var array
*/
protected $fillable = [
'schedule_id',
'customer_id',
'cart_zone_id',
'indirizzo',
'latitudine',
'longitudine',
'tipo',
'enabled'
];
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = [];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [];
/**
* Get the Schedule for this model.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function Schedule()
{
return $this->belongsTo('App\Models\Schedules', 'schedule_id', 'id')->withTrashed();
}
/**
* Get the Customer for this model.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function Customer()
{
return $this->belongsTo('App\Models\Customers', 'customer_id', 'id')->withTrashed();
}
/**
* Get the CartZone for this model.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function CartZone()
{
return $this->belongsTo('App\Models\CartZones', 'cart_zone_id', 'id')->withTrashed();
}
}
Events model (around 400k records on the table)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
class RecordEvents extends Model
{
/**
* Indicates if the model should be timestamped.
*
* #var bool
*/
public $timestamps = false;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'events';
/**
* The database primary key value.
*
* #var string
*/
protected $primaryKey = 'id';
/**
* Attributes that should be mass-assignable.
*
* #var array
*/
protected $fillable = [
'code',
'description',
'device_id',
'schedule_id',
'boa_id',
'parent_id',
'user_id',
'skip_unique'
];
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = [];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [];
/**
* Get the device for this model.
*
* #return App\Models\Device
*/
public function device()
{
return $this->belongsTo('App\Models\Devices', 'device_id')->withTrashed();
}
/**
* Get the schedule for this model.
*
* #return App\Models\Schedule
*/
public function schedule()
{
return $this->belongsTo('App\Models\Schedules', 'schedule_id')->withTrashed();
}
/**
* Get the boa for this model.
*
* #return App\Models\Boa
*/
public function boa()
{
return $this->belongsTo('App\Models\Points', 'boa_id')->withTrashed();
}
/**
* Get the boa for this model.
*
* #return App\Models\Boa
*/
public function pvd()
{
return $this->belongsTo('App\Models\CustomersPvds', 'pvd_id')->withTrashed();
}
/**
* Get the boa for this model.
*
* #return App\Models\Boa
*/
public function cartzone()
{
return $this->belongsTo('App\Models\CartZones', 'cartzone_id')->withTrashed();
}
/**
* Get the parent for this model.
*
* #return App\Models\Parent
*/
public function parent()
{
return $this->belongsTo('App\Models\Parent', 'parent_id')->withTrashed();
}
/**
* Get the user for this model.
*
* #return App\Models\User
*/
public function user()
{
return $this->belongsTo('App\Models\Users', 'user_id')->withTrashed();
}
/**
* Get created_at in array format
*
* #param string $value
* #return array
*/
public function getCreatedAtAttribute($value)
{
return \DateTime::createFromFormat($this->getDateFormat(), $value)->format('d/m/Y H:i:s');
}
/**
* Get data in array format
*
* #param string $value
* #return string
*/
public function getDataRawAttribute($value)
{
return Carbon::createFromFormat('d/m/Y H:is', $this->created_at)->format('Y-m-d H:i:s');
}
}
Query
$pointsCartZone = Points::where('cart_zone_id', $trip->cart_zone_id)
->where('enabled', 1)
->select('*', DB::raw('(select COUNT(*) as ch from events where boa_id = points.id and schedule_id = ' . $id . ') as passed'))
->get();
try to put on events table the index on boa_id and schedule_id and on points table on cart_zone_id.
let me know if it works :-)
I'm trying to fetch results from mysql table
I'm using symfony3 and of course doctrine 2
I have 2 entity Client.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\ManyToMany;
use Doctrine\ORM\Mapping\JoinTable;
use Doctrine\ORM\Mapping\JoinColumn;
/**
* Client
*
* #ORM\Table(name="client")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ClientRepository")
*/
class Client
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="cin", type="integer")
*/
private $cin;
/**
* #ManyToMany(targetEntity="
* #JoinTable(name="listesouhait",
* joinColumns={#JoinColumn(name="utilisateur_id",
referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="evenement_id",
referencedColumnName="id")}
* )
*/
private $evenements;
public function __construct() {
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set cin
*
* #param integer $cin
*
* #return Client
*/
public function setCin($cin)
{
$this->cin = $cin;
return $this;
}
/**
* Get cin
*
* #return int
*/
public function getCin()
{
return $this->cin;
}
/**
* Add evenement
*
* #param \AppBundle\Entity\Evenement $evenement
*
* #return Client
*/
public function addEvenement(\AppBundle\Entity\Evenement $evenement)
{
$this->evenements[] = $evenement;
return $this;
}
/**
* Remove evenement
*
* #param \AppBundle\Entity\Evenement $evenement
*/
public function removeEvenement(\AppBundle\Entity\Evenement $evenement)
{
$this->evenements->removeElement($evenement);
}
/**
* Get evenements
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEvenements()
{
return $this->evenements;
}
}
and Evenement.php
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\JoinColumn;
/**
* Evenement
*
* #ORM\Table(name="evenement")
* #ORM\Entity(repositoryClass="AppBundle\Repository\EvenementRepository")
*/
class Evenement
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
//all attributes
when executing php bin\console doctrine:schema:update --force
image source
now everything is fine
but i can't find a clear code to insert in my controllerAction to fetch all the records in table listeshouhait (which is being generated automatically) because the table listeshouhait is not a real entity
also to mention that my repository are empty
i've heard of DQL in Repository and it might be helpful
Can SO help me please ??
To get the list of events attached to a client, in your controller :
$em = $this->getDoctrine()->getManager();
// Récupérer le client qui a l'id = 1
$item = $em->getRepository('AppBundle:Client')->findOneById(1);
// Liste des evenements
$events = $item->getEvenements();
foreach ($events as $event)
{
echo $event->getId() .'<br>';
}
die;
I'm currently working on a project for which i have to deal with a lot of users fields (+/- 80). My first approach was (and still is) to vertically partition the user table in 4 tables : main informations, administrative informations, banking informations, statistics informations. The ids of the 3 extra tables rows refer to the auto incremented id of the main table.
My questions are :
Is it relevant to do so ?
It seems like, with the way i did the
association, Doctrine isn't able to flush one object into database
in one shot :
Entity of type MyVendor\User\UserBundle\Entity\UsersInfosBank is missing an
assigned ID for field 'id_user'. The identifier generation strategy
for this entity requires the ID field to be populated before
EntityManager#persist() is called. If you want automatically generated
identifiers instead you need to adjust the metadata mapping
accordingly.
The project will be pushed into production in 3 weeks, so we're still able to go back to a more traditionnal way to store these datas into one huge table…
****************UPDATE*****************
WHOLE CODE LOGIC BELOW*****************
I just removed most of the properties and methods which are not concerned by my problem…
And yes, i'm using FOSUserBundle ;)
UsersMain
<?php
namespace LCP\User\UserBundle\Entity;
use FOS\UserBundle\Model\GroupableInterface;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* UsersMain
*
* #ORM\Table(name="lcp_users_main")
* #ORM\Entity
*/
class UsersMain extends BaseUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersInfosBank", mappedBy="id_user", cascade={"persist"})
*/
private $infosBank;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersApodis", mappedBy="id_user", cascade={"persist"})
*/
private $apodis;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersInfosAdmin", mappedBy="id_user", cascade={"persist"})
*/
private $infosAdmin;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersInfosStats", mappedBy="id_user", cascade={"persist"})
*/
private $infosStats;
/**
* Constructor
*/
public function __construct()
{
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
$this->creationDate = new \Datetime();
}
/**
* Set apodis
*
* #param \LCP\User\UserBundle\Entity\UsersApodis $apodis
* #return UsersMain
*/
public function setApodis(\LCP\User\UserBundle\Entity\UsersApodis $apodis = null)
{
if(is_null($this->apodis) && is_null($apodis)){
$this->apodis = new \LCP\User\UserBundle\Entity\UsersApodis();
} else {
$this->apodis = $infosBank;
}
$this->apodis->setIdUser($this);
return $this;
}
/**
* Get apodis
*
* #return \LCP\User\UserBundle\Entity\UsersApodis
*/
public function getApodis()
{
if(is_null($this->infosAdmin)){
$this->infosAdmin = new \LCP\User\UserBundle\Entity\UsersApodis();
}
return $this->apodis;
}
/**
* Set infosAdmin
*
* #param \LCP\User\UserBundle\Entity\UsersInfosAdmin $infosAdmin
* #return UsersMain
*/
public function setInfosAdmin(\LCP\User\UserBundle\Entity\UsersInfosAdmin $infosAdmin = null)
{
if(is_null($this->infosAdmin) && is_null($infosAdmin)){
$this->infosAdmin = new \LCP\User\UserBundle\Entity\UsersInfosAdmin();
} else {
$this->infosAdmin = $infosAdmin;
}
$this->infosAdmin->setIdUser($this);
return $this;
}
/**
* Get infosAdmin
*
* #return \LCP\User\UserBundle\Entity\UsersInfosAdmin
*/
public function getInfosAdmin()
{
if(is_null($this->infosAdmin)){
$this->infosAdmin = new \LCP\User\UserBundle\Entity\UsersInfosAdmin();
}
return $this->infosAdmin;
}
/**
* Set infosStats
*
* #param \LCP\User\UserBundle\Entity\UsersInfosStats $infosStats
* #return UsersMain
*/
public function setInfosStats(\LCP\User\UserBundle\Entity\UsersInfosStats $infosStats = null)
{
if(is_null($this->infosStats) && is_null($infosStats)){
$this->infosStats = new \LCP\User\UserBundle\Entity\UsersInfosStats();
} else {
$this->infosStats = $infosAdmin;
}
$this->infosStats->setIdUser($this);
return $this;
}
/**
* Get infosStats
*
* #return \LCP\User\UserBundle\Entity\UsersInfosStats
*/
public function getInfosStats()
{
if(is_null($this->infosStats)){
$this->infosStats = new \LCP\User\UserBundle\Entity\UsersInfosStats();
}
return $this->infosStats;
}
}
UsersInfosAdmin
<?php
namespace LCP\User\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* UsersInfosAdmin
*
* #ORM\Table(name="lcp_users_infos_admin", indexes={#ORM\Index(name="pharmacyCip_idx", columns={"pharmacy_cip"})})
* #ORM\Entity
*/
class UsersInfosAdmin
{
/**
* #var integer
* #ORM\Id
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersMain", cascade={"persist"}, inversedBy="infosAdmin")
*/
private $id_user;
/**
* Set id_user
*
* #param \LCP\User\UserBundle\Entity\UsersMain $idUser
* #return UsersInfosAdmin
*/
public function setIdUser(\LCP\User\UserBundle\Entity\UsersMain $idUser)
{
$this->id_user = $idUser;
return $this;
}
/**
* Get id_user
*
* #return \LCP\User\UserBundle\Entity\UsersMain
*/
public function getIdUser()
{
return $this->id_user;
}
}
UsersInfosStats
<?php
namespace LCP\User\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* UsersInfosStats
*
* #ORM\Table(name="lcp_users_infos_stats")
* #ORM\Entity
*/
class UsersInfosStats
{
/**
* #var integer
* #ORM\Id
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersMain", cascade={"persist"}, inversedBy="infosStats")
*/
private $id_user;
/**
* Set id_user
*
* #param \LCP\User\UserBundle\Entity\UsersMain $idUser
* #return UsersInfosStats
*/
public function setIdUser(\LCP\User\UserBundle\Entity\UsersMain $idUser)
{
$this->id_user = $idUser;
return $this;
}
/**
* Get id_user
*
* #return \LCP\User\UserBundle\Entity\UsersMain
*/
public function getIdUser()
{
return $this->id_user;
}
}
Here is how i create a user (it is through a secured admin area form) :
/**
* This action get the field from the form
*/
public function userSaveAction(Request $request)
{
$userManager = $this->get('fos_user.user_manager');
$this->request = $request;
$userValues = $this->getRequest()->request->all();
$this->em = $this->getDoctrine()->getManager();
$user = $this->processUser($userValues);
$userManager->updateUser($user, false);
return $this->redirect($this->generateUrl('lcp_admin_user_edit', ['id'=>$user->getId()]));
}
/**
* This method process user fields and uses setters (or getters for joined entities) to set datas of user
*/
private function processUser($userValues)
{
if($userValues['userId']=="") {
$user = $this->get('fos_user.user_manager')->createUser();
} else {
$user = $this->em->getRepository('LCPUserBundle:UsersMain')
->findOneBy(['id' => $userId]);
}
//construction of related entities
$user->setInfosAdmin();
$user->setInfosBank();
$user->setInfosStats();
$user->setApodis();
unset($userValues['userId']);
//this method inspect submitted field to check if they are mandatory or if current user is allowed to modify them
$this->fields = $this->getInfosFields();
foreach($userValues as $input=>$value){
list($entity,$input)=explode('-',$input);
if($input=='plainPassword' && $value==''){
continue;
}
if($entity=='Main'){
$setter = 'set'.ucfirst($input);
$user->$setter($value);
} else {
$setter = 'set'.ucfirst($input);
$join = 'get'.$entity;
$user->$join()->$setter($value);
}
}
return $user;
}
According to the comments your UsersMain property need to be like this:
/**
* Join administrative informations
* #ORM\OneToOne(targetEntity="MyVendor\User\UserBundle\Entity\UsersInfosAdmin", mappedBy="userMain", cascade={"persist"}, orphanRemoval=true)
*/
private $infosAdmin;
/**
* Setter InfosAdmin
*/
public function setInfosAdmin(UsersInfosAdmin $infosAdmin)
{
$this->infosAdmin = $infosAdmin;
$this->infosAdmin->setUserMain($this); <--- add this to set userMain on associated object
return $this;
}
then your UsersInfosAdmin properties need to be like this:
/**
* #var integer
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="MyVendor\User\UserBundle\Entity\UsersMain", inversedBy="userMain")
*/
private $userMain;
Issue
I've been trying to follow the tutorial to embed a form in another one. What I'm trying to do here is add a task, and add multiple categories to it. I'm using the example at http://symfony.com/doc/current/book/forms.html#embedding-a-single-object, but I added some ORM annotations to make the relation many-to-many. As such, here is my code for the Task & Category entities:
Code
Task entity
<?php
namespace Acme\TaskBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Task
*
* #ORM\Table()
* #ORM\Entity
*/
class Task
{
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="tasks_categories")
*
* #Assert\Type(type="Acme\TaskBundle\Entity\Category")
*/
protected $categories;
// ...
/**
* #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;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Task
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add categories
*
* #param \Acme\TaskBundle\Entity\Category $categories
* #return Task
*/
public function addCategorie(\Acme\TaskBundle\Entity\Category $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* #param \Acme\TaskBundle\Entity\Category $categories
*/
public function removeCategorie(\Acme\TaskBundle\Entity\Category $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
}
Category entity
<?php
namespace Acme\TaskBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Table()
* #ORM\Entity
*/
class Category
{
/**
* #ORM\ManyToMany(targetEntity="Task", mappedBy="categories")
*/
private $tasks;
/**
* #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;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->tasks = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add tasks
*
* #param \Acme\TaskBundle\Entity\Task $tasks
* #return Category
*/
public function addTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks[] = $tasks;
return $this;
}
/**
* Remove tasks
*
* #param \Acme\TaskBundle\Entity\Task $tasks
*/
public function removeTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks->removeElement($tasks);
}
/**
* Get tasks
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTasks()
{
return $this->tasks;
}
}
Both forms have been auto-generated by using the doctrine:generate:form command. I changed the TaskType form to include the categories:
TaskType form
<?php
namespace Acme\TaskBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('categories', new CategoryType())
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Task',
'cascade_validation' => true,
));
}
public function getName()
{
return 'task';
}
}
Now when I go to the create page for tasks, I get this error:
The form's view data is expected to be an instance of class
Acme\TaskBundle\Entity\Category, but is an instance of class
Doctrine\Common\Collections\ArrayCollection. You can avoid this error
by setting the "data_class" option to null or by adding a view
transformer that transforms an instance of class
Doctrine\Common\Collections\ArrayCollection to an instance of
Acme\TaskBundle\Entity\Category.
I honestly have no idea how to fix it since this seemed a pretty straight-forward thing but apparently it isn't. Could someone help me out here please?
in your Task Entity remove the validation for categories.
Symfony tries to validate a ArrayCollection as one Category!(hence the error)
* #Assert\Type(type="Acme\TaskBundle\Entity\Category")
*/
$categories;
It isn't necessary since it is a collection. (validation will be based on what type of objects are in the collection)
If you created a CategoryType form then this form should return Acme\TaskBundle\Entity\Category for it's data class.
class CategoryType {
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Category',
.....
));
}
}
Also, in your TaskType
$builder
->add('name')
->add('categories', new CategoryType()) // new CategoryType()
// is not really needed here,
// symfony will automatically detect
// it's relation and create a new
// CategoryType if necessary.
I've got a problem with JMSSerializerBundle.
I have my entity AGVote there :
<?php
namespace K\AGBundle\Entity;
use JMS\SerializerBundle\Annotation\Type;
use JMS\SerializerBundle\Annotation\Accessor;
use JMS\SerializerBundle\Annotation\AccessType;
use JMS\SerializerBundle\Annotation\Exclude;
use JMS\SerializerBundle\Annotation\ExclusionPolicy;
use Doctrine\ORM\Mapping as ORM;
/**
* K\AGBundle\Entity\AGVote
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*
*/
/*
*
/** #AccessType("public_method") */
class AGVote
{
/**
* #Type("integer")
* #Accessor(getter="getId")
*/
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="text")
* #Accessor(getter="getQuestion")
* #Type("text")
*/
public $question;
/**
* #ORM\Column(type="smallint")
* #Type("integer")
* #Accessor(getter="getActif")
*/
public $actif;
/**
* #ORM\ManyToOne(targetEntity="\K\KBundle\Entity\Users", cascade={"all"})
* #Exclude
*/
protected $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 K\KBundle\Entity\Province $Users
*/
public function setUsers(\K\KBundle\Entity\Users $users)
{
$this->users = $users;
}
/**
* Get Users
*
* #return K\KBundle\Entity\Users
*/
public function getUsers()
{
return $this->users;
}
public function __toString()
{
return $this->getquestion();
}
}
I have made a controller that juste return me an AGVote Entity in Json :
public function jsonvoteAction($id) {
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('KAGBundle:AGVote')->findOneById($id);
if ($entity->getActif() == 1) {
$serializer = $this->container->get('serializer');
$serializer->serialize($entity, 'json');
$response = new Response($serializer);
return $reponse;
}
}
I have a response in Json but it is a error saying :
[{"message":"The Response content must be a string or object implementing __toString(), \"object\" given.","class":"UnexpectedValueException","trace":
In fact I have already implement a __toString() method inside of all my entities.
Does anyone have an idea ?
Thanks you :)
When you call the serialize method on the $serializer, it returns the serialized data (a string).
The problem is that you do not use this returned value, and create the response with the $serializer itself, which makes no sense.
First, store the serialized $entity:
$serializedEntity = $serializer->serialize($entity, 'json');
Then, you can return a new response using with string:
return new Response($serializedEntity, 200, array('Content-Type' => 'application/json'));