Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
100.00% |
1 / 1 |
|
100.00% |
11 / 11 |
CRAP | |
100.00% |
64 / 64 |
ReferenceListMigrator | |
100.00% |
1 / 1 |
|
100.00% |
11 / 11 |
29 | |
100.00% |
64 / 64 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
6 / 6 |
|||
createAlterStatementList | |
100.00% |
1 / 1 |
5 | |
100.00% |
11 / 11 |
|||
getConstraintByReference | |
100.00% |
1 / 1 |
3 | |
100.00% |
4 / 4 |
|||
createAlterStatement | |
100.00% |
1 / 1 |
3 | |
100.00% |
8 / 8 |
|||
compareMapping | |
100.00% |
1 / 1 |
6 | |
100.00% |
17 / 17 |
|||
areMappingIdentical | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
|||
getConstraintMappingByReferenceMapping | |
100.00% |
1 / 1 |
4 | |
100.00% |
4 / 4 |
|||
addDropConstraintStatement | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
addCreateReference | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
getAddForeignKeyStatementList | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getDropForeignKeyStatementList | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
<?php | |
declare(strict_types = 1); | |
namespace Siesta\Migration; | |
use Siesta\Database\MetaData\ConstraintMappingMetaData; | |
use Siesta\Database\MetaData\ConstraintMetaData; | |
use Siesta\Database\MigrationStatementFactory; | |
use Siesta\Model\Reference; | |
use Siesta\Model\ReferenceMapping; | |
/** | |
* @author Gregor Müller | |
*/ | |
class ReferenceListMigrator | |
{ | |
/** | |
* @var ConstraintMetaData[] | |
*/ | |
protected $constraintMetaDataList; | |
/** | |
* @var Reference[] | |
*/ | |
protected $referenceList; | |
/** | |
* @var MigrationStatementFactory | |
*/ | |
protected $migrationStatementFactory; | |
/** | |
* @var string[] | |
*/ | |
protected $dropForeignKeyStatementList; | |
/** | |
* @var string[] | |
*/ | |
protected $addForeignKeyStatementList; | |
/** | |
* ReferenceListMigrator constructor. | |
* | |
* @param MigrationStatementFactory $migrationStatementFactory | |
* @param ConstraintMetaData[] $constraintMetaDataList | |
* @param Reference[] $referenceList | |
*/ | |
public function __construct(MigrationStatementFactory $migrationStatementFactory, array $constraintMetaDataList, array $referenceList) | |
{ | |
$this->migrationStatementFactory = $migrationStatementFactory; | |
$this->constraintMetaDataList = $constraintMetaDataList; | |
$this->referenceList = $referenceList; | |
$this->addForeignKeyStatementList = []; | |
$this->dropForeignKeyStatementList = []; | |
} | |
/** | |
* compares the refernces (foreign key) found in the database with the definition in the model and creates alter | |
* statements for columns and foreign key constraints | |
* @return void | |
*/ | |
public function createAlterStatementList() | |
{ | |
$processedDatabaseList = []; | |
// iterate references from model and retrieve alter statements | |
foreach ($this->referenceList as $reference) { | |
// check if a corresponding database reference exists | |
$constraint = $this->getConstraintByReference($reference); | |
// retrieve alter statements and add them | |
$this->createAlterStatement($constraint, $reference); | |
// if a database reference has been found add it to the processed list | |
if ($constraint) { | |
$processedDatabaseList[] = $constraint->getConstraintName(); | |
} | |
} | |
// iterate references from database and retrieve alter statements | |
foreach ($this->constraintMetaDataList as $constraintMetaData) { | |
// check if reference has already been processed | |
if (in_array($constraintMetaData->getConstraintName(), $processedDatabaseList)) { | |
continue; | |
} | |
// no corresponding model reference will result in drop statements | |
$this->createAlterStatement($constraintMetaData, null); | |
} | |
} | |
/** | |
* @param Reference $reference | |
* | |
* @return null|ConstraintMetaData | |
*/ | |
private function getConstraintByReference(Reference $reference) | |
{ | |
foreach ($this->constraintMetaDataList as $constraintMetaData) { | |
if ($constraintMetaData->getConstraintName() === $reference->getConstraintName()) { | |
return $constraintMetaData; | |
} | |
} | |
return null; | |
} | |
/** | |
* @param ConstraintMetaData $constraintMetaData | |
* @param Reference $reference | |
*/ | |
private function createAlterStatement(ConstraintMetaData $constraintMetaData = null, Reference $reference = null) | |
{ | |
if ($constraintMetaData === null) { | |
$this->addCreateReference($reference); | |
return; | |
} | |
if ($reference === null) { | |
$this->addDropConstraintStatement($constraintMetaData); | |
return; | |
} | |
$this->compareMapping($constraintMetaData, $reference); | |
} | |
/** | |
* @param ConstraintMetaData $constraintMetaData | |
* @param Reference $reference | |
*/ | |
private function compareMapping(ConstraintMetaData $constraintMetaData, Reference $reference) | |
{ | |
// check if they are referencing the same column | |
if ($constraintMetaData->getForeignTable() !== $reference->getForeignTable()) { | |
$this->addDropConstraintStatement($constraintMetaData); | |
$this->addCreateReference($reference); | |
return; | |
} | |
if (sizeof($constraintMetaData->getConstraintMappingList()) !== sizeof($reference->getReferenceMappingList())) { | |
$this->addDropConstraintStatement($constraintMetaData); | |
$this->addCreateReference($reference); | |
return; | |
} | |
// modify columns if needed and check if the | |
if (!$this->areMappingIdentical($constraintMetaData, $reference)) { | |
$this->addDropConstraintStatement($constraintMetaData); | |
$this->addCreateReference($reference); | |
return; | |
} | |
// compare on update // >> drop constraint, add constraint | |
if ($constraintMetaData->getOnUpdate() === $reference->getOnUpdate() and $constraintMetaData->getOnDelete() === $reference->getOnDelete()) { | |
return; | |
} | |
$this->addCreateReference($reference); | |
$this->addDropConstraintStatement($constraintMetaData); | |
} | |
/** | |
* @param ConstraintMetaData $constraintMetaData | |
* @param Reference $reference | |
* | |
* @return bool | |
*/ | |
protected function areMappingIdentical(ConstraintMetaData $constraintMetaData, Reference $reference) : bool | |
{ | |
foreach ($reference->getReferenceMappingList() as $referenceMapping) { | |
$constraintMappingMetaDataList = $constraintMetaData->getConstraintMappingList(); | |
$constraintMappingMetaData = $this->getConstraintMappingByReferenceMapping($constraintMappingMetaDataList, $referenceMapping); | |
if ($constraintMappingMetaData === null) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* @param ConstraintMappingMetaData[] $constraintMappingList | |
* @param ReferenceMapping $referenceMapping | |
* | |
* @return ConstraintMappingMetaData|null | |
*/ | |
protected function getConstraintMappingByReferenceMapping(array $constraintMappingList, ReferenceMapping $referenceMapping) | |
{ | |
foreach ($constraintMappingList as $constraintMapping) { | |
if ($constraintMapping->getLocalColumn() === $referenceMapping->getLocalColumnName() && $constraintMapping->getForeignColumn() === $referenceMapping->getForeignColumnName()) { | |
return $constraintMapping; | |
} | |
} | |
return null; | |
} | |
/** | |
* @param ConstraintMetaData $constraintMetaData | |
*/ | |
private function addDropConstraintStatement(ConstraintMetaData $constraintMetaData) | |
{ | |
$dropList = $this->migrationStatementFactory->createDropConstraintStatement($constraintMetaData); | |
$this->dropForeignKeyStatementList = array_merge($this->dropForeignKeyStatementList, $dropList); | |
} | |
/** | |
* @param Reference $reference | |
*/ | |
private function addCreateReference(Reference $reference) | |
{ | |
$addList = $this->migrationStatementFactory->createAddReferenceStatement($reference); | |
$this->addForeignKeyStatementList = array_merge($this->addForeignKeyStatementList, $addList); | |
} | |
/** | |
* @return string[] | |
*/ | |
public function getAddForeignKeyStatementList() | |
{ | |
return $this->addForeignKeyStatementList; | |
} | |
/** | |
* @return string[] | |
*/ | |
public function getDropForeignKeyStatementList() | |
{ | |
return $this->dropForeignKeyStatementList; | |
} | |
} |