I am beginning to suspect that this doesn't work because in my use case it just doesn't -- as opposed to me missing something -- but I have to consult your expertise to make sure, and to see if anyone can suggesta workaround.
I have a Many-to-Many situation that I am implementing with an association class, so we have one-to-many/many-to-one associations between the 3 participating classes. There is an Interpreter entity representing a person, and a Language entity representing a spoken language (actually a working language pair, but one half of the pair is understood to be English in this anglocentric application). An Interpreter can have multiple languages, and a Language is among the working languages of multiple interpreters. We need to manage other attributes of the interpreter-language, hence the InterpreterLanguage class.
When I call $interpreter->removeInterpreterLanguage($interpreterLanguage); followed by $entityManager->flush(), the in-memory Interpreter entity has one fewer elements in its $interpreterLanguages collection as you would expect, and there is no error or Exception thrown, but in the database here's what happens: nothing.
I have tried this in an MVC context, with ZendFramework 3 and a bound Zend\Form\Form with fieldsets, and when that drove me nuts I wrote a CLI script to try to examine the problem -- same result. Maybe it's worth noting that for updating scalar properties it's working fine.
I apologize for not including a link to the discussion of this issue that I read earlier -- can't find it now, for some reason. But I recall someone saying that it just doesn't work because Doctrine sees the M:1 on the other side, and therefore won't delete, and you have to say $entityManager->remove($object) to get it done. My experimental CLI script appears to confirm this. Nevertheless, I'd like to rule out the possibility that I am doing something wrong.
Any ideas? Suggestions for solving?
So here's my Language entity:
/** module/InterpretersOffice/src/Entity/Language.php */
namespace InterpretersOffice\Entity;
use Doctrine\ORM\Mapping as ORM;
use Zend\Form\Annotation;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Entity class representing a language used by an Interpreter.
*
* #Annotation\Name("language")
* #ORM\Entity(repositoryClass="InterpretersOffice\Entity\Repository\LanguageRepository")
* #ORM\Table(name="languages",uniqueConstraints={#ORM\UniqueConstraint(name="unique_language",columns={"name"})})
*/
class Language
{
/**
* entity id.
*
* #ORM\Id
* #ORM\GeneratedValue #ORM\Column(type="smallint",options={"unsigned":true})
*/
protected $id;
/**
* name of the language.
*
* #ORM\Column(type="string",length=50,nullable=false)
*
* #var string
*/
protected $name;
/**
* comments.
*
* #ORM\Column(type="string",length=300,nullable=false,options={"default":""})
*
* #var string
*/
protected $comments = '';
/**
*
* #ORM\OneToMany(targetEntity="InterpreterLanguage",mappedBy="language")
*/
protected $interpreterLanguages;
/**
* constructor
*/
public function __construct()
{
$this->interpreterLanguages = new ArrayCollection();
}
// setters and getters omitted for brevity
}
Here is the Interpreter entity:
<?php
/** module/InterpretersOffice/src/Entity/Interpreter.php */
namespace InterpretersOffice\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* Entity representing an Interpreter.
*
* #ORM\Entity(repositoryClass="InterpretersOffice\Entity\Repository\InterpreterRepository")
* #ORM\Table(name="interpreters")
*/
class Interpreter extends Person
{
/**
* entity id.
*
* #ORM\Id #ORM\GeneratedValue #ORM\Column(type="smallint",options={"unsigned":true})
*/
protected $id;
/**
* phone number.
*
* #ORM\Column(type="string",length=16,nullable=true)
*
* #var string
*/
protected $phone;
/**
* date of birth.
*
* #ORM\Column(type="date",nullable=true)
*
* #var string
*/
protected $dob;
/**
* working languages.
*
* #ORM\OneToMany(targetEntity="InterpreterLanguage",mappedBy="interpreter", cascade={"persist", "remove"})
*
*
* #var ArrayCollection of InterpreterLanguage
*/
protected $interpreterLanguages;
/**
* Constructor.
*/
public function __construct()
{
$this->interpreterLanguages = new ArrayCollection();
}
// some boring setters and getters omitted....
/**
* Add interpreterLanguage.
*
* #param InterpreterLanguage $interpreterLanguage
*
* #return Interpreter
*/
public function addInterpreterLanguage(InterpreterLanguage $interpreterLanguage)
{
$this->interpreterLanguages->add($interpreterLanguage);
return $this;
}
/**
* Remove interpreterLanguage.
*
* #param \InterpretersOffice\Entity\InterpreterLanguage $interpreterLanguage
*
* #return Interpreter
*/
public function removeInterpreterLanguage(InterpreterLanguage $interpreterLanguage)
{
$this->interpreterLanguages->removeElement($interpreterLanguage);
//$interpreterLanguage->setInterpreter(null)->setLanguage(null);
return $this;
}
/**
* Get interpreterLanguages.
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getInterpreterLanguages()
{
return $this->interpreterLanguages;
}
/*
because "AllowRemove strategy for DoctrineModule hydrator requires both addInterpreterLanguages and removeInterpreterLanguages to be defined in InterpretersOffice\Entity\Interpreter entity domain code, but one or both
[seemed] to be missing"
*/
public function addInterpreterLanguages(Collection $interpreterLanguages)
{
foreach ($interpreterLanguages as $interpreterLanguage) {
$interpreterLanguage->setInterpreter($this);
$this->interpreterLanguages->add($interpreterLanguage);
}
}
public function removeInterpreterLanguages(Collection $interpreterLanguages)
{
foreach ($interpreterLanguages as $interpreterLanguage) {
$this->interpreterLanguages->removeElement($interpreterLanguage);
}
}
}
and the association class:
/** module/InterpretersOffice/src/Entity/InterpreterLanguage.php */
namespace InterpretersOffice\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Entity representing an Interpreter's Language.
*
* Technically, it is a language *pair*, but in this system it is understood that
* the other language of the pair is English. There is a many-to-many relationship
* between interpreters and languages. But because there is also metadata to record
* about the language (federal certification), it is implemented as a Many-To-One
* relationship on either side.
*
* #ORM\Entity
* #ORM\Table(name="interpreters_languages")
*/
class InterpreterLanguage
{
/**
* constructor.
*
* #param Interpreter $interpreter
* #param Language $language
*
* #todo a lifecycle callback to ensure certified languages have a boolean
* $federalCertification set
*/
public function __construct(
Interpreter $interpreter = null,
Language $language = null
) {
if ($interpreter) {
$this->setInterpreter($interpreter);
}
if ($language) {
$this->setLanguage($language);
}
}
/**
* The Interpreter who works in this language.
*
* #ORM\ManyToOne(targetEntity="Interpreter",inversedBy="interpreterLanguages")
* #ORM\Id
*
* #var Interpreter
*/
protected $interpreter;
/**
* The language in which this interpreter works.
*
* #ORM\ManyToOne(targetEntity="Language",inversedBy="interpreterLanguages")
* #ORM\Id
*
* #var Language
*/
protected $language;
/**
* Whether the Interpreter holds federal court interpreter certification in this language.
*
* The only certified languages in the US District Court system are Spanish,
* Navajo and Haitian Creole. Of these, only the Spanish certification
* program is active. This field should be a boolean for the certified
* languages and null for everything else.
*
* #link http://www.uscourts.gov/services-forms/federal-court-interpreters/federal-court-interpreter-certification-examination the federal court certification program
*
* #ORM\Column(name="federal_certification",type="boolean",nullable=true)
*
* #var bool
*/
protected $federalCertification;
/**
* Set interpreter.
*
* #param \InterpretersOffice\Entity\Interpreter $interpreter
*
* #return InterpreterLanguage
*/
public function setInterpreter(Interpreter $interpreter = null)
{
$this->interpreter = $interpreter;
return $this;
}
/**
* Get interpreter.
*
* #return Interpreter
*/
public function getInterpreter()
{
return $this->interpreter;
}
/**
* Set language.
*
* #param Language $language
*
* #return InterpreterLanguage
*/
public function setLanguage(Language $language = null)
{
$this->language = $language;
return $this;
}
/**
* Get language.
*
* #return Language
*/
public function getLanguage()
{
return $this->language;
}
/**
* Set federalCertification.
*
* #param bool $federalCertification
*
* #return InterpreterLanguage
*/
public function setFederalCertification($federalCertification)
{
$this->federalCertification = $federalCertification;
return $this;
}
/**
* Get federalCertification.
*
* #return bool
*/
public function getFederalCertification()
{
return $this->federalCertification;
}
}
For brevity's sake, I will leave out the code for the Form and the Fieldset classes -- they do seem to be working fine (look tasteful, too. Thank you Bootstrap). I load the form, I remove one of the InterpreterLanguages and submit... Here's the controller action:
/**
* updates an Interpreter entity.
*/
public function editAction()
{
$viewModel = (new ViewModel())
->setTemplate('interpreters-office/admin/interpreters/form.phtml')
->setVariable('title', 'edit an interpreter');
$id = $this->params()->fromRoute('id');
$entity = $this->entityManager->find('InterpretersOffice\Entity\Interpreter', $id);
if (!$entity) {
return $viewModel->setVariables(['errorMessage' => "interpreter with id $id not found"]);
}
$form = new InterpreterForm($this->entityManager, ['action' => 'update']);
$form->bind($entity);
$viewModel->setVariables(['form' => $form, 'id' => $id ]);
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if (!$form->isValid()) {
return $viewModel;
}
$this->entityManager->flush();
$this->flashMessenger()
->addSuccessMessage(sprintf(
'The interpreter <strong>%s %s</strong> has been updated.',
$entity->getFirstname(),
$entity->getLastname()
));
// dump the entity and see how it looksa after update
echo "NOT redirecting. entity:<pre>";
\Doctrine\Common\Util\Debug::dump($entity); echo "</pre>";
//$this->redirect()->toRoute('interpreters');
} else {
// dump the entity fresh from the database
echo "loaded:<pre> "; \Doctrine\Common\Util\Debug::dump($entity);echo "</pre>";}
return $viewModel;
}
Again, the data looks right as it's dumped to the screen, but you reload the form and the collection has as many elements as it did before.
Thanks!
In Interpreter.php, orphanRemoval=true !!
/**
* working languages.
*
* #ORM\OneToMany(targetEntity="InterpreterLanguage",mappedBy="interpreter",
* cascade={"persist", "remove"},orphanRemoval=true)
*
* #var ArrayCollection of InterpreterLanguage
*/
protected $interpreterLanguages;
Related
My entity class is:
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\TipiVendita", inversedBy="idAgente")
* #ORM\JoinTable(name="tipi_vendita_agenti",
* joinColumns={
* #ORM\JoinColumn(name="id_agente", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="id_tipo_vendita", referencedColumnName="id")
* }
* )
*/
private $idTipoVendita;
/**
* Constructor
*/
public function __construct()
{
$this->idTipoVendita = new \Doctrine\Common\Collections\ArrayCollection();
}
and when i use the command 'doctrine:generate:entities', methods that generates are wrongly named:
/**
* Add idTipoVendita
*
* #param \AppBundle\Entity\TipiVendita $idTipoVendita
* #return Agenti
*/
public function addIdTipoVenditum(\AppBundle\Entity\TipiVendita $idTipoVendita)
{
$this->idTipoVendita[] = $idTipoVendita;
return $this;
}
/**
* Remove idTipoVendita
*
* #param \AppBundle\Entity\TipiVendita $idTipoVendita
*/
public function removeIdTipoVenditum(\AppBundle\Entity\TipiVendita $idTipoVendita)
{
$this->idTipoVendita->removeElement($idTipoVendita);
}
/**
* Get idTipoVendita
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getIdTipoVendita()
{
return $this->idTipoVendita;
}
How can i have addIdTipoVentita instead of addIdTipoVenditum, removeIdTipoVendita instead of removeIdTipoVenditum?
Update
The issue is that doctrine don't generate properly my entity! It generates methods names with the doctrine inflector component and add these kind of suffixes. How can i configure it in the right way?
Riccardo, You should name your properties in English.
And you should be aware that you are in a Object world, you work with objects and not with object_ids.
So the Entity TipiVendita should be named something like SellType (english, singular).
While the `idTipoVendita' field, if I understand, should enforce an N-M relation with SellType and Agents, so it should be named something like sellTypes (english, plural because it is a collection).
To make a long story short idTipoVendita - beeing a field for a collection, is seen as a plural form and is singularized in idTipoVenditum (just like "Curricula" and "Curriculum").
Best regards.
I have a situation where I need to add columns to a many-to-many join table, so I'm trying to follow the recommended practice of having the join table represented by an entity with ManyToOne relationships with each of the other two entities.
In this case, we have a court interpreter management system where there's an entity called Event, another called Interpreter. The InterpreterAssignment entity is one-to-many with both of these, but it also needs two metadata columns: a created datetime, and the Application\Entity\User who created it (I leave out the latter for simplicity's sake).
So, this works just fine:
$interpreter = $entityManager->getRepository('Application\Entity\Interpreter')
->findOneBy(['lastname'=>'Mintz']);
$assignment = new Entity\InterpreterAssignment();
$assignment->setInterpreter($interpreter)->setEvent($event);
$event->addInterpretersAssigned($assignment);
$em->flush();
...and I don't even need to say persist() because of the cascade={"persist","remove"}) on Event#interpretersAssigned.
However, when I try to do the reverse, that is,
use the removeInterpretersAssigned() method that Doctrine wrote for me:
$event = $entityManager->find('Application\Entity\Event',103510);
$assignment = $event->getInterpretersAssigned()[0];
$event->removeInterpretersAssigned($assignment);
$em->flush();
the database is untouched; Doctrine does not delete the row in the join table.
I can work around by saying $entityManager->remove($assignment). But I can't help but think that $event->removeInterpretersAssigned($assignment) is supposed to work.
So, I must be missing something but I can't see what. The Doctrine cli tool says my mappings are OK. Here are the entities, in relevant part:
/* namespace declarations and use statements omitted */
class Event
{
/* other fields and methods omitted */
/**
* #ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="event",cascade={"persist","remove"})
* #var InterpreterAssignment[]
*/
protected $interpretersAssigned;
/* the following created by the Doctrine cli tool */
/**
* Remove interpretersAssigned
*
* #param \Application\Entity\InterpreterAssignment $interpretersAssigned
*/
public function removeInterpretersAssigned(\Application\Entity\InterpreterAssignment $interpretersAssigned)
{
$this->interpretersAssigned->removeElement($interpretersAssigned);
}
/**
* Get interpretersAssigned
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getInterpretersAssigned()
{
return $this->interpretersAssigned;
}
}
class Interpreter
{
/**
* #ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="interpreter")
* #var InterpreterAssignment[]
*/
protected $assignments;
/**
* Remove assignment
*
* #param \Application\Entity\InterpreterAssignment $assignment
*/
public function removeAssignment(\Application\Entity\InterpreterAssignment $assignment)
{
$this->assignments->removeElement($assignment);
}
/**
* Get assignments
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getAssignments()
{
return $this->assignments;
}
}
and here is the InterpreterAssignment
/**
* #ORM\Entity
* #ORM\Table(name="interp_events", uniqueConstraints={#ORM\UniqueConstraint(name="unique_deft_event",columns={"interp_id","event_id"})})
* #ORM\HasLifeCycleCallbacks
*/
class InterpreterAssignment
{
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Interpreter",inversedBy="assignments")
* #ORM\JoinColumn(name="interp_id", referencedColumnName="interp_id")
* #var Interpreter
*/
protected $interpreter;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Event",inversedBy="interpretersAssigned")
* #ORM\JoinColumn(name="event_id", referencedColumnName="event_id")
* #var Event
*/
protected $event;
/**
* #ORM\Column(type="datetime",nullable=false)
* #var \DateTime
*/
protected $created;
/**
* #ORM\PrePersist
*/
public function onPrePersist()
{
$this->created = new \DateTime();
}
/**
* Set interpreter
*
* #param \Application\Entity\Interpreter $interpreter
*
* #return InterpreterAssignment
*/
public function setInterpreter(\Application\Entity\Interpreter $interpreter)
{
$this->interpreter = $interpreter;
return $this;
}
/**
* Get interpreter
*
* #return \Application\Entity\Interpreter
*/
public function getInterpreter()
{
return $this->interpreter;
}
/**
* Set event
*
* #param \Application\Entity\Event $event
*
* #return InterpreterAssignment
*/
public function setEvent(\Application\Entity\Event $event)
{
$this->event = $event;
return $this;
}
/**
* Get event
*
* #return \Application\Entity\Event
*/
public function getEvent()
{
return $this->event;
}
/* other stuff ommitted */
}
Many thanks.
I think you need to do 2 things:
(optional) You need to call $assignment->setEvent(null) after calling $event->removeInterpretersAssigned($assignment);
Also you may want to use Orphan Removal to remove the entity from the many to many table. and so the entity code should changed to (notice the addition of , orphanRemoval=true to the mapping code):
/**
* #ORM\OneToMany(targetEntity="InterpreterAssignment",mappedBy="event",cascade={"persist","remove"}, orphanRemoval=true)
* #var InterpreterAssignment[]
*/
protected $interpretersAssigned;
I am new to Doctrine2 and trying to create entities for the following DB structure:
I want to have all machine parts as an array in one attribute of the machine class. I tried this:
class Machine {
....
/**
* #var array
* #ORM\OneToMany(targetEntity="MachineHasPart", mappedBy="machine", cascade={"persist", "remove"}, orphanRemoval=TRUE)
*/
private $parts;
....
public function getParts () {
return array_map(
function ($machineHasPart) {
return $machineHasPart->getPart();
},
$this->parts->toArray()
);
}
}
Where MachineHasPart is a #MappedSuperclass for the intermediate entities/tables (like machineHasCylinder etc), but it failed with:
An exception occurred while executing 'SELECT FROM machineHasPart t0'.
Should I restructure my database to use ORM here? Or there is a solution for my case?
You cannot query a #MappedSuperClass. This is also mentioned in the Doctrine2 documentation in chapter 6.1. Mapped Superclasses:
A mapped superclass cannot be an entity, it is not query-able and persistent
This means you have to either change the target entity to something queryable or you have to make MachineHasPart to a entity and change to single table inheritance.
When I look at your database structure I would suggest changing your Machine entity to have three independent relationships for the parts. One for Belt, one for Cylinder and one for Gear.
Then instead of a generic getParts you will have three methods getBelts, getCylinders and getGears.
If that is really not what you want then you can leave a comment.
UPDATE
You can solve it also with class inheritance. First make a base class Part that is also an entity and use it in the other classes Belt, Cylinder and Gear:
Part:
<?php
namespace Machine\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Part
*
* #ORM\Entity
* #ORM\Table("part")
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="discriminator", type="string")
* #ORM\DiscriminatorMap({
* "part" = "Part",
* "gear" = "Gear",
* "cylinder" = "Cylinder",
* "belt" = "Belt",
* })
* #property int $id
*/
class Part
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var Machine
* #ORM\ManyToOne(targetEntity="Machine\Entity\Machine", inversedBy="parts")
* #ORM\JoinColumn(name="machine_id", referencedColumnName="id", nullable=true)
*/
protected $machine;
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set id.
*
* #param int $id
* #return self
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
//... add setters and getters for machine as normal ...
}
Extend this class in your other parts:
Belt:
<?php
namespace Machine\Entity;
/**
* Belt
*
* #ORM\Entity
*/
class Belt extends Part
{
}
Cylinder:
<?php
namespace Machine\Entity;
/**
* Cylinder
*
* #ORM\Entity
*/
class Cylinder extends Part
{
}
Gear:
<?php
namespace Machine\Entity;
/**
* Gear
*
* #ORM\Entity
*/
class Gear extends Part
{
}
Now in your machine relate to the parts like as follows.
Machine:
<?php
namespace Machine\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Machine
*
* #ORM\Entity
* #ORM\Table("machine")
* #property int $id
*/
class Machine
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* Get id.
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set id.
*
* #param int $id
* #return self
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* #var Collection
* #ORM\OneToMany(targetEntity="Machine\Entity\Part", mappedBy="machine")
*/
protected $parts;
public function __constuct()
{
$parts = new ArrayCollection();
}
/**
*
* #return Collection
*/
public function getParts()
{
return $this->parts;
}
//... add setters and getters for parts as normal ...
}
Extend this class in your other parts:
Reading further in the Doctrine2 documentation in chapter 6.1. Mapped Superclasses (referred to by #Wilt):
... Furthermore Many-To-Many associations are only possible if the mapped superclass is only used in exactly one entity at the moment...
This means in this case the ORM mapping doesn't help. I cannot gather the data of all three entities MachineHasCylinder, MachineHasBelt and MachineHasGear through a MappedSupperclass at the same time.
I think using DQL or Native SQL is the only solution for this problem.
I'm usual working with symfony from the 2.1 or 2.2 versions.
Today i started a new project on the 2.3 and i'm encountering problems to create my custom entity repository.
My entity is:
<?php
namespace Acme\MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* AnnualProduction
*
* #ORM\Table(name="Annual_Production")
* #ORM\Entity(repositoryClass="Acme\MyBundle\Entity\AnnualproductionRepository")
*/
class AnnualProduction
{
/**
* #var string
*
* #ORM\Column(name="device_address", type="string", length=45, nullable=true)
*/
private $deviceAddress;
/**
* #var integer
*
* #ORM\Column(name="mese_1", type="integer", nullable=true)
*/
private $mese1;
/**
* #var integer
*
* #ORM\Column(name="mese_2", type="integer", nullable=true)
*/
SOME MISSING VAR SET AND GET
/**
* #var string
*
* #ORM\Column(name="sens_id", type="string", length=45)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $sensId;
/**
* #var \DateTime
*
* #ORM\Column(name="AAAA", type="date")
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $aaaa;
/**
* Set deviceAddress
*
* #param string $deviceAddress
* #return AnnualProduction
*/
public function setDeviceAddress($deviceAddress)
{
$this->deviceAddress = $deviceAddress;
return $this;
}
/**
* Get deviceAddress
*
* #return string
*/
public function getDeviceAddress()
{
return $this->deviceAddress;
}
/**
* Set mese1
*
* #param integer $mese1
* #return AnnualProduction
*/
public function setMese1($mese1)
{
$this->mese1 = $mese1;
return $this;
}
/**
* Get mese1
*
* #return integer
*/
public function getMese1()
{
return $this->mese1;
}
/**
* Set sensId
*
* #param string $sensId
* #return AnnualProduction
*/
public function setSensId($sensId)
{
$this->sensId = $sensId;
return $this;
}
/**
* Get sensId
*
* #return string
*/
public function getSensId()
{
return $this->sensId;
}
/**
* Set aaaa
*
* #param \DateTime $aaaa
* #return AnnualProduction
*/
public function setAaaa($aaaa)
{
$this->aaaa = $aaaa;
return $this;
}
/**
* Get aaaa
*
* #return \DateTime
*/
public function getAaaa()
{
return $this->aaaa;
}
}
I dont write all variable and get and sets functions.
I've created a repository file: Acme\MyBundle\Entity\AnnualproductionRepository.php
The code for the repository file is the following:
<?php
namespace Acme\MyBundle\Entity;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;
use Acme\MyBundle\Entity\AnnualProduction;
class AnnualproductionRepository extends EntityRepository
{
public function findByYearMonthDay($anno, $mese, $giorno, $sensId)
{
$query = $this->getEntityManager()
->createQuery(" SOME QUERY HERE")->setParameters(array(SOME PARAMETERS HERE));
return $query->getSingleResult();
}
}
I call the repository in one of my controller, with the following code:
<?php
namespace Acme\MyBundle\Controller;
use Acme\MyBundle\Entity\AnnualProduction;
use Acme\MyBundle\Entity;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints\Date;
class DataController extends Controller{
public function indexUserAction(){
*
*
*
*
*
$DailyProduction=$DailyProduction+$em->getRepository('AcmeMyBundle:AnnualProduction')->findByYearMonthDay($year, $month, $day, $productionSensor);
*
*
*
*
}
}
But i get this error like the repository doesnt exist and the controller get the function name like a default findBy* on one of the Entity attributes.
ERROR:
*> Entity 'Acme\MyBundle\Entity\AnnualProduction' has no field
'yearMonthDay'. You can therefore not call 'findByYearMonthDay' on the
entities' repository***
Have you some advise to solve this problem? the code seems to be identical to the one i usualy add to include custom entity repository in symfony 2.2 but for some reason it refuse to work.
Tx for your time and Help.
Problem Solved, the fact was that the entity.orm.xml files, stored in /src/acme/myBundle/config/doctrine, have an hight priority over the entity files, so every modification to the entity that i was doing wasent readed.
SOLUTION: Delete all the entity.orm.xml files after done the annotation ed the generation of the entity via terminal php command.
The namespace for your repository is wrong. You should have Acme\MyBundle\Entity\Repository for a namespace instead. The path to your file ought to then be Acme/MyBundle/Entity/Repository/AnnualProduction.
You should also let doctrine generate all your entities for you via
php app/console doctrine:generate:entities Acme
You will then see a folder called Repositories in your Entities folder and thats where all the entities need to be stored.
After I successfuly created TaskBundle with One-to-Many relation between category and tasks, now I'm trying to create a new TaskBundle with Many-to-Many relation. I get also problem with checking checkbox in this relation, but now it is not a primary problem (maybe after solving this). I deleted all tables, which is TaskBundle using and trying to create a new, but here is problem (description at the bottom).
My Task object:
<?php
namespace Acme\TaskBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="tasks")
*/
class Task
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=200)
* #Assert\NotBlank(
* message = "Task is empty"
* )
* #Assert\Length(
* min = "3",
* minMessage = "Task is too short"
* )
*/
protected $task;
/**
* #ORM\Column(type="datetime")
* #Assert\NotBlank()
* #Assert\Type("\DateTime")
*/
protected $dueDate;
/**
* #Assert\True(message = "You have to agree.")
*/
protected $accepted;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="categories")
*/
protected $category;
/**
* Constructor
*/
public function __construct()
{
$this->category = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set task
*
* #param string $task
* #return Task
*/
public function setTask($task)
{
$this->task = $task;
return $this;
}
/**
* Get task
*
* #return string
*/
public function getTask()
{
return $this->task;
}
/**
* Set dueDate
*
* #param \DateTime $dueDate
* #return Task
*/
public function setDueDate($dueDate)
{
$this->dueDate = $dueDate;
return $this;
}
/**
* Get dueDate
*
* #return \DateTime
*/
public function getDueDate()
{
return $this->dueDate;
}
/**
* Add category
*
* #param \Acme\TaskBundle\Entity\Category $category
* #return Task
*/
public function addCategory(\Acme\TaskBundle\Entity\Category $category)
{
$this->category[] = $category;
return $this;
}
/**
* Remove category
*
* #param \Acme\TaskBundle\Entity\Category $category
*/
public function removeCategory(\Acme\TaskBundle\Entity\Category $category)
{
$this->category->removeElement($category);
}
/**
* Get category
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategory()
{
return $this->category;
}
}
and Category object
<?php
namespace Acme\TaskBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="categories")
*/
class Category
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", length=200, unique=true)
* #Assert\NotNull(message="Categories cannot be empty", groups = {"adding"})
*/
protected $name;
/**
* #ORM\ManyToMany(targetEntity="Task", mappedBy="category")
*/
private $tasks;
public function __toString()
{
return strval($this->name);
}
/**
* Constructor
*/
public function __construct()
{
$this->tasks = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* 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;
}
/**
* 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;
}
}
So, after i put doctrine:schema:update --force i'll get error: Table 'symfony.categories' already exists. I've tried to delete all caches, but same problem. Any idea?
There's only problem, if it is as m2m relation.
PS: I was looking for this problem at the Google, but no one answers at this problem. There were only questions, but not correct answers, where the problem is and how to solve it.
Looks like you already have table named "categories" in that database. Remove this line #ORM\JoinTable(name="categories") and try without it.
P.S. "Categories" is really a strange name for join table. You should probably follow some conventions and let doctrine name it. Common names for join tables are category_task or category2task as they are more self-explanatory. Nothing that important, just trying to suggest what I consider good practice.
The thing is that doctrine doesn't understand how your existing table should be used. But you can give him some help.
You have two options :
You don't care about the existing table : simple, you can remove the #ORM\JoinTable(name="categories") annotation, and doctrine will create an other table etc.
You want to keep your existing table, which sounds pretty logical : you have to be more explicit in your annotation by adding #ORM\JoinColumn annotation.
Here is an example:
class
<?php
...
/**
* #ORM\Entity
* #ORM\Table(name="tasks")
*/
class Task
{
...
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="categories",
* joinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="task_id", referencedColumnName="id")})
*/
protected $category;
...
}
and Category object
<?php
...
/**
* #ORM\Entity
* #ORM\Table(name="categories")
*/
class Category
{
...
/**
* #ORM\ManyToMany(targetEntity="Task", mappedBy="category")
* #ORM\JoinTable(name="categories",
* joinColumns={#ORM\JoinColumn(name="task_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="category_id", referencedColumnName="id")})
*/
private $tasks;
...
Doing so, you will be able to keep your table without any doctrine error.
My fix for this, as far as I can tell, was a case-sensitivity issue with table names. Doctrine let me create a Users and a users table but afterwards would die on migrations:diff or migrations:migrate .
I used the -vvv option to get more detail on this error message; it seems that the error happens when Doctrine is loading up its own internal representation of the current database's schema. So if your current database has table names that Doctrine doesn't understand (like two tables that are identical, case-insensitive) then it will blow up in this fashion.
Seems like most of the answers above assume that the error is in your code, but in my case it was in the database.
I got this error with 2 ManyToMany targeting the same entity (User in the exemple below).
To create the table name doctrine use the entity and target entity name.
So in my case it was trying to create two time the table thread_user
To debug this it's easy. Just use the '#ORM\JoinTable' annotation and specify the table name.
Here is a working exemple.
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User")
* #ORM\JoinTable(name="thread_participant")
*/
private $participants;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\User")
* #ORM\JoinTable(name="thread_recipient")
*/
private $recipients;
in Symfony4.1 you can force the migration using the migration version
doctrine:migrations:execute <migration version>
ex
for migration version123456.php use
doctrine:migrations:execute 123456
there is another using the table name ,you can search it in your project . Maby be demo,I think it...
sorry for my chinese english !
Try to drop everything inside of your proxy directory.
I fix same issue after check other entities on each bundles, be aware of this.