When I set a ManytoOne mapping, while both class in same namespace, it works.
but it won't work if the two class are in different namespace?
/**
* #ORM\ManyToOne(targetEntity="OP\ProjectBundle\Entity\Project", inversedBy="tickets")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
protected $project;
You have to use the absolute namespace of your target entity - note the leading backspace in its name.
/**
* #ORM\ManyToOne(targetEntity="\OP\ProjectBundle\Entity\Project", inversedBy="tickets")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
protected $project;
Related
I have a Person and Admin entity. One Person can only have one Admin, but I do not need admin all the time. When I list all people with admin associated, doctrine will load all admins from DB. Why is this happening?
In a case of one-to-one association (and in similar cases, e.g. while lazy loading one-to-many association) Doctrine generates so called proxy objects for associated entities. These proxy objects mimics interface of target entity but only triggers actual data loading from database upon access to non-id field.
Because of this in your case when you're fetching list of Person entities - you doesn't get list of Admin entities fetched from database, but receiving list of Admin proxies instead. Unless you will (occasionally or intentionally) try to access some of properties of Admin entity (with exception of its id which can be safely accessed) Doctrine will not try to fetch any Admin information from database.
Consider following simplified setup of A and B entities with one-to-one association:
// A.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class A
{
/**
* #var integer
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var B
* #ORM\OneToOne(targetEntity="App\Entity\B")
*/
private $b;
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #return B
*/
public function getB(): B
{
return $this->b;
}
}
// B.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class B
{
/**
* #var integer
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string|null
* #ORM\Column(type="string", nullable=true)
*/
private $name;
}
You can proof that A::$b contain proxy object by either looking into debugger or by using reflection:
$entities = $this->getEntityManager()->getRepository(\App\Entity\A::class)->findAll();
/** #var \App\Entity\A $a */
$a = array_shift($entities);
$class = (new \ReflectionObject($a->getB()))->getName();
In this case value of $class variable will be Proxies\__CG__\App\Entity\B (Doctrine proxy object for App\Entity\B) and not App\Entity\B as it would be in a case of normal entity object.
I have an entity with a OneToMany relation to itself (note that it uses single table inheritance).
/**
* #ORM\Table()
* #ORM\Entity()
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="discr", type="string", length=30)
**/
abstract class PlatformPost
{
// [...]
/**
* #var PlatformPost
*
* #ORM\ManyToOne(targetEntity="PlatformPost", inversedBy="comments")
*/
private $parent;
/**
* #var PlatformPost[]|Collection
*
* #ORM\OneToMany(targetEntity="PlatformPost", mappedBy="parent", orphanRemoval=true, cascade={"ALL"})
* #Assert\Valid()
*/
private $comments;
// [...]
}
I create this entity from an api and then persist it. If it already exists i use $em->merge($post) to update it.
This only kind of works. The entity I get from that method is exactly like I want it but doctrine does not update the foreign key of the comments. If I query the post again the comment array still contains the old entities which should have been deleted.
A quick solution would be to remove all comments before merging but i'd like a better solution.
Is it possible to have One-To-One Relationships in Flow without having to set the attributes twice?
I have two tables that are connected in a One-To-One Relationship, but only one of them should contain an extra column for this Relation.
Doctrine clearly supports this behavior:
http://doctrine-orm.readthedocs.org/en/latest/reference/association-mapping.html#one-to-one-bidirectional
The class that should come with a componenttape column:
/**
* #Flow\Entity
*/
class Component{
/**
* #var \Some\Package\Domain\Model\Component\Tape
* #ORM\OneToOne(cascade={"all"}, inversedBy="component")
*/
protected $componentTape;
…
}
The class that should just be able to find the connection without an extra column:
/**
* #Flow\Entity
*/
class Tape{
/**
* #var \ Some\Package\Domain\Model\Component
* #ORM\OneToOne(mappedBy="componentTape")
*/
protected $component;
}
A doctrine update will create extra columns for both models.
This is what my workarround at the moment looks like:
class Component{
..
/**
* #param \Some\Package\Domain\Model\Component\Tape $componentTape
* #return void
*/
public function setComponentTape($componentTape) {
$this->componentTape = $componentTape;
$this->componentTape->setComponent($this);
}
The workaround will be necessary anyway to keep the relation correct at all times during a request.
But the second DB column shouldn't be necessary. Did you check if doctrine actually fills it? Maybe/Probably just the created migration is wrong and the component column in Tape can be omitted.
Does your workaround stil work for you?
In my case, I have to update the ComponentTape model on the repository by self:
class Component {
/**
* #param \Some\Package\Domain\Model\Component\Tape $componentTape
* #return void
*/
public function setComponentTape($componentTape) {
$this->componentTape = $componentTape;
$this->componentTape->setComponent($this);
$this->componentTapeRepository->update($this->componentTape);
}
I’m trying to set up a Base-class for my Typo3 Flow projects. It should contain the “created at” and the “updated at” date.
Since Doctrine allows you to use inheritance mapping, I want to make my baseclass a “MappedSuperclass”.
BaseClass.php:
/**
* #Flow\Entity
* #ORM\MappedSuperclass
*/
class BaseClass {
/**
* #var \DateTime
* #ORM\Column(type="datetime")
*/
protected $created;
/**
* #var \DateTime
* #ORM\Column(type="datetime")
*/
protected $updated;
...
Component.php:
/**
* #Flow\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
*/
class Component extends BaseClass{
If i try to use the "flow doctrine:update" command the following error message pops up:
Uncaught Exception
Entity '...\Domain\Model\BaseClass' has no method
'Flow_Aop_Proxy_fixMethodsAndAdvicesArrayForDoctrineProxies' to be
registered as lifecycle callback.
So is it possible to use model inheritance in TYPO3 Flow?
I found out one way to do it.
Just make your BaseClass abstract and add all the additional annotations like this:
/**
* #Flow\Entity
* #ORM\MappedSuperclass
*/
abstract class BaseClass {
And extend your models like that:
/**
* #Flow\Entity
* #ORM\InheritanceType("SINGLE_TABLE")
*/
class SomeModel extends BaseClass{
The table of SomeModel will now have the attributes from the BaseClass. But BaseClass itself is not represented in the database schema.
Maybe you are also able to use traits for more complex solutions.
I am using doctrine 2 in zend framework 2. Below is my entity file. The problem is, when I tried to validate schema using,
./vendor/bin/doctrine-module orm:validate-schema
command.
I am getting error,
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'database.opportunitycriteria' already exists.
What should I do?
namespace Administration\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* OpportunityCriteria
*
* #ORM\Table(name="OpportunityCriteria")
* #ORM\Entity
*/
class Criteria
{
/**
* #var integer
* #ORM\Id
* #ORM\Column(name="criteria_id", type="integer", nullable=false)
*/
private $criteria_id;
/**
* #var string
*
* #ORM\Column(name="description", type="string", nullable=false)
*/
private $description;
}
and appropriate getter and setter methods..
I finally figured it out. OP's use case may be different, but in my case, this was because of a misconfigured bidirectional many-to-many relationship.
I had the following entities:
class Cuisine {
/**
* #ManyToMany(targetEntity="Dish")
* #ORM\JoinTable(name="CuisineDish", ...)
*/
protected $dishes;
}
class Dish {
/**
* #ORM\ManyToMany(targetEntity="Cuisine")
* #ORM\JoinTable(name="CuisineDish", ...)
*/
protected $cuisines;
}
What was missing was the inversedBy and mappedBy properties of the #ManyToMany annotations. These are only required when the association is bi-directional.
So now the correctly mapped entities look like:
class Cuisine {
/**
* #ManyToMany(targetEntity="Dish", inversedBy="cuisines")
* #ORM\JoinTable(name="CuisineDish", )
*/
protected $dishes;
}
class Dish {
/**
* #ORM\ManyToMany(targetEntity="Cuisine", mappedBy="dishes")
* #ORM\JoinTable(name="CuisineDish", ...)
*/
protected $cuisines;
}
And orm:validate-schema does not exit with an exception any more.
The exception message is just misleading, as the database is not altered by this operation. Furthermore, this issue is only spotted when validating the sync with the database, not when validating the mapping only (--skip-sync), where it should.
I just reported this bug.
it can cause this error message if you want to use a table name which is already used by one of the installed bundles.