Skip to content
This repository has been archived by the owner on Aug 19, 2020. It is now read-only.

Commit

Permalink
CRM-2557 renew composite ids on update
Browse files Browse the repository at this point in the history
  • Loading branch information
Felix Willmann committed Sep 21, 2016
1 parent 8303435 commit a9e4c49
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 21 deletions.
65 changes: 60 additions & 5 deletions src/CompositeNumberRangeBehavior.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

class CompositeNumberRangeBehavior extends Behavior
{
protected $compositeKeyColumnName;

protected $parameters = array(
'foreignTable' => null,
'refPhpName' => null,
Expand Down Expand Up @@ -73,7 +75,7 @@ public function modifyTable()
$table->setReloadOnInsert(true);

$foreignIdColumnName = $foreignTableName . '_id';
$compositeKeyColumnName = $foreignTableName . '_' . $tableName . '_id';
$this->compositeKeyColumnName = $foreignTableName . '_' . $tableName . '_id';

if ($table->hasBehavior('concrete_inheritance')) {
// we're a child in a concrete inheritance
Expand Down Expand Up @@ -111,19 +113,19 @@ public function modifyTable()

}

if ($table->hasColumn($compositeKeyColumnName)) {
$compositeKeyColumn = $table->getColumn($compositeKeyColumnName);
if ($table->hasColumn($this->compositeKeyColumnName)) {
$compositeKeyColumn = $table->getColumn($this->compositeKeyColumnName);
} else {
$compositeKeyColumn = $table->addColumn(
array(
'name' => $compositeKeyColumnName,
'name' => $this->compositeKeyColumnName,
'type' => 'integer',
'required' => false,
)
);
}

$index = new Unique($tableName . '_UQ_' . $foreignIdColumnName . '_' . $compositeKeyColumnName);
$index = new Unique($tableName . '_UQ_' . $foreignIdColumnName . '_' . $this->compositeKeyColumnName);
$index->addColumn($foreignIdColumn);
$index->addColumn($compositeKeyColumn);
$table->addUnique($index);
Expand Down Expand Up @@ -170,4 +172,57 @@ public function modifyTable()
);
}
}

public function postUpdate()
{
if ($this->parentHasBehaviour()) {
return null;
}
return "\$this->reloadAfterCompositeNumberUpdate();";
}

public function objectMethods($builder)
{
if ($this->parentHasBehaviour()) {
return null;
}

$this->builder = $builder;
$script = '';

$this->addReloadAfterCompositeNumberUpdate($script);

return $script;
}

private function addReloadAfterCompositeNumberUpdate(&$script)
{
$script .= <<<EOM
/**
* Reload object after updated composite number field
*/
public function reloadAfterCompositeNumberUpdate()
{
\$compositeNumberField = "{$this->compositeKeyColumnName}";
if (null === \$this->\$compositeNumberField) {
\$this->reload();
}
}
EOM;
}

private function parentHasBehaviour()
{
$table = $this->getTable();
if ($table->hasBehavior('concrete_inheritance')) {
$parentTableName = $table->getBehavior('concrete_inheritance')->getParameter('extends');
$parentTable = $table->getDatabase()->getTable($parentTableName);
if ($parentTable->hasBehavior('\\' . __CLASS__)) {
return true;
}
}
return false;
}

}
68 changes: 52 additions & 16 deletions src/Platform/MysqlPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,23 @@ class MysqlPlatform extends BaseMysqlPlatform
*
* @return string|null
*/
protected function getExistingTriggerName(Table $table)
protected function getExistingTriggerNames(Table $table)
{
$con = $this->getConnection();

echo "Checking the {$table->getName()} \n";

$sql = "SHOW TRIGGERS WHERE `Table` = ? AND `Trigger` LIKE 'set%Id'";
$stmt = $con->prepare($sql);
$stmt->execute([$table->getName()]);
$ret = $stmt->fetchAll();

$names = [];
foreach($ret as $trigger) {
$names []= $trigger['Trigger'];
}

return $stmt->fetchColumn();
return $names;
}

/**
Expand All @@ -40,7 +48,7 @@ public function getModifyTableDDL(TableDiff $tableDiff)
$fromTable = $tableDiff->getFromTable();
$toTable = $tableDiff->getToTable();

$hasTrigger = $this->hasTrigger($fromTable);
$hasTrigger = $this->hasTriggers($fromTable);

// if from-table has a trigger but to-table don't need it anymore, then drop it
$needDrop = $hasTrigger && !$this->hasCompositeNumberRangeBehavior($toTable);
Expand All @@ -50,10 +58,11 @@ public function getModifyTableDDL(TableDiff $tableDiff)

switch (true) {
case $needCreate:
$ret .= $this->createTriggerDDL($toTable);
$ret .= $this->createDropTriggersDDL($toTable);
$ret .= $this->createTriggersDDL($toTable);
break;
case $needDrop:
$ret .= $this->createDropTriggerDDL($toTable);
$ret .= $this->createDropTriggersDDL($toTable);
break;
}

Expand All @@ -68,9 +77,9 @@ public function getModifyTableDDL(TableDiff $tableDiff)
*
* @return bool
*/
protected function hasTrigger(Table $table)
protected function hasTriggers(Table $table)
{
return (boolean) $this->getExistingTriggerName($table);
return count($this->getExistingTriggerNames($table)) == 2;
}

/**
Expand Down Expand Up @@ -108,7 +117,7 @@ public function getAddTableDDL(Table $table)
$ret = parent::getAddTableDDL($table);

if ($this->hasCompositeNumberRangeBehavior($table)) {
$ret .= $this->createTriggerDDL($table);
$ret .= $this->createTriggersDDL($table);
}

return $ret;
Expand All @@ -121,11 +130,15 @@ public function getAddTableDDL(Table $table)
*
* @return string
*/
protected function createDropTriggerDDL(Table $table)
protected function createDropTriggersDDL(Table $table)
{
$triggerName = $this->getExistingTriggerName($table);
$triggerNames = $this->getExistingTriggerNames($table);

return "DROP TRIGGER IF EXISTS $triggerName;\n";
$sql = "";
foreach($triggerNames as $triggerName) {
$sql .= "DROP TRIGGER IF EXISTS $triggerName;\n";
}
return $sql;
}

/**
Expand All @@ -135,15 +148,18 @@ protected function createDropTriggerDDL(Table $table)
*
* @return string
*/
protected function getTriggerName(Table $table)
protected function getTriggerNames(Table $table)
{
$tableName = $table->getName();

/** @var CompositeNumberRangeBehavior $behavior */
$behavior = $table->getBehavior(self::BEHAVIOR_NAME);
$foreignTableName = $behavior->getForeignTable();

return str_replace(' ', '', ucwords(str_replace('_', ' ', 'set' . ucfirst($foreignTableName) . ucfirst($tableName) . 'Id')));
$insertTrigger = str_replace(' ', '', ucwords(str_replace('_', ' ', 'set' . ucfirst($foreignTableName) . ucfirst($tableName) . 'Id')));
$updateTrigger = str_replace(' ', '', ucwords(str_replace('_', ' ', 'setOnUpdate' . ucfirst($foreignTableName) . ucfirst($tableName) . 'Id')));

return [ $insertTrigger, $updateTrigger ];
}

/**
Expand All @@ -153,19 +169,19 @@ protected function getTriggerName(Table $table)
*
* @return string
*/
protected function createTriggerDDL(Table $table)
protected function createTriggersDDL(Table $table)
{

/** @var CompositeNumberRangeBehavior $behavior */
$behavior = $table->getBehavior(self::BEHAVIOR_NAME);
$foreignTableName = $behavior->getForeignTable();
$triggerName = $this->getTriggerName($table);
$triggerNames = $this->getTriggerNames($table);
$tableName = $table->getName();

$sql = "
DELIMITER $;
CREATE TRIGGER {$triggerName}
CREATE TRIGGER {$triggerNames[0]}
BEFORE INSERT ON ${tableName}
FOR EACH ROW
BEGIN
Expand All @@ -179,6 +195,26 @@ protected function createTriggerDDL(Table $table)
SET NEW.${foreignTableName}_${tableName}_id = LAST_INSERT_ID();
END
DELIMITER ;
DELIMITER $;
CREATE TRIGGER {$triggerNames[1]}
BEFORE UPDATE ON ${tableName}
FOR EACH ROW
BEGIN
IF NEW.${foreignTableName}_${tableName}_id IS NULL THEN
INSERT INTO ${foreignTableName}_sequence (
table_name, ${foreignTableName}_id, ${foreignTableName}_max_sequence_id
) VALUES (
'${tableName}', NEW.${foreignTableName}_id, LAST_INSERT_ID(1)
) ON DUPLICATE KEY
UPDATE ${foreignTableName}_max_sequence_id = LAST_INSERT_ID(${foreignTableName}_max_sequence_id +1);
SET NEW.${foreignTableName}_${tableName}_id = LAST_INSERT_ID();
END IF;
END
DELIMITER ;
";

Expand Down

0 comments on commit a9e4c49

Please sign in to comment.