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;
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 :-)
Some how whatever changes i make in my entites,doctrine doesn't seem to update it.I know there are already some similar questions.I have gone through them and tried :
php app/console cache:clear
php app/console doctrine:cache:clear-metadata
php app/console doctrine:schema:update --force
I have never imported the database,so there are no orm.yaml files in my src folder.
I am using mysql database with symfony and doctrine as orm.
here is my config
doctrine:
dbal:
driver: pdo_mysql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
# if using pdo_sqlite as your database driver:
# 1. add the path in parameters.yml
# e.g. database_path: "%kernel.root_dir%/data/data.db3"
# 2. Uncomment database_path in parameters.yml.dist
# 3. Uncomment next line:
# path: "%database_path%"
orm:
auto_generate_proxy_classes: "%kernel.debug%"
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
doctrine:schema:validate gives me this:
[Mapping] FAIL - The entity-class 'Madhuri\TermsBundle\Entity\RelatedTerm' mapping is invalid:
* The association Madhuri\TermsBundle\Entity\RelatedTerm#term1 refers to the inverse side field Madhuri\TermsBundle\Entity\Term#relatedTerm which does not exist.
My entities are
Term.php
namespace Madhuri\TermsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Term
*
* #ORM\Table(name="terms")
* #ORM\Entity
*/
class Term
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="termName", type="string", length=255)
*/
private $termName;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=2000)
*/
private $description;
/**
* #var string
*
* #ORM\Column(name="mnemonic", type="string", length=2000)
*/
private $mnemonic;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="RelatedTerm",
* mappedBy="term1")
*/
private $relatedTerms;
// /**
// * #var ArrayCollection
// *
// * #ORM\OneToMany(targetEntity="TermExamples",
// * mappedBy="term")
// */
// private $termExamples;
public function __construct()
{
$this->relatedTerms = new ArrayCollection();
$this->$termExamples = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Get Related Terms
*/
public function getRelatedTerms()
{
return $this->relatedTerms ;
}
/**
* Add related term
*/
public function addRelatedTerm($relatedTerm)
{
$this->relatedTerms[] = $relatedTerm;
}
/**
* Clear related Terms
*/
public function clearRelatedTerms()
{
$this->relatedTerms->clear();
}
/**
* Remove a related Term
*/
public function removeRelatedTerm($relatedTerm)
{
$this->relatedTerms->removeElement($relatedTerm);
}
/**
* Get Term Examples
*/
// public function getTermExamples()
// {
// return $this->termExamples ;
// }
//
// /**
// * Add term example
// */
// public function addTermExample($termExample)
// {
// $this->termExamples[] = $termExample;
// }
//
// /**
// * Clear term examples
// */
// public function clearTermExamples()
// {
// $this->termExamples->clear() ;
// }
//
// /**
// * Remove a Term Example
// */
// public function removeTermExample($termExample)
// {
// $this->termExamples->removeElement($termExample);
// }
/**
* Set termName
*
* #param string $termName
* #return Term
*/
public function setTermName($termName)
{
$this->termName = $termName;
return $this;
}
/**
* Get termName
*
* #return string
*/
public function getTermName()
{
return $this->termName;
}
/**
* Set description
*
* #param string $description
* #return Term
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set mnemonic
*
* #param string $mnemonic
* #return Term
*/
public function setMnemonic($mnemonic)
{
$this->mnemonic = $mnemonic;
return $this;
}
/**
* Get mnemonic
*
* #return string
*/
public function getMnemonic()
{
return $this->mnemonic;
}
}
RelatedTerm.php
<?php
namespace Madhuri\TermsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* RelatedTerms
*
* #ORM\Table(name="related_terms")
* #ORM\Entity
*/
class RelatedTerm
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Term
*
* #ORM\ManyToOne(targetEntity="Term",
* inversedBy="relatedTerm")
*/
private $term1;
/**
* #var Term
*
* #ORM\ManyToOne(targetEntity ="Term")
*/
private $term2;
/**
* #var string
*
* #ORM\Column(name="notes", type="string", length=2000, nullable=true)
*/
private $notes;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Get term1
*
* #return Term
*/
public function getTerm1()
{
if($this->term1)
{
return $this->term1;
}
else {
return null;
}
}
/**
* Set term1
*
* #param Term $term1
*
* #return Term
*/
public function setTerm1(Term $term1)
{
$this->term1 = $term1;
return $this;
}
/**
* Get term2
*
* #return Term
*/
public function getTerm2()
{
return $this->term2;
}
/**
* Set term2
*
* #param Term $term2
*
* #return Term
*/
public function setTerm2( Term $term2)
{
$this->term2 = $term2;
return $this;
}
/**
* Get notes
*
* #return string
*/
public function getNotes()
{
return $this->notes;
}
/**
* Set notes
*
* #param string $notes
*
* #return Term
*/
public function setNotes($notes)
{
$this->notes = $notes;
return $this;
}
}
?>
If you are using doctrine without framework (like i do), delete the calling to doctrine as ORM (maybe not needed)
use Doctrine\ORM\Mapping as ORM;
then replace all the #ORM\ for just #.
This was stopping doctrine from recognizing the class and its changes.
Hope it helps
Every quartal (each 3-month) i need into table "report" add new "column" - for example "Y2014Q1" where Y=year and Q=quartal (1,2,3,4). After creating I need to make mapping of this new column in to object.
Part of my code is:
namespace backend\backendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* FactSheetData
*
* #ORM\Table(name="report")
* #ORM\Entity
*/
class ReportData
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Y2016Q3", type="string")
*/
private $Y2016Q3;
/**
* #param string $Y2016Q3
*/
public function setY2016Q3($Y2016Q3)
{
$this->Y2016Q3 = $Y2016Q3;
}
/**
* #return string
*/
public function getY2016Q4()
{
return $this->Y2016Q4;
}
....
I need to do something like this when new period comes:
class ReportData {
public function __construct() {
// if new perriod alter table
if (test_new_perriod) {
$new_period='Y2016Q4';
$sql="ALTER TABLE `report` ADD COLUMN `".$new_period."` VARCHAR(50) NULL DEFAULT NULL;";
$stmt = $this->getEntityManager()->getConnection()->prepare($sql);
$stmt->execute();
//and now - this is problem how to do - dynamic maping
/**
* #var string
*
* #ORM\Column(name="$new_period", type="string")
*/
private $new_period;
/**
* #param string $new_period
*/
public function set$new_period($new_period)
{
$this->$new_period =$new_period;
}
/**
* #return string
*/
public function get$new_period()
{
return $this->$new_period;
}
}
}
Hope I describe clear... Thanx for any advice.
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'));