I have some ManyToMany table relations.
I want to add a new column "created_at" automatically.
Following Symfony and Doctrine Documentation, i tired this :
app/config/services_dev.yaml
[...]
App\Event\Listener\ManyToManyListener:
tags:
- { name: doctrine.event_listener, event: onSchemaCreateTable }
app/src/Event/Listener/ManyToManyListener.php
[.....]
class ManyToManyListener implements EventSubscriber
{
public function getSubscribedEvents()
{
return ['onSchemaCreateTable'];
}
public function onSchemaCreateTable(SchemaCreateTableEventArgs $event)
{
$columns = $event->getTable()->getColumns();
if (count($columns) <= 2 && !array_key_exists("created_at", $columns)) {
$tableName = $event->getTable()->getName();
$sql = "ALTER TABLE $tableName ADD COLUMN created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP;";
$event->addSql($sql);
//dump($sql);
}
}
}
I can dump my SQL code inside, it works.
I also tried this code (inside the if statement)
$event->getTable()->addColumn(
"created_at",
"datetime",
["default" => "CURRENT_TIMESTAMP"]
);
This never execute the SQL statement.
For example, while php bin/console doctrine:schema:update --dump-sql
, I can't see my query.
I went through doctrine code and I understood that it was impossible to do what I wanted with those event because Event are dispatched AFTER the code path through columns, for example in Doctrine\DBAL\Platforms\AbstractPlatform
if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) {
$eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this);
$this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs);
if ($eventArgs->isDefaultPrevented()) {
return array_merge($eventArgs->getSql(), $columnSql);
}
}
So the only way with this event would have been to preventDefault
and create the SQL myself.
Looking through code, I found a better way :
I modify the schema generated by the Doctrine\ORM\Tools\SchemaTool->getSchemaFromMetadata
Not sure it's the best way but it perfectly works.
App\EventSubscriber\ManyToManyListener:
tags:
- { name: doctrine.event_listener, event: postGenerateSchema }
class SchemaGeneratorListener
{
public function postGenerateSchema(GenerateSchemaEventArgs $event)
{
$tables = $event->getSchema()->getTables();
foreach ($tables as $table) {
$columns = $table->getColumns();
if (count($columns) <= 2 && !array_key_exists("created_at", $columns)) {
$event->getSchema()->getTable($table->getName())->addColumn(
"created_at",
'datetime',
["default" => "CURRENT_TIMESTAMP"]
);
}
}
}
}