Skip to content

Commit

Permalink
Merge pull request #647 from havvg/feature/versionable-one-to-one
Browse files Browse the repository at this point in the history
add one-to-one handling to VersionableBehavior
  • Loading branch information
willdurand committed Apr 9, 2013
2 parents 5b3ad51 + 0379f34 commit 11a8504
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 66 deletions.
73 changes: 50 additions & 23 deletions generator/lib/behavior/versionable/VersionableBehavior.php
Expand Up @@ -33,8 +33,12 @@ class VersionableBehavior extends Behavior
'version_comment_column' => 'version_comment'
);

/**
* @var Table
*/
protected $versionTable;

protected
$versionTable,
$objectBuilderModifier,
$queryBuilderModifier,
$peerBuilderModifier;
Expand Down Expand Up @@ -69,7 +73,7 @@ protected function addVersionColumn()
{
$table = $this->getTable();
// add the version column
if (!$table->containsColumn($this->getParameter('version_column'))) {
if (!$table->hasColumn($this->getParameter('version_column'))) {
$table->addColumn(array(
'name' => $this->getParameter('version_column'),
'type' => 'INTEGER',
Expand All @@ -81,20 +85,20 @@ protected function addVersionColumn()
protected function addLogColumns()
{
$table = $this->getTable();
if ($this->getParameter('log_created_at') == 'true' && !$table->containsColumn($this->getParameter('version_created_at_column'))) {
if ($this->getParameter('log_created_at') == 'true' && !$table->hasColumn($this->getParameter('version_created_at_column'))) {
$table->addColumn(array(
'name' => $this->getParameter('version_created_at_column'),
'type' => 'TIMESTAMP'
));
}
if ($this->getParameter('log_created_by') == 'true' && !$table->containsColumn($this->getParameter('version_created_by_column'))) {
if ($this->getParameter('log_created_by') == 'true' && !$table->hasColumn($this->getParameter('version_created_by_column'))) {
$table->addColumn(array(
'name' => $this->getParameter('version_created_by_column'),
'type' => 'VARCHAR',
'size' => 100
));
}
if ($this->getParameter('log_comment') == 'true' && !$table->containsColumn($this->getParameter('version_comment_column'))) {
if ($this->getParameter('log_comment') == 'true' && !$table->hasColumn($this->getParameter('version_comment_column'))) {
$table->addColumn(array(
'name' => $this->getParameter('version_comment_column'),
'type' => 'VARCHAR',
Expand Down Expand Up @@ -158,33 +162,40 @@ protected function addVersionTable()

public function addForeignKeyVersionColumns()
{
$table = $this->getTable();
$versionTable = $this->versionTable;
foreach ($this->getVersionableFks() as $fk) {
$fkVersionColumnName = $fk->getLocalColumnName() . '_version';
if (!$versionTable->containsColumn($fkVersionColumnName)) {
if (!$versionTable->hasColumn($fkVersionColumnName)) {
$versionTable->addColumn(array(
'name' => $fkVersionColumnName,
'type' => 'INTEGER',
'default' => 0
));
}
}

foreach ($this->getVersionableReferrers() as $fk) {
$fkTableName = $fk->getTable()->getName();
$fkIdsColumnName = $fkTableName . '_ids';
if (!$versionTable->containsColumn($fkIdsColumnName)) {
$versionTable->addColumn(array(
'name' => $fkIdsColumnName,
'type' => 'ARRAY'
));

if ($fk->isLocalPrimaryKey()) {
$columns = array(
$fkTableName . '_id' => $fk->getForeignColumn()->getType(),
$fkTableName . '_version' => 'INTEGER',
);
} else {
$columns = array(
$fkTableName . '_ids' => 'ARRAY',
$fkTableName . '_versions' => 'ARRAY',
);
}
$fkVersionsColumnName = $fkTableName . '_versions';
if (!$versionTable->containsColumn($fkVersionsColumnName)) {
$versionTable->addColumn(array(
'name' => $fkVersionsColumnName,
'type' => 'ARRAY'
));

foreach ($columns as $eachName => $eachType) {
if (!$versionTable->hasColumn($eachName)) {
$versionTable->addColumn(array(
'name' => $eachName,
'type' => $eachType,
));
}
}
}
}
Expand All @@ -199,6 +210,9 @@ public function getVersionTablePhpName()
return $this->getTable()->getPhpName() . 'Version';
}

/**
* @return ForeignKey[]
*/
public function getVersionableFks()
{
$versionableFKs = array();
Expand All @@ -213,6 +227,9 @@ public function getVersionableFks()
return $versionableFKs;
}

/**
* @return ForeignKey[]
*/
public function getVersionableReferrers()
{
$versionableReferrers = array();
Expand All @@ -230,17 +247,27 @@ public function getVersionableReferrers()
public function getReferrerIdsColumn(ForeignKey $fk)
{
$fkTableName = $fk->getTable()->getName();
$fkIdsColumnName = $fkTableName . '_ids';

return $this->versionTable->getColumn($fkIdsColumnName);
if ($fk->isLocalPrimaryKey()) {
$fkColumnName = $fkTableName . '_id';
} else {
$fkColumnName = $fkTableName . '_ids';
}

return $this->versionTable->getColumn($fkColumnName);
}

public function getReferrerVersionsColumn(ForeignKey $fk)
{
$fkTableName = $fk->getTable()->getName();
$fkIdsColumnName = $fkTableName . '_versions';

return $this->versionTable->getColumn($fkIdsColumnName);
if ($fk->isLocalPrimaryKey()) {
$fkColumnName = $fkTableName . '_version';
} else {
$fkColumnName = $fkTableName . '_versions';
}

return $this->versionTable->getColumn($fkColumnName);
}

public function getObjectBuilderModifier()
Expand Down
Expand Up @@ -16,9 +16,27 @@
*/
class VersionableBehaviorObjectBuilderModifier
{
protected $behavior, $table, $builder, $objectClassname, $peerClassname;
/**
* @var VersionableBehavior
*/
protected $behavior;

/**
* @var Table
*/
protected $table;

/**
* @var PHP5ObjectBuilder
*/
protected $builder;

/**
* @var string
*/
protected $objectClassname, $peerClassname;

public function __construct($behavior)
public function __construct(VersionableBehavior $behavior)
{
$this->behavior = $behavior;
$this->table = $behavior->getTable();
Expand Down Expand Up @@ -250,21 +268,45 @@ public function isVersioningNecessary(\$con = null)
}
";
}

foreach ($this->behavior->getVersionableReferrers() as $fk) {
$fkGetter = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
$script .= "
// to avoid infinite loops, emulate in save
\$this->alreadyInSave = true;
foreach (\$this->get{$fkGetter}(null, \$con) as \$relatedObject) {
if (\$relatedObject->isVersioningNecessary(\$con)) {
\$this->alreadyInSave = false;
if ($fk->isLocalPrimaryKey()) {
$fkGetter = $this->builder->getRefFKPhpNameAffix($fk);
$script .= "
if (\$this->single{$fkGetter}) {
// to avoid infinite loops, emulate in save
\$this->alreadyInSave = true;
if (\$this->single{$fkGetter}->isVersioningNecessary(\$con)) {
\$this->alreadyInSave = false;
return true;
}
\$this->alreadyInSave = false;
}
\$this->alreadyInSave = false;
";
} else {
$fkGetter = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
$script .= "
if (\$this->coll{$fkGetter}) {
// to avoid infinite loops, emulate in save
\$this->alreadyInSave = true;
foreach (\$this->get{$fkGetter}(null, \$con) as \$relatedObject) {
if (\$relatedObject->isVersioningNecessary(\$con)) {
\$this->alreadyInSave = false;
return true;
}
}
\$this->alreadyInSave = false;
}
";
}
}

$script .= "
return false;
Expand Down Expand Up @@ -305,15 +347,27 @@ public function addVersion(\$con = null)
}";
}
foreach ($this->behavior->getVersionableReferrers() as $fk) {
$fkGetter = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
$idsColumn = $this->behavior->getReferrerIdsColumn($fk);
$versionsColumn = $this->behavior->getReferrerVersionsColumn($fk);
$script .= "
if ($fk->isLocalPrimaryKey()) {
$fkGetter = $this->builder->getRefFKPhpNameAffix($fk);
$idColumn = $this->behavior->getReferrerIdsColumn($fk);
$versionColumn = $this->behavior->getReferrerVersionsColumn($fk);
$script .= "
if ((\$related = \$this->get{$fkGetter}(\$con)) && \$related->getVersion()) {
\$version->set{$idColumn->getPhpName()}(\$related->getPrimaryKey());
\$version->set{$versionColumn->getPhpName()}(\$related->getVersion());
}";
} else {
$fkGetter = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
$idsColumn = $this->behavior->getReferrerIdsColumn($fk);
$versionsColumn = $this->behavior->getReferrerVersionsColumn($fk);
$script .= "
if (\$relateds = \$this->get{$fkGetter}(\$con)->toKeyValue('{$fk->getTable()->getFirstPrimaryKeyColumn()->getPhpName()}', 'Version')) {
\$version->set{$idsColumn->getPhpName()}(array_keys(\$relateds));
\$version->set{$versionsColumn->getPhpName()}(array_values(\$relateds));
}";
}
}

$script .= "
\$version->save(\$con);
Expand Down Expand Up @@ -406,23 +460,51 @@ public function populateFromVersion(\$version, \$con = null, &\$loadedObjects =
}";
}
foreach ($this->behavior->getVersionableReferrers() as $fk) {
$fkPhpNames = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
$fkPhpName = $this->builder->getRefFKPhpNameAffix($fk, $plural = false);
$foreignTable = $fk->getTable();
$foreignBehavior = $foreignTable->getBehavior($this->behavior->getName());
$foreignVersionTable = $foreignBehavior->getVersionTable();
$fkColumnIds = $this->behavior->getReferrerIdsColumn($fk);
$fkColumnVersions = $this->behavior->getReferrerVersionsColumn($fk);
$fkColumn = $foreignVersionTable->getFirstPrimaryKeyColumn();
$fkVersionColumn = $foreignVersionTable->getColumn($this->behavior->getParameter('version_column'));

$relatedClassname = $this->builder->getNewStubObjectBuilder($foreignTable)->getClassname();

$relatedVersionQueryBuilder = $this->builder->getNewStubQueryBuilder($foreignVersionTable);
$this->builder->declareClassFromBuilder($relatedVersionQueryBuilder);
$relatedVersionQueryClassname = $relatedVersionQueryBuilder->getClassname();

$relatedVersionPeerBuilder = $this->builder->getNewStubPeerBuilder($foreignVersionTable);
$this->builder->declareClassFromBuilder($relatedVersionPeerBuilder);
$relatedVersionPeerClassname = $relatedVersionPeerBuilder->getClassname();
$relatedClassname = $this->builder->getNewStubObjectBuilder($foreignTable)->getClassname();
$fkColumn = $foreignVersionTable->getFirstPrimaryKeyColumn();
$fkVersionColumn = $foreignVersionTable->getColumn($this->behavior->getParameter('version_column'));
$script .= "

if ($fk->isLocalPrimaryKey()) {
$fkPhpName = $this->builder->getRefFKPhpNameAffix($fk, $plural = false);
$fkColumnId = $this->behavior->getReferrerIdsColumn($fk);
$fkColumnVersion = $this->behavior->getReferrerVersionsColumn($fk);
$fkColumnVersionPhpName = $fkColumnVersion->getPhpName();
$this->builder->declareClassFromBuilder($relatedVersionPeerBuilder);

$script .= "
if (\$fkValue = \$version->get{$fkColumnId->getPhpName()}()) {
if (isset(\$loadedObjects['{$relatedClassname}']) && isset(\$loadedObjects['{$relatedClassname}'][\$fkValue]) && isset(\$loadedObjects['{$relatedClassname}'][\$fkValue][\$version->get{$fkColumnVersionPhpName}()])) {
\$related = \$loadedObjects['{$relatedClassname}'][\$fkValue][\$version->get{$fkColumnVersionPhpName}()];
} else {
\$related = new {$relatedClassname}();
\$relatedVersion = {$relatedVersionQueryClassname}::create()
->filterBy{$fk->getLocalColumn()->getPhpName()}(\$fkValue)
->filterByVersion(\$version->get{$fkColumnVersionPhpName}())
->findOne(\$con);
\$related->populateFromVersion(\$relatedVersion, \$con, \$loadedObjects);
\$related->setNew(false);
}
\$this->set{$fkPhpName}(\$related);
}";
} else {
$fkPhpNames = $this->builder->getRefFKPhpNameAffix($fk, $plural = true);
$fkPhpName = $this->builder->getRefFKPhpNameAffix($fk, $plural = false);
$fkColumnIds = $this->behavior->getReferrerIdsColumn($fk);
$fkColumnVersions = $this->behavior->getReferrerVersionsColumn($fk);
$this->builder->declareClassFromBuilder($relatedVersionPeerBuilder);

$script .= "
if (\$fkValues = \$version->get{$fkColumnIds->getPhpName()}()) {
\$this->clear{$fkPhpNames}();
\$fkVersions = \$version->get{$fkColumnVersions->getPhpName()}();
Expand All @@ -446,7 +528,9 @@ public function populateFromVersion(\$version, \$con = null, &\$loadedObjects =
\$this->resetPartial{$fkPhpNames}(false);
}";
}
}

$script .= "
return \$this;
Expand Down
Expand Up @@ -18,7 +18,7 @@ class VersionableBehaviorQueryBuilderModifier
{
protected $behavior, $table, $builder, $objectClassname, $peerClassname;

public function __construct($behavior)
public function __construct(VersionableBehavior $behavior)
{
$this->behavior = $behavior;
$this->table = $behavior->getTable();
Expand Down

0 comments on commit 11a8504

Please sign in to comment.