Doctrine keeps updating DATETIME on update CURRENT_TIMESTAMP - symfony

I have parent entity class:
namespace App\Model\Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
*/
abstract class ParentEntity
{
/**
* #var int|null
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column(type="datetime", columnDefinition="DATETIME on update CURRENT_TIMESTAMP")
*/
protected $modifiedOn;
}
and everytime I run php bin/console o:s:u --dump-sql or --force the console prints out that X queries will be executed and every query is for modified_on column.
ALTER TABLE contact CHANGE modified_on modified_on DATETIME on update CURRENT_TIMESTAMP;
ALTER TABLE about_us CHANGE modified_on modified_on DATETIME on update CURRENT_TIMESTAMP;
ALTER TABLE image CHANGE modified_on modified_on DATETIME on update CURRENT_TIMESTAMP;
...
In MySQL database everything is setup correctly:
CREATE TABLE `about_us` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`modified_on` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
So my question is why is this happening? Did I miss some configuration/annotation for Doctrine? Or do you have to specify this attribute in some other way?

You are probably after Lifecycle Callbacks. if so this is the way to go:
namespace App\Model\Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\MappedSuperclass
* #ORM\HasLifecycleCallbacks
*/
abstract class ParentEntity
{
/**
* #var int|null
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\Column(type="datetime")
*/
protected $modifiedOn;
/**
* #ORM\PreUpdate
*/
public function setModifiedOn()
{
$this->modifiedOn = new \DateTime();
}
}

Related

How to modify Symfony ORM insert\update query

I have project that is migrate to Symfony, that project have multiple tables,and also some tables are migrated to ORM, but now i need to incert/update from Symfony to table that have Entity but not managed by ORM. Problem consist in not null columns that require some value and in Entity I cannot define that value because of table relations.
It posible to edit MySql query before they submited to Database.
For example i have Entity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="p_user")
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User
{
/**
* #var int
*
* #ORM\Column(name="user_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string|null
*
* #ORM\Column(name="name", type="string", length=55, nullable=true)
*/
private $name;
/**
* #var Permission
*
* #ORM\ManyToOne(targetEntity="Permission", inversedBy="user", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="permission_id", referencedColumnName="permission_id", onDelete="CASCADE")
*/
private $permission;
}
permission_id can be null but in database is not null with default value 0, same for name but with default value ''.
That mean when I make flush, ORM execute INSERT INTO p_user (name, permission_id) VALUES ('name', null), but I want also to execute INSERT INTO p_user (name) VALUES ('name').
It's possible to do that I wanted.
To achieve this you can provide default values.
private $permission = 0;
private $name = '';

NOT NULL if value is true in another column

I'm creating my entities and I want to create an entity with two columns that need to have a specific constraint. If addressId is defined, then extAddressId can be null (and it has to be null).
/**
* #ORM\Entity()
* #ORM\Table(name="widgets")
*/
class Widget
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $addressId;
/**
* #ORM\Column(type="integer")
*/
private $extAddressId;
}
I know how to do it with SQL but not with doctrine.
CREATE TABLE widgets
(
id integer,
addressId integer,
extAddressId integer,
CONSTRAINT if_addressId_then_extAddressId_is_not_null
CHECK ( (NOT addressId) OR (extAddressId IS NOT NULL) )
);
According to the documentation you can add check constraints like this :
/**
* #ORM\Column(type="integer", options={"check":"[your check condition]"})
*/
private $addressId;
/**
* #ORM\Column(type="integer", options={"check":"[your check condition]"})
*/
private $extAddressId;
Haven't tested myself.

Doctrine 2 one-to-one via composite key of both entities

I have a question similar to this one.
I need a relation one-to-one through composite key, is it possible? I've read about this but it's referred to one-to-many relation
class Header{
/**
*
* #ORM\Id
* #ORM\Column(name="UH1", type="integer", nullable=false)
*/
protected $key1;
/**
*
* #ORM\Id
* #ORM\Column(name="UH2", type="integer", nullable=false)
*/
protected $key2;
/**
* #ORM\OneToOne(targetEntity="Detail", mappedBy="header")
*/
protected $detail;
}
class Detail{
/**
*
* #ORM\Id
* #ORM\Column(name="UD1", type="integer", nullable=false)
*/
protected $key1;
/**
*
* #ORM\Id
* #ORM\Column(name="UD2", type="integer", nullable=false)
*/
protected $key2;
/**
* #ORM\OneToOne(targetEntity="Header", inversedBy="detail")
*/
protected $header;
}
I mean there are two columns as Id per entity... do i need to add the joincolumn ?
You need to use the JoinColumns annotation that allows to define an array of JoinColumn annotations to handle such cases for ManyToOne or OneToOne associations.
With the following entities:
AppBundle\Entity\A.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class A
{
/**
* #ORM\Id
* #ORM\Column(name="key1", type="integer", nullable=false)
*/
private $key1;
/**
* #ORM\Id
* #ORM\Column(name="key2", type="integer", nullable=false)
*/
private $key2;
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\B", mappedBy="a")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="key1", referencedColumnName="key1"),
* #ORM\JoinColumn(name="key2", referencedColumnName="key2"),
* )
*/
private $b;
}
AppBundle\Entity\B.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
*/
class B
{
/**
* #ORM\Id
* #ORM\Column(name="key1", type="integer", nullable=false)
*/
private $key1;
/**
* #ORM\Id
* #ORM\Column(name="key2", type="integer", nullable=false)
*/
private $key2;
/**
* #ORM\OneToOne(targetEntity="AppBundle\Entity\A", inversedBy="b")
* #ORM\JoinColumns(
* #ORM\JoinColumn(name="key1", referencedColumnName="key1"),
* #ORM\JoinColumn(name="key2", referencedColumnName="key2"),
* )
*/
private $a;
}
I could achieve the desired behaviour. When asked for a schema update, Doctrine outputs:
CREATE TABLE a (key1 INT NOT NULL, key2 INT NOT NULL, UNIQUE INDEX b_uniq (key1, key2), PRIMARY KEY(key1, key2)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE b (key1 INT NOT NULL, key2 INT NOT NULL, UNIQUE INDEX a_uniq (key1, key2), PRIMARY KEY(key1, key2)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE a ADD CONSTRAINT FK_E8B7BE432C5C6450B55535EA FOREIGN KEY (key1, key2) REFERENCES b (key1, key2);
ALTER TABLE b ADD CONSTRAINT FK_71BEEFF92C5C6450B55535EA FOREIGN KEY (key1, key2) REFERENCES a (key1, key2);

Doctrine wont generate columns for properites inherited from mapped super class

I have a mapped super class and two entities that extend that base class. I followed this docs, but when I run bin/console doctrine:schema:update both of my entities are generated only with the properties declared on the entity itself but not the ones declared in the mapped super class. What am I missing or doing wrong?
mapped super class:
<?php
namespace AppBundle\Model;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Entity\User;
/**
* #ORM\MappedSuperclass(repositoryClass="Doctrine\ORM\EntityRepository")
*/
class Comment {
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="comments")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $author;
/**
* #ORM\Column(name="content", type="text", length=500)
*/
private $content;
/**
* #ORM\Column(name="date", type="datetime")
*/
private $date;
// setters and getters...
}
extending entities:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Model\Comment;
/**
* #ORM\Entity
* #ORM\Table(name="component_comment")
*/
class ComponentComment extends Comment {
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="ComponentComment", inversedBy="replies")
* #ORM\JoinColumn(name="reply_to", referencedColumnName="id")
*/
private $replyTo;
/**
* #ORM\OneToMany(targetEntity="ComponentComment", mappedBy="replyTo")
*/
private $replies;
/**
* #ORM\ManyToOne(targetEntity="Component", inversedBy="comments")
* #ORM\JoinColumn(name="component", referencedColumnName="id")
*/
private $targetComponent;
// setters and getters...
}
and
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Model\Comment;
/**
* #ORM\Entity
* #ORM\Table(name="food_comment")
*/
class FoodComment extends Comment {
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="FoodComment", inversedBy="replies")
* #ORM\JoinColumn(name="reply_to", referencedColumnName="id")
*/
private $replyTo;
/**
* #ORM\OneToMany(targetEntity="FoodComment", mappedBy="replyTo")
*/
private $replies;
/**
* #ORM\ManyToOne(targetEntity="Food", inversedBy="comments")
* #ORM\JoinColumn(name="food", referencedColumnName="id")
*/
private $targetFood;
// setters and getters...
}
And my corresponding database tables look like:
CREATE TABLE `component_comment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`reply_to` int(11) DEFAULT NULL,
`component` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_2478D345E2B0FBEB` (`reply_to`),
KEY `IDX_2478D34549FEA157` (`component`),
CONSTRAINT `FK_2478D34549FEA157` FOREIGN KEY (`component`) REFERENCES `component` (`id`),
CONSTRAINT `FK_2478D345E2B0FBEB` FOREIGN KEY (`reply_to`) REFERENCES `component_comment` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `food_comment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`reply_to` int(11) DEFAULT NULL,
`food` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_DBEB8E54E2B0FBEB` (`reply_to`),
KEY `IDX_DBEB8E54D43829F7` (`food`),
CONSTRAINT `FK_DBEB8E54D43829F7` FOREIGN KEY (`food`) REFERENCES `food` (`id`),
CONSTRAINT `FK_DBEB8E54E2B0FBEB` FOREIGN KEY (`reply_to`) REFERENCES `food_comment` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
The columns from common properties inherited from the Comment parent class are missing. Why is wrong with my code?
I've fond an other solution that fits better my requirements, but I think I've figured out. I haven't tested it but very likely the problem is that the mapped super class has private properties instead of protected ones. So although they were mapped properly, the sub classes didn't inherit neither the properties nor the mappings belonging to them.
I think you should place the mapped superclass under AppBundle/Entity

Doctrine2 prevent default relation index

I have defined a new entity in symfony 2 using doctrine annotations. It has a many-to-one relation to another table and an unique index, using the same column (parent_id, subset_index):
/**
* #ORM\Table(name="mapping", uniqueConstraints={#ORM\UniqueConstraint(name="parent_subset_index", columns={"parent_id", "subset_index"})})
* #ORM\Entity
*/
class Mapping
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Record")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=false, onDelete="RESTRICT")
*/
private $parent;
/**
* #ORM\Column(name="subset_index", type="integer")
*/
private $subsetIndex;
}
A doctrine:migrations:diff generates the follwing MySQL statement:
CREATE TABLE mapping (
id INT AUTO_INCREMENT NOT NULL,
parent_id INT NOT NULL,
subset_index INT NOT NULL,
INDEX IDX_D87F7E0C727ACA70 (parent_id),
UNIQUE INDEX parent_subset_index (parent_id, subset_index),
PRIMARY KEY(id)
)
As you see I end up with two indices over parent_id, the IDX_D87F7E0C727ACA70 index is unnecessary.
How can I prevent doctrine from generating this index? I know I can edit the migration file, but then the index would be recreated everytime I run another doctrine:migrations:diff.

Resources