I'm new to Symfony2 + Doctrine and I´m looking for a way to validate the uniqueness in an Arraycollection. May be it is already answered question but I can´t figure how resolve it.
I`ve a Relevamientosserviciosprestador class with a Callback:
namespace Prestadores\PrincipalBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\ExecutionContext;
/**
* Prestadores\PrincipalBundle\Entity\Relevamientosserviciosprestador
*
* #ORM\Table(name="relevServiciosPrestador")
* #ORM\Entity(repositoryClass="Prestadores\PrincipalBundle\Repository\RelevamientosserviciosprestadorRepository")*
* #Assert\Callback(methods={"sonUnicosLosTiposDeReclamoq"})
*/
class Relevamientosserviciosprestador
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
....
....
/**
* #ORM\OneToMany(targetEntity="Atencionusuarioreclamo", mappedBy="relevamiento_id", cascade={"persist"})
* #Assert\Valid
*/
private $reclamos;
....
....
public function __construct()
{
$this->personal = new ArrayCollection();
$this->reclamos = new ArrayCollection();
}
....
....
/*Acá intentaremos validar si los tipos de reclamo que se están cargando son únicos para ese relevamiento*/
public function sonUnicosLosTiposDeReclamoq(ExecutionContext $context)
{
foreach ($this->reclamos as $reclamo){
/*Here, I get all entities, not only those related to a Relevamientosserviciosprestador*/
var_dump($reclamo->gettiporeclamo()->getnombre());
}
}
}
And the Atencionusuarioreclamo entity:
namespace Prestadores\PrincipalBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Prestadores\PrincipalBundle\Entity\Atencionusuarioreclamo
*
* #ORM\Table(name="atencionUsuarioReclamo")
* #ORM\Entity
*/
class Atencionusuarioreclamo
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var Atencionusuariosede
*
* #ORM\ManyToOne(targetEntity="Atencionusuariosede")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="nroSede", referencedColumnName="id")
* })
*/
private $nrosede;
/**
* #var relevamiento_id
*
* #ORM\ManyToOne(targetEntity="Relevamientosserviciosprestador")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="relevamiento_id", referencedColumnName="id")
* })
*/
private $relevamiento_id;
/**
* #var Prmreclamotipo
*
* #ORM\ManyToOne(targetEntity="Prmreclamotipo")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="tipoReclamo", referencedColumnName="id")
* })
* #Assert\NotBlank()
*/
private $tiporeclamo;
....
....
....
....
}
I want to chek uniqueness of tiporeclamo in a given sede and relevamiento_id
I create or edit a Relevamientosserviciosprestador using a Form which has a sub form collection for "Atencionusuarioreclamo" entities. On submit, the callback for Relevamientosserviciosprestador executes but $this->reclamos has all saved entities not only those related to the Relevamientosserviciosprestador what I´m editing.
Is this the expected behauvoir or I`m missing something?
I´ve also tested the approach mentioned in How to validate unique entities in an entity collection in symfony2
but, again, it checks all entities.
I´ve also read Doctrine2 ArrayCollection but I cant´t understand if it resolve the problem.
Please, can you tell me how do you manage uniqueness in your ArrayCollection before persist it?
I´m sorry for my poor english
Thanks in advance
Ivan
php's array array_unique ( array $array [, int $sort_flags = SORT_STRING ] )
combined with ArrayCollection->toArray() and ArrayCollection->__construct()
In your case:
$Atencionusuarioreclamo =
new ArrayCollection(array_unique($Atencionusuarioreclamo->toArray());
Related
I have two entities relating to this issue, and I want a join table to be able to cross reference values in each table.
Here is an explanation:
Entity ContainerType.php:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\Containers;
/**
* ContainerType
*
* #ORM\Table(name="container_type")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks()
*/
class ContainerType
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=255)
*/
private $type;
/**
* #var \DateTime
*
* #ORM\Column(name="date_added", type="datetime")
*/
private $dateAdded;
/**
* #var \DateTime
*
* #ORM\Column(name="date_modified", type="datetime", nullable=true)
*/
private $dateModified;
/**
* #ORM\ManyToMany(targetEntity="Containers", inversedBy="type")
* #ORM\JoinTable(name="container_type_containers")
**/
private $container;
public function __construct()
{
$this->container = new ArrayCollection();
}
And entity Containers.php:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use AppBundle\Entity\ContainerType;
/**
* Containers
*
* #ORM\Table(name="containers")
* #ORM\Entity
*/
class Containers
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="number", type="string", length=255)
*/
private $number;
/**
* #ORM\ManyToMany(targetEntity="Containers", mappedBy="container")
*/
private $type;
public function __construct()
{
$this->type = new ArrayCollection();
}
And although the schema update works without problems, when I do a doctrine:schema:validate I get the following fail:
[Mapping] FAIL - The entity-class 'AppBundle\Entity\Containers' mapping is invalid:
* The association AppBundle\Entity\Containers#type refers to the owning side field AppBundle\Entity\Containers#container which does not exist.
But the $container field DOES exist in ContainerType so I do not understand why it's trying to reference a field called container in the Containers entity?
Can anyone shed any light on this?
Thank you
Michael
I think this code should works fine for you :)
ContainerType.php
/**
* #ORM\ManyToMany(targetEntity="Containers", inversedBy="containersType")
* #ORM\JoinTable(name="container_type_containers",
* joinColumns={#ORM\JoinColumn(name="container_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="container_type_id", referencedColumnName="id")})
*/
protected $containers;
Containers.php
/**
* #ORM\ManyToMany(targetEntity="ContainerType", mappedBy="containers")
*/
protected $containersType;
I have just realized my error!
I had used the wrong target Entity in the Containers.php file, I should have used ContainerType as the target, instead I had Containers which is why it was trying to find the field in the wrong table!
I know that is a recurrent question but after creating a OneToOne relation between 2 entities and run 'php app/console doctrine:schema:validate' I get this error:
'[Mapping] FAIL - The entity-class 'HO\CisBundle\Entity\AffiliateSalesAccounts' mapping is invalid:
* The association HO\CisBundle\Entity\AffiliateSalesAccounts#affiliate refers to the inverse side field HO\HasoffersBundle\Entity\Affiliate#affiliateSalesAccounts which does not exist.'
This is part of the code with both entities:
AffiliatesSalesAccount Entity
namespace HO\CisBundle\Entity;
use HO\HasoffersBundle\Entity\Affiliate;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="AffiliateSalesAccounts")
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks
*/
class AffiliateSalesAccounts {
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
private $id;
/**
* #var \HO\HasoffersBundle\Entity\Affiliate
*
* #ORM\OneToOne(targetEntity="HO\HasoffersBundle\Entity\Affiliate", inversedBy="affiliateSalesAccounts")
* #ORM\JoinColumn(name="affiliate_id", referencedColumnName="id")
*
*/
private $affiliate;
...
/**
* #param Affiliate $affiliate
*/
public function setAffiliate(Affiliate $affiliate)
{
$this->affiliate = $affiliate;
}
/**
* #return Affiliate
*/
public function getAffiliate()
{
return $this->affiliate;
}
}
Affiliate Entity
namespace HO\HasoffersBundle\Entity;
use HO\CisBundle\Entity\AffiliateSalesAccounts;
use Doctrine\ORM\Mapping as ORM;
/**
*
* #ORM\Table(name="ho_Affiliate")
*/
class Affiliate
{
/**
* #var AffiliateSalesAccounts
*
* #ORM\OneToOne(targetEntity="HO\CisBundle\Entity\AffiliateSalesAccounts", mappedBy="affiliate")
*/
private $affiliateSalesAccounts;
....
/**
* #param \HO\CisBundle\Entity\AffiliateSalesAccounts $affiliateSalesAccounts
*/
public function setAffiliateSalesAccounts($affiliateSalesAccounts)
{
$this->affiliateSalesAccounts = $affiliateSalesAccounts;
}
/**
* #return \HO\CisBundle\Entity\AffiliateSalesAccounts
*/
public function getAffiliateSalesAccounts()
{
return $this->affiliateSalesAccounts;
}
}
I have other similar OneToOne relations between 2 entities and it works great.
Someone can I help me?
Thanks a lot..
I am not sure about your problem but I notice that I do it in a different way I just let the code here so that you will be able to check it
/**
* #ORM\OneToOne(targetEntity="Profile", mappedBy="user", cascade={"remove"})
**/
private $profile;
The other class:
/**
* #var \Lifecrops\LCUserBundle\Entity\User
*
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\OneToOne(targetEntity="Lifecrops\LCUserBundle\Entity\User", inversedBy="profile")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="User_id", referencedColumnName="id")
* })
*/
private $user;
Ussually I do something like this:
namespace HO\CisBundle\Entity;
use HO\HasoffersBundle\Entity\Affiliate;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="AffiliateSalesAccounts")
* #ORM\Entity()
*/
class AffiliateSalesAccounts {
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Affiliate", inversedBy="affiliateSalesAccounts")
* #ORM\JoinColumn(name="affiliate_id", referencedColumnName="id")
*
*/
private $affiliate;
/**
* #param Affiliate $affiliate
*/
public function setAffiliate(Affiliate $affiliate)
{
$this->affiliate = $affiliate;
}
/**
* #return Affiliate
*/
public function getAffiliate()
{
return $this->affiliate;
}
}
And the second entity:
namespace HO\HasoffersBundle\Entity;
use HO\CisBundle\Entity\AffiliateSalesAccounts;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Table(name="ho_Affiliate")
* #ORM\Entity()
*/
class Affiliate
{
/**
* #ORM\OneToOne(targetEntity="AffiliateSalesAccounts", mappedBy="affiliate")
*/
private $affiliateSalesAccounts;
/**
* #param AffiliateSalesAccounts $affiliateSalesAccounts
*/
public function setAffiliateSalesAccounts($affiliateSalesAccounts)
{
$this->affiliateSalesAccounts = $affiliateSalesAccounts;
}
/**
* #return AffiliateSalesAccounts
*/
public function getAffiliateSalesAccounts()
{
return $this->affiliateSalesAccounts;
}
}
Clearing cache is imortant part, and if all goes bad you can look to:
doctrine:
orm:
auto_mapping: true
Ok, I solved the problem... First, sorry for bothering you because it was a stupid silly absent-mindedness... Since we use Redis to cache doctrine (with sncRedisBundle), specially metadata and query, Affiliate entity was cached in Redis but without the new field declaration "affiliateSalesAccounts". After deleting the key which store Affiliate entity the problem was solved.
Thank so much for your comments
I updated my entity file to include relationship mapping.
Persist worked before the update now it doesn't.
Maybe it's something I forgot to do.
namespace classes\classBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* advisersplans
*
* #ORM\Table()
* #ORM\Entity
*/
class advisersPlans
{
/**
*
* #ORM\ManyToOne(targetEntity="plans", inversedBy="adviserPlans")
* #ORM\JoinColumn(name="planid", referencedColumnName="id")
*/
public $plan;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #var integer
*
* #ORM\Column(name="userid", type="integer")
*
*
*/
public $userid;
/**
* #var integer
*
* #ORM\Column(name="adviserid", type="integer")
*
*
*/
public $adviserid;
/**
* #var integer
*
* #ORM\Column(name="planid", type="integer")
*
*
*/
public $planid;
/**
* #var string
*
* #ORM\Column(name="participantLoginWebsiteAddress", type="string", length=255)
*/
public $participantLoginWebsiteAddress;
public function __construct()
{
$class_vars = get_class_vars(get_class($this));
foreach ($class_vars as $key => $value)
{
if ($key != "plan")
$this->$key = "";
}
}
}
Perist returns error saying planid is null. If I remove the following it works.
/**
*
* #ORM\ManyToOne(targetEntity="plans", inversedBy="adviserPlans")
* #ORM\JoinColumn(name="planid", referencedColumnName="id")
*/
Here is my code while persisting.
$adviserPlan = new advisersPlans();
$adviserPlan->planid = $planid;
$adviserPlan->userid = $this->userid();
$adviserPlan->adviserid = $session->get("editadviserid");
$em->persist($adviserPlan);
Am I supposed to populate the plan field and not the planid field or is my entity file coded wrong.
You shouldn't set ids. You should set entities:
$adviserPlan = new advisersPlans();
// You should retrieve the plan before doing this, of course.
$adviserPlan->setPlan($plan);
$plans->addAdviserPlan(§adviserPlan);
$em->persist($adviserPlan);
The methods for adding an entity to a collection should be generated by doctrine when you run:
php app/console doctrine:generate:entities YourBundle
I have a ManyToMany relation with a composite key on the reverse side.
When I use the console command doctrine:schema:update I have the following error:
[Doctrine\ORM\ORMException]
Column name `keyword` referenced for relation from Map\MapBundle\Entity\
Student towards Map\MapBundle\Entity\SkillType does not exist.
I have an entity student (unique key) with a ManyToMany relation with an entity skill (composite key) which has a ManyToOne relation with skillType (unique key).
Here is the different class mapping I have:
Class Student
<?php
namespace Map\MapBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Student
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Map\MapBundle\Entity\StudentRepository")
*/
class Student {
/**
*
* #var integer #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToMany(targetEntity="Map\MapBundle\Entity\SkillType")
* #ORM\JoinTable(name="students_skills",
* joinColumns={
* #ORM\JoinColumn(name="keyword", referencedColumnName="keyword"),
* #ORM\JoinColumn(name="attribut", referencedColumnName="attribut")
* })
*/
private $skills;
}
Class skill
<?php
namespace Map\MapBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Skill
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Map\MapBundle\Entity\SkillRepository")
*/
class Skill {
/**
* #ORM\ManyToOne(targetEntity="Map\MapBundle\Entity\skillType")
* #ORM\JoinColumn(name="keyword", referencedColumnName="keyword")
* #ORM\Id
*/
private $keyword;
}
Classe skillType
<?php
namespace Map\MapBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* SkillType
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Map\MapBundle\Entity\SkillTypeRepository")
*/
class SkillType {
/**
* #var string
*
* #ORM\Column(name="keyword", type="string", length=255)
* #ORM\Id
*/
private $keyword;
}
I tried to exchange the keyword and attribut #joinColumn lines, but I have the same error message with attribut instead of keyword.
I can't see what's wrong with my mapping. The table skill exists and has columns named keyword and attribut.
I hope that somebody will see where I made a mistake (probably a typo error like a missing character or a case mistake).
Thank you for your answer. It helped me a lot and i succeded doing the schema update.
Here is the code I finaly used
/**
* #ORM\ManyToMany(targetEntity="Carte\CarteBundle\Entity\Skill")
* #ORM\JoinTable(name="students_skills",
* joinColumns={#ORM\JoinColumn(name="student_id", referencedColumnName="id")},
* inverseJoinColumns={
* #ORM\JoinColumn(name="keyword", referencedColumnName="keyword"),
* #ORM\JoinColumn(name="attribut", referencedColumnName="attribut")
* })
*/
private $skills;
You write that you want Student to have the many-to-many relation with Skill, but you connected it with SkillType instead. And you're missing the inverseJoinColumns property and you didn't referenced Student properly.
Try the following annotation (untested and after looking at the documentation):
/**
* #ORM\ManyToMany(targetEntity="Map\MapBundle\Entity\Skill")
* #ORM\JoinTable(name="students_skills",
* joinColumns={#ORM\JoinColumn(name="student_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="skill_keyword", referencedColumnName="keyword")}
* )
*/
private $skills;
I'm pretty new to symfony/Doctrine and having some problems with querybuilder:
Given this ER:
And following declaration:
namespace xxx\SeoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* xxx\SeoBundle\Entity\Session
*
* #ORM\Table(name="session")
* #ORM\Entity
*/
class Session
{
const repositoryName = "InternetSmSeoBundle:Session";
/**
* #var string $id
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
*/
private $id;
......
/**
* #var Gsite
*
* #ORM\ManyToOne(targetEntity="Gsite")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="gsite_id", referencedColumnName="id")
* })
*/
private $site;
......
}
I need to find sessions which filtering them by site.
I've tried following approach:
$rep = $this->em->getRepository(Session::repositoryName);
$qb = $rep->createQueryBuilder("s");
$qb->setMaxResults(200);
$qb->where("1=1");
$qb->orderBy("time", "desc");
//site
if ($params->site != null){
/** #var Gsite **/
$site = $params->site;
$qb->where($qb->expr()->eq("gsite_id",$site->getId()));
}
Or even
$qb->where($qb->expr()->eq("site",$site));
But it doesn't work. What is correct way to filter data in presence of Many To One foreign keys? Do I need to create declaration of gsite_id column in my Model?
Thanks.
Set the parameter, Doctrine will be able to infer the type (no need to use the foreign key id):
$qb
->where($qb->expr()->eq('site', ':site'))
->setParameter('site', $site);
;