Doctrine 2 - ManyToOne Nullable relation not work - symfony

I have a strange error, on my Symfony4 project.
One of my relation is a ManyToOne with nullable true, like this:
class UserComic
{
...
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Series")
* #ORM\JoinColumn(name="id_series", referencedColumnName="id", nullable=true)
*/
private $series;
...
}
then I try to create a new UserComic with the $series attribute set to NULL, but i receive this error:
"Entity of type App\Entity\UserComic is missing an assigned ID for
field 'series'. 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."
As the field is not setted to nullable. Any advice?

ID means UNIQ and NOT NULLABLE.
You are on a ManyToOne relatsionship (on the many side) that break the UNIQ property of ID
You set the joinColumn as nullable, that breaks the NOT NULLABLE PROPERTY

Related

On delete of Parent entities - null the association on the other entity

I am trying to solve my issue on Doctrine ORM. I have 2 parent entities: CompanyDoctrineEntity and ServiceDoctrineEntity and 1 entity that are associated with these 2 (but the association is not required) OrderLinkRedirectLogDoctrineEntity. The association in OrderLinkRedirectLogDoctrineEntity is defined by:
class OrderLinkRedirectLogDoctrineEntity {
/**
* #Id
* #Column(type="integer")
* #ORM\GeneratedValue()
*
* #var int $id
*/
private $id;
/**
* Many logs have one company. This is the owning side.
*
* #ManyToOne(targetEntity="CompanyDoctrineEntity", cascade="detach")
* #JoinColumn(name="company_id", referencedColumnName="id")
*
* #var CompanyDoctrineEntity $company
*/
private $company;
/**
* Many logs have one service. This is the owning side.
*
* #ManyToOne(targetEntity="ServiceDoctrineEntity", cascade="detach")
* #JoinColumn(name="service_id", referencedColumnName="id")
*
* #var ServiceDoctrineEntity $service
*/
private $service;
}
My expected behaviour is, whenever either CompanyDoctrineEntity or ServiceDoctrineEntity is removed from the database, the association in the OrderLinkRedirectLogDoctrineEntity will be NULLed, which I believe what the cascade="detach" does, but for some reason, it's not working, as I am getting the following errors:
Fatal error: Uncaught PDOException: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`test_app2`.`logs_order_link_redirects`, CONSTRAINT `FK_6C1CA74CED5CA9E6` FOREIGN KEY (`service_id`) REFERENCES `app_services` (`id`)) in /Users/arvil/Projects/app2.test/public_html/wp-content/themes/app-theme/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117
Stack trace:
#0 /Users/arvil/Projects/app2.test/public_html/wp-content/themes/app-theme/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php(117): PDOStatement->execute(NULL)
#1 /Users/arvil/Projects/app2.test/public_html/wp-content/themes/app-theme/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(1054): Doctrine\DBAL\Driver\PDOStatement->execute()
#2 /Users/arvil/Projects/app2.test/public_html/wp-content/themes/app-theme/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(656): Doctrine\DBAL\Connection->exe in /Users/arvil/Projects/app2.test/public_html/wp-content/themes/app-theme/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php on line 49
I'm far from an expert on Doctrine, so take this with a grain of salt and test thoroughly.
Your relations are not nullable (defaults to false), which is why your foreign key constraint is complaining: logs_order_link_redirects.service_id (and company_id) isn't allowed to be null. That likely wasn't a problem before because you're not inserting the OrderLinkRedirectLogDoctrineEntity entities without the relationships. If you were to say
$redirectLog = new OrderLinkRedirectLogDoctrineEntity();
$entityManager->persist($redirectLog);
$entityManager->flush();
you'd probably trigger the same error immediately.
Also, I don't believe you want cascade={"detach"} here. Detach would just remove the entity from this entity manager instance (in other words: for the running process), so anything you'd do to the entity after detaching it wouldn't be reflected in the database when $entityManager->flush() is called. On the next request, the entity would be back in the entity manager.
I believe that adding nullable=true to your ManyToOne's JoinColumn annotations, e.g.
#JoinColumn(name="company_id", referencedColumnName="id", nullable=true)
will get you the result you're looking for. You'll need to update your database schema afterwards for changes to be applied to the tables. Also, make sure you don't have (or add) orphanRemoval=true on the inverse side so Doctrine doesn't automatically remove your entities if they lose their parent.
I prefer adding the JoinColumn annotation to relationships as well, even though it's not required if you're fine with Doctrine's default field name choices. Adding nullable=false makes it more explicit that this relationship cannot be null. That's implied if you don't have nullable=true, but when I start looking at relationships and need to know whether they can be null or not, I'm usually confused by something and I don't have mental energy to spare to actively remember the default values for important attributes.

Symfony2 misconfigured entity

I am getting two warnings about misconfigured entities in my Symfony 2 project. It runs fine in the development environment, but the production environment will not start and I suspect these misconfigured entities might be the reason.
It is the same error on both entities so I am only including one of them as an example.
BizTV\MediaManagementBundle\Entity\QrImage:
The field BizTV\MediaManagementBundle\Entity\QrImage#visits is on the inverse side of a bi-directional relationship, but the specified mappedBy association on the target-entity BizTV\MediaManagementBundle\Entity\QrVisit#QrImage does not contain the required 'inversedBy="visits"' attribute.
QrVisit entity:
class QrVisit
{
...
/**
* #var object BizTV\MediaManagementBundle\Entity\QrImage
*
* #ORM\ManyToOne(targetEntity="BizTV\MediaManagementBundle\Entity\QrImage")
* #ORM\JoinColumn(name="QrImage", referencedColumnName="id")
*/
protected $QrImage;
QrImage entity:
class QrImage
{
...
/**
* #ORM\OneToMany(targetEntity="BizTV\MediaManagementBundle\Entity\QrVisit", mappedBy="QrImage")
*/
private $visits;
I changed QrImage to include the inversedBy as below, but I probably did it wrong because I still get an error message, although a new one.
/**
* #ORM\OneToMany(targetEntity="BizTV\MediaManagementBundle\Entity\QrVisit", mappedBy="QrImage", inversedBy="visits")
*/
private $visits;
But this generates the error:
[Creation Error] The annotation #ORM\JoinColumn declared on property BizTV\UserBundle\Entity\UserGroup::$company does not have a property named "inversedBy". Available properties: name, referencedColumnName, unique, nullable, onDelete, columnDefinition, fieldName
If you want to establish a bi-directional ManyToOne / OneToMany relationship you'll have to put the mappedBy attribute on the OneToMany side like:
#ORM\OneToMany(targetEntity="BizTV\MediaManagementBundle\Entity\QrVisit", mappedBy="QrImage")
and the inversedBy on the ManyToOne side like:
#ORM\ManyToOne(targetEntity="BizTV\MediaManagementBundle\Entity\QrImage", inversedBy="visits")
that's all you need here. For your reference please check Doctrine doc
The error that you're getting refers to a different entity (UserGroup) but you can check them in the same fashion.

Doctrine: set foreign relation

This is regarding a problem with Doctrine when I try to insert a record into a associative entity. Below is a simplified description of the problem.
I have two tables, let's call them One and Two. Table One has a foreign key to table Two, called twoId with a column two_id. Field two_id happens to be part of the primary key.
* #ORM\Id
* #ORM\Column(name="user_id", type="string", length=40)
*/
private $twoId;
/**
* #ManyToOne(targetEntity="[...]", inversedBy="[...]", fetch="EAGER")
* #JoinColumn(name="two_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $two;
I am trying to insert a new record into table A. This works:
$two = [.. read from DB ..];
$one = new One();
$one->setTwo($two);
$one->setTwoId($two->getId());
$em->persist($one);
$em->flush();
I don't like to call both setTwo and setTwoId. Furthermore, I don't like reading the $two record before referencing it.
If I skip setTwoId call, I get the error: Entity of type [..] is missing an assigned ID for field 'twoId'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called.
If I skip setTwo call, I get the error: Integrity constraint violation: 1048 Column 'two_id' cannot be null
My problems are:
How can I avoid calling both setTwo() and setTwoId()?
What if I want to reference a entity from Two without reading it? Should I use $em->getReference()? (PhpStorm doesn't even recognize it)
In case someone makes the same mistake:
As pointed out by #lordrhodos, declaring the field $twoId was wrong because Doctrine will create it automatically without having a definition.
Definition:
/**
* #ManyToOne(targetEntity="[...]", inversedBy="[...]", fetch="EAGER")
* #JoinColumn(name="two_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $two;
Usage:
$two = [.. read from DB ..];
$one = new One();
$one->setTwo($two);
$em->persist($one);
$em->flush();

Semantical Error Symfony2

Hi I have an Entity name: Template
it containing 5-6 field with respective their getter/setter, defined.
But I am getting an semantical error as follows while fething data from this entity:
/**
* #var integer
*
* #ORM\Column(name="message_type", type="integer", nullable=false)
*/
private $messageType;
[Semantical Error] line 0, col 20 near 'message_type,': Error: Class MyuBundle\Entity\MyTemplate. has no field or association named message_type.
even the field "message_type" already defined in my entity and table in db.
any suggestion what could be the issue.
Thanks
we need to see the formType thats throwing the error to be 100%.
but looking at the snippet, you don't actually have a property message_type on that class. (the column name itself isn't used in mapping).
The likely error is caused by the fact that you've mapped a form field against a fieldname of message_type when it should be messageType.
provided you have a getter and setter for it you should be fine.
public function getMessageType()
public function setMessageType()
even the field "message_type" already defined in my entity and table in db.
this is not actually the case.

doctrine2: undefined index - many-to-one with non default referencedColumnName does not persist entity

I'm using Symfony 2.1.2.
I have two entities and define a [many-to-one (bidirectional)] (1) association between them. I don't want to use the primary key for the foreign key (referencedColumnName). I want to use another integer unique column: customer_no
/**
* #ORM\Entity
* #ORM\Table(name="t_myuser")
*/
class MyUser extends BaseEntity // provides an id (pk)
{
/**
* #ORM\ManyToOne(targetEntity="Customer", inversedBy="user")
* #ORM\JoinColumn(name="customer_no", referencedColumnName="customer_no", nullable=false)
*/
public $customer;
}
/**
* #ORM\Entity
* #ORM\Table(name="t_customer")
*/
class Customer extends BaseEntity // provides an id (pk)
{
/**
* #ORM\Column(type="integer", unique=true, nullable=false)
*/
public $customer_no;
/**
* #ORM\OneToMany(targetEntity="MyUser", mappedBy="customer")
*/
public $user;
}
When I try to persist a MyUser entity with an Customer entity, I get this error:
Notice: Undefined index: customer_no in ...\vendor\doctrine\orm\lib\Doctrine\ORM\Persisters\BasicEntityPersister.php line 608
The schema on the db looks fine, these should be the important sql schema definitions:
CREATE UNIQUE INDEX UNIQ_B4905AC83CDDA96E ON t_customer (customer_no);
CREATE INDEX IDX_BB041B3B3CDDA96E ON t_myuser (customer_no);
ALTER TABLE t_myuser ADD CONSTRAINT FK_BB041B3B3CDDA96E FOREIGN KEY (customer_no)
REFERENCES t_customer (customer_no) NOT DEFERRABLE INITIALLY IMMEDIATE;
So there is definitely an index for customer_no
//update:
I fix the inversedBy and mappedBy stuff, but this is not the problem.
(1) : http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional
#m2mdas:
Yes you're right, I thought it's possible because JPA (which has influence to doctrine) has this feature. The attribute referencedColumnName only for the case when your property does not match the table column.
Whatever, I found a solution by patching the BasicEntityPersister.php, see here the gist on github: https://gist.github.com/3800132
the solution is to add the property/field name and value for the mapping column. This information is already there but not bound to the right place. It have to be added to the $newValId arrray this way:
$fieldName = $targetClass->getFieldName($targetColumn);
$newValId[$fieldName] = $targetClass->getFieldValue($newVal, $fieldName);
It only works for ManyToOne reference. ManyToMany doesn't work.
For ManyToOne I test it with already existing entities. You can test it, too:
change the doctrine annotation in tests/Doctrine/Tests/Models/Legacy/LegacyArticle.php
from
#JoinColumn(name="iUserId", referencedColumnName="iUserId")
to
#JoinColumn(name="username", referencedColumnName="sUsername")

Resources