Skip to content

Commit b6356a9

Browse files
committed
Adding columns defined in actAs-templates to the docblock of the generated model class.
1 parent 33bebf2 commit b6356a9

File tree

2 files changed

+124
-23
lines changed

2 files changed

+124
-23
lines changed

lib/Doctrine/Import/Builder.php

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -396,12 +396,11 @@ public function buildTableDefinition(array $definition)
396396
/**
397397
* buildSetUp
398398
*
399-
* @param array $options
400-
* @param array $columns
401-
* @param array $relations
399+
* @param array $definition
400+
* @param array $actAsColumns
402401
* @return string
403402
*/
404-
public function buildSetUp(array $definition)
403+
public function buildSetUp(array $definition, array &$actAsColumns = array())
405404
{
406405
$ret = array();
407406
$i = 0;
@@ -483,7 +482,7 @@ public function buildSetUp(array $definition)
483482
}
484483

485484
if (isset($definition['actAs']) && is_array($definition['actAs']) && !empty($definition['actAs'])) {
486-
$ret[$i] = $this->buildActAs($definition['actAs']);
485+
$ret[$i] = $this->buildActAs($definition['actAs'], $actAsColumns);
487486
$i++;
488487
}
489488

@@ -640,8 +639,9 @@ public function buildAccessors(array $definition)
640639
* Build the phpDoc for a class definition
641640
*
642641
* @param array $definition
642+
* @param array $actAsColumns
643643
*/
644-
public function buildPhpDocs(array $definition)
644+
public function buildPhpDocs(array $definition, array $actAsColumns = array())
645645
{
646646
$ret = array();
647647
$ret[] = $definition['className'];
@@ -654,7 +654,7 @@ public function buildPhpDocs(array $definition)
654654
$setters = array();
655655

656656
if ((isset($definition['is_base_class']) && $definition['is_base_class']) || ! $this->generateBaseClasses()) {
657-
foreach ($definition['columns'] as $name => $column) {
657+
foreach (array_merge($definition['columns'], $actAsColumns) as $name => $column) {
658658
$name = isset($column['name']) ? $column['name']:$name;
659659
// extract column name & field name
660660
if (stripos($name, ' as '))
@@ -857,21 +857,33 @@ public function buildPhpDocs(array $definition)
857857
return $ret;
858858
}
859859

860+
/**
861+
* find class matching $name
862+
*
863+
* @param $name
864+
* @return string
865+
*/
866+
private function findTemplateClassMatchingName($name)
867+
{
868+
$classname = $name;
869+
if (class_exists("Doctrine_Template_$name", true)) {
870+
$classname = "Doctrine_Template_$name";
871+
}
872+
873+
return $classname;
874+
}
875+
860876
/**
861877
* emit a behavior assign
862878
*
863879
* @param int $level
864880
* @param string $name
865881
* @param string $option
882+
* @param string $classname
866883
* @return string assignation code
867884
*/
868-
private function emitAssign($level, $name, $option)
885+
private function emitAssign($level, $name, $option, $classname)
869886
{
870-
// find class matching $name
871-
$classname = $name;
872-
if (class_exists("Doctrine_Template_$name", true)) {
873-
$classname = "Doctrine_Template_$name";
874-
}
875887
return " \$" . strtolower($name) . "$level = new $classname($option);". PHP_EOL;
876888
}
877889

@@ -904,11 +916,12 @@ private function emitActAs($level, $name)
904916
/**
905917
* buildActAs: builds a complete actAs code. It supports hierarchy of plugins
906918
* @param array $actAs array of plugin definitions and options
919+
* @param array $actAsColumns contains on output an array of columns defined by actAs behaviors
907920
*/
908-
public function buildActAs($actAs)
921+
public function buildActAs($actAs, array &$actAsColumns = array())
909922
{
910923
$emittedActAs = array();
911-
$build = $this->innerBuildActAs($actAs, 0, null, $emittedActAs);
924+
$build = $this->innerBuildActAs($actAs, 0, null, $emittedActAs, $actAsColumns);
912925
foreach($emittedActAs as $str) {
913926
$build .= $str;
914927
}
@@ -922,9 +935,10 @@ public function buildActAs($actAs)
922935
* @param int $level current indentation level
923936
* @param string $parent name of the parent template/plugin
924937
* @param array $emittedActAs contains on output an array of actAs command to be appended to output
938+
* @param array $actAsColumns contains on output an array of columns defined by actAs behaviors
925939
* @return string actAs full definition
926940
*/
927-
private function innerBuildActAs($actAs, $level = 0, $parent = null, array &$emittedActAs = array())
941+
private function innerBuildActAs($actAs, $level = 0, $parent = null, array &$emittedActAs = array(), array &$actAsColumns = array())
928942
{
929943
// rewrite special case of actAs: [Behavior] which gave [0] => Behavior
930944
if (is_array($actAs) && isset($actAs[0]) && !is_array($actAs[0])) {
@@ -943,9 +957,10 @@ private function innerBuildActAs($actAs, $level = 0, $parent = null, array &$emi
943957
$currentParent = $parent;
944958
if (is_array($actAs)) {
945959
foreach($actAs as $template => $options) {
960+
$className = $this->findTemplateClassMatchingName($template);
946961
if ($template == 'actAs') {
947962
// found another actAs
948-
$build .= $this->innerBuildActAs($options, $level + 1, $parent, $emittedActAs);
963+
$build .= $this->innerBuildActAs($options, $level + 1, $parent, $emittedActAs, $actAsColumns);
949964
} else if (is_array($options)) {
950965
// remove actAs from options
951966
$realOptions = array();
@@ -959,17 +974,19 @@ private function innerBuildActAs($actAs, $level = 0, $parent = null, array &$emi
959974
}
960975

961976
$optionPHP = $this->varExport($realOptions);
962-
$build .= $this->emitAssign($level, $template, $optionPHP);
977+
$build .= $this->emitAssign($level, $template, $optionPHP, $className);
978+
$this->addActAsColumnsToDefinition($className, $realOptions, $actAsColumns);
963979
if ($level == 0) {
964980
$emittedActAs[] = $this->emitActAs($level, $template);
965981
} else {
966982
$build .= $this->emitAddChild($level, $currentParent, $template);
967983
}
968984
// descend for the remainings actAs
969985
$parent = $template;
970-
$build .= $this->innerBuildActAs($leftActAs, $level, $template, $emittedActAs);
986+
$build .= $this->innerBuildActAs($leftActAs, $level, $template, $emittedActAs, $actAsColumns);
971987
} else {
972-
$build .= $this->emitAssign($level, $template, null);
988+
$build .= $this->emitAssign($level, $template, null, $className);
989+
$this->addActAsColumnsToDefinition($className, array($options), $actAsColumns);
973990
if ($level == 0) {
974991
$emittedActAs[] = $this->emitActAs($level, $template);
975992
} else {
@@ -979,7 +996,9 @@ private function innerBuildActAs($actAs, $level = 0, $parent = null, array &$emi
979996
}
980997
}
981998
} else {
982-
$build .= $this->emitAssign($level, $actAs, null);
999+
$className = $this->findTemplateClassMatchingName($actAs);
1000+
$build .= $this->emitAssign($level, $actAs, null, $className);
1001+
$this->addActAsColumnsToDefinition($className, array(), $actAsColumns);
9831002
if ($level == 0) {
9841003
$emittedActAs[] = $this->emitActAs($level, $actAs);
9851004
} else {
@@ -990,6 +1009,56 @@ private function innerBuildActAs($actAs, $level = 0, $parent = null, array &$emi
9901009
return $build;
9911010
}
9921011

1012+
/**
1013+
* Adds the columns of the used actAs behaviors to the comment block.
1014+
*
1015+
* @param string $className
1016+
* @param array $instanceOptions
1017+
* @param array $actAsColumns
1018+
*
1019+
* @throws Doctrine_Import_Builder_Exception
1020+
*/
1021+
private function addActAsColumnsToDefinition($className, $instanceOptions, &$actAsColumns)
1022+
{
1023+
// No class specified or class does not exist.
1024+
if (!$className || !class_exists($className)) {
1025+
return;
1026+
}
1027+
1028+
$actAsInstance = new $className($instanceOptions);
1029+
$options = $actAsInstance->getOptions();
1030+
1031+
if (count($options) == 0) {
1032+
return;
1033+
}
1034+
1035+
// Some behaviors do not contain an array of columns, e.g. SoftDelete.
1036+
if (!is_array(reset($options))) {
1037+
$options = array($options);
1038+
}
1039+
1040+
foreach ($options as $name => $column) {
1041+
if (!is_array($column) || !array_key_exists('name', $column) || !array_key_exists('type', $column)) {
1042+
// 'name' or 'type' not found. Unfortunately there is no logger. What is the best way to abort here?
1043+
continue;
1044+
}
1045+
1046+
if (array_key_exists('disabled', $column) && $column['disabled']) {
1047+
// Column has been disabled.
1048+
continue;
1049+
}
1050+
1051+
// Add field, if it does not exist already.
1052+
if (
1053+
!array_key_exists($name, $actAsColumns)
1054+
&& !array_key_exists($column['name'], $actAsColumns)
1055+
) {
1056+
$actAsColumns[$name] = $column;
1057+
}
1058+
}
1059+
}
1060+
1061+
9931062
/**
9941063
* Build php code for adding record listeners
9951064
*
@@ -1122,9 +1191,10 @@ public function buildDefinition(array $definition)
11221191
$className = $definition['className'];
11231192
$extends = isset($definition['inheritance']['extends']) ? $definition['inheritance']['extends']:$this->_baseClassName;
11241193

1194+
$actAsColumns = array();
11251195
if ( ! (isset($definition['no_definition']) && $definition['no_definition'] === true)) {
11261196
$tableDefinitionCode = $this->buildTableDefinition($definition);
1127-
$setUpCode = $this->buildSetUp($definition);
1197+
$setUpCode = $this->buildSetUp($definition, $actAsColumns);
11281198
} else {
11291199
$tableDefinitionCode = null;
11301200
$setUpCode = null;
@@ -1136,7 +1206,7 @@ public function buildDefinition(array $definition)
11361206

11371207
$setUpCode.= $this->buildToString($definition);
11381208

1139-
$docs = PHP_EOL . $this->buildPhpDocs($definition);
1209+
$docs = PHP_EOL . $this->buildPhpDocs($definition, $actAsColumns);
11401210

11411211
$content = sprintf(self::$_tpl, $docs, $abstract,
11421212
$className,

tests/Ticket/gh110TestCase.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
class Doctrine_Ticket_gh110_TestCase extends Doctrine_UnitTestCase
4+
{
5+
public function testAddActAsColumnsToDocBlock()
6+
{
7+
$builder = new Doctrine_Import_Builder();
8+
$class = $builder->buildDefinition(
9+
array(
10+
'className' => 'Ticket_gh110_TestRecord',
11+
'topLevelClassName' => 'Ticket_gh110_TestRecord',
12+
'is_base_class' => true,
13+
'columns' => array(
14+
'id' => array(
15+
'type' => 'integer',
16+
'length' => 4,
17+
)
18+
),
19+
'actAs' => array(
20+
'SoftDelete' => array(),
21+
'Timestampable' => array(),
22+
)
23+
)
24+
);
25+
26+
$this->assertTrue(preg_match('/@property int\s*\$id/', $class));
27+
$this->assertTrue(preg_match('/@property string\s*\$deleted_at/', $class));
28+
$this->assertTrue(preg_match('/@property string\s*\$created_at/', $class));
29+
$this->assertTrue(preg_match('/@property string\s*\$updated_at/', $class));
30+
}
31+
}

0 commit comments

Comments
 (0)