Skip to content

Commit 992f64c

Browse files
committed
Merge branch 'master' of github.com:thecodingmachine/tdbm
2 parents 59e6d11 + 107cfa8 commit 992f64c

11 files changed

+229
-79
lines changed

src/Utils/BeanDescriptor.php

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ class BeanDescriptor implements BeanDescriptorInterface
106106
* @var ConfigurationInterface
107107
*/
108108
private $configuration;
109+
/**
110+
* @var BeanRegistry
111+
*/
112+
private $registry;
109113

110114
public function __construct(
111115
Table $table,
@@ -119,7 +123,8 @@ public function __construct(
119123
NamingStrategyInterface $namingStrategy,
120124
AnnotationParser $annotationParser,
121125
CodeGeneratorListenerInterface $codeGeneratorListener,
122-
ConfigurationInterface $configuration
126+
ConfigurationInterface $configuration,
127+
BeanRegistry $registry
123128
) {
124129
$this->table = $table;
125130
$this->beanNamespace = $beanNamespace;
@@ -133,10 +138,10 @@ public function __construct(
133138
$this->annotationParser = $annotationParser;
134139
$this->codeGeneratorListener = $codeGeneratorListener;
135140
$this->configuration = $configuration;
136-
$this->initBeanPropertyDescriptors();
141+
$this->registry = $registry;
137142
}
138143

139-
private function initBeanPropertyDescriptors(): void
144+
public function initBeanPropertyDescriptors(): void
140145
{
141146
$this->beanPropertyDescriptors = $this->getProperties($this->table);
142147
}
@@ -282,7 +287,7 @@ private function getPropertiesForTable(Table $table): array
282287
continue;
283288
}
284289

285-
$beanPropertyDescriptors[] = new ObjectBeanPropertyDescriptor($table, $fk, $this->namingStrategy, $this->beanNamespace, $this->annotationParser);
290+
$beanPropertyDescriptors[] = new ObjectBeanPropertyDescriptor($table, $fk, $this->namingStrategy, $this->beanNamespace, $this->annotationParser, $this->registry->getBeanForTableName($fk->getForeignTableName()));
286291
} else {
287292
$beanPropertyDescriptors[] = new ScalarBeanPropertyDescriptor($table, $column, $this->namingStrategy, $this->annotationParser);
288293
}
@@ -327,6 +332,7 @@ private function generateBeanConstructor() : MethodGenerator
327332

328333
$constructor = new MethodGenerator('__construct', [], MethodGenerator::FLAG_PUBLIC);
329334
$constructor->setDocBlock('The constructor takes all compulsory arguments.');
335+
$constructor->getDocBlock()->setWordWrap(false);
330336

331337
$assigns = [];
332338
$parentConstructorArguments = [];
@@ -761,13 +767,13 @@ public function generateDaoPhpCode(): ?FileGenerator
761767
[ new ParameterGenerator('obj', $beanClassName) ],
762768
MethodGenerator::FLAG_PUBLIC,
763769
'$this->tdbmService->save($obj);',
764-
new DocBlockGenerator(
770+
(new DocBlockGenerator(
765771
"Persist the $beanClassWithoutNameSpace instance.",
766772
null,
767773
[
768774
new ParamTag('obj', [$beanClassWithoutNameSpace], 'The bean to save.')
769775
]
770-
)
776+
))->setWordWrap(false)
771777
);
772778
$saveMethod->setReturnType('void');
773779

@@ -1035,7 +1041,7 @@ public function generateDaoPhpCode(): ?FileGenerator
10351041
],
10361042
MethodGenerator::FLAG_PROTECTED,
10371043
$findOneFromSqlMethodBody,
1038-
new DocBlockGenerator(
1044+
(new DocBlockGenerator(
10391045
"Get a single $beanClassWithoutNameSpace specified by its filters.",
10401046
"Unlike the `findOne` method that guesses the FROM part of the statement, here you can pass the \$from part.
10411047
@@ -1048,7 +1054,7 @@ public function generateDaoPhpCode(): ?FileGenerator
10481054
new ParamTag('parameters', ['mixed[]'], 'The parameters associated with the filter'),
10491055
new ReturnTag(['\\'.$beanClassName, 'null'])
10501056
]
1051-
)
1057+
))->setWordWrap(false)
10521058
);
10531059
$findOneFromSqlMethod->setReturnType("?$beanClassName");
10541060
$findOneFromSqlMethod = $this->codeGeneratorListener->onBaseDaoFindOneFromSqlGenerated($findOneFromSqlMethod, $this, $this->configuration, $class);
@@ -1183,13 +1189,14 @@ private function generateFindByDaoCodeForIndex(Index $index, string $beanNamespa
11831189
foreach ($columns as $column) {
11841190
$fk = $this->isPartOfForeignKey($this->table, $this->table->getColumn($column));
11851191
if ($fk !== null) {
1186-
if (!in_array($fk, $elements)) {
1187-
$elements[] = new ObjectBeanPropertyDescriptor($this->table, $fk, $this->namingStrategy, $this->beanNamespace, $this->annotationParser);
1192+
if (!isset($elements[$fk->getName()])) {
1193+
$elements[$fk->getName()] = new ObjectBeanPropertyDescriptor($this->table, $fk, $this->namingStrategy, $this->beanNamespace, $this->annotationParser, $this->registry->getBeanForTableName($fk->getForeignTableName()));
11881194
}
11891195
} else {
11901196
$elements[] = new ScalarBeanPropertyDescriptor($this->table, $this->table->getColumn($column), $this->namingStrategy, $this->annotationParser);
11911197
}
11921198
}
1199+
$elements = array_values($elements);
11931200

11941201
// If the index is actually only a foreign key, let's bypass it entirely.
11951202
if (count($elements) === 1 && $elements[0] instanceof ObjectBeanPropertyDescriptor) {

src/Utils/BeanRegistry.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
4+
namespace TheCodingMachine\TDBM\Utils;
5+
6+
use Doctrine\DBAL\Schema\Schema;
7+
use Doctrine\DBAL\Schema\Table;
8+
use TheCodingMachine\TDBM\ConfigurationInterface;
9+
use TheCodingMachine\TDBM\TDBMSchemaAnalyzer;
10+
11+
class BeanRegistry
12+
{
13+
/** @var BeanDescriptor[] table_name => BeanDescriptor */
14+
private $registry = [];
15+
/** @var ConfigurationInterface */
16+
private $configuration;
17+
/** @var Schema */
18+
private $schema;
19+
/** @var TDBMSchemaAnalyzer */
20+
private $tdbmSchemaAnalyzer;
21+
/** @var NamingStrategyInterface */
22+
private $namingStrategy;
23+
24+
/**
25+
* BeanRegistry constructor.
26+
* @param ConfigurationInterface $configuration
27+
* @param Schema $schema
28+
* @param TDBMSchemaAnalyzer $tdbmSchemaAnalyzer
29+
* @param NamingStrategyInterface $namingStrategy
30+
*/
31+
public function __construct(
32+
ConfigurationInterface $configuration,
33+
Schema $schema,
34+
TDBMSchemaAnalyzer $tdbmSchemaAnalyzer,
35+
NamingStrategyInterface $namingStrategy
36+
) {
37+
$this->configuration = $configuration;
38+
$this->schema = $schema;
39+
$this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer;
40+
$this->namingStrategy = $namingStrategy;
41+
}
42+
43+
public function hasBeanForTable(Table $table): bool
44+
{
45+
return isset($this->registry[$table->getName()]);
46+
}
47+
48+
public function addBeanForTable(Table $table): BeanDescriptor
49+
{
50+
if (!$this->hasBeanForTable($table)) {
51+
$this->registry[$table->getName()] = new BeanDescriptor(
52+
$table,
53+
$this->configuration->getBeanNamespace(),
54+
$this->configuration->getBeanNamespace() . '\\Generated',
55+
$this->configuration->getDaoNamespace(),
56+
$this->configuration->getDaoNamespace() . '\\Generated',
57+
$this->configuration->getSchemaAnalyzer(),
58+
$this->schema,
59+
$this->tdbmSchemaAnalyzer,
60+
$this->namingStrategy,
61+
$this->configuration->getAnnotationParser(),
62+
$this->configuration->getCodeGeneratorListener(),
63+
$this->configuration,
64+
$this
65+
);
66+
}
67+
return $this->getBeanForTableName($table->getName());
68+
}
69+
70+
public function getBeanForTableName(string $table): BeanDescriptor
71+
{
72+
return $this->registry[$table];
73+
}
74+
}

src/Utils/DirectForeignKeyMethodDescriptor.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ class DirectForeignKeyMethodDescriptor implements MethodDescriptorInterface
3636
* @var NamingStrategyInterface
3737
*/
3838
private $namingStrategy;
39-
/**
40-
* @var AnnotationParser
41-
*/
42-
private $annotationParser;
4339
/**
4440
* @var string
4541
*/
@@ -133,7 +129,7 @@ public function getCode() : array
133129
if ($this->hasLocalUniqueIndex()) {
134130
$getter->setDocBlock(sprintf('Returns the %s pointing to this bean via the %s column.', $beanClass, implode(', ', $this->foreignKey->getUnquotedLocalColumns())));
135131
$classType = '\\' . $this->beanNamespace . '\\' . $beanClass;
136-
$getter->getDocBlock()->setTag(new ReturnTag([$classType . '|null']));
132+
$getter->getDocBlock()->setTag(new ReturnTag([$classType . '|null']))->setWordWrap(false);
137133
$getter->setReturnType('?' . $classType);
138134

139135
$code = sprintf(
@@ -147,7 +143,7 @@ public function getCode() : array
147143
$getter->getDocBlock()->setTag(new ReturnTag([
148144
$beanClass . '[]',
149145
'\\' . AlterableResultIterator::class
150-
]));
146+
]))->setWordWrap(false);
151147
$getter->setReturnType(AlterableResultIterator::class);
152148

153149
$code = sprintf(

src/Utils/ForeignKeyAnalyzerTrait.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace TheCodingMachine\TDBM\Utils;
55

66
use Doctrine\DBAL\Schema\Column;
7+
use TheCodingMachine\TDBM\Utils\Annotation\AnnotationParser;
78
use TheCodingMachine\TDBM\Utils\Annotation\Annotations;
89

910
trait ForeignKeyAnalyzerTrait
@@ -16,6 +17,10 @@ trait ForeignKeyAnalyzerTrait
1617
* @var Column[]
1718
*/
1819
private $localColumns;
20+
/**
21+
* @var AnnotationParser
22+
*/
23+
private $annotationParser;
1924

2025
/**
2126
* @return Column[]

src/Utils/ObjectBeanPropertyDescriptor.php

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,35 @@ class ObjectBeanPropertyDescriptor extends AbstractBeanPropertyDescriptor
2828
* @var string
2929
*/
3030
private $beanNamespace;
31-
3231
/**
33-
* @var AnnotationParser
32+
* @var BeanDescriptor
3433
*/
35-
private $annotationParser;
34+
private $foreignBeanDescriptor;
3635

3736
/**
3837
* ObjectBeanPropertyDescriptor constructor.
3938
* @param Table $table
4039
* @param ForeignKeyConstraint $foreignKey
4140
* @param NamingStrategyInterface $namingStrategy
41+
* @param string $beanNamespace
42+
* @param AnnotationParser $annotationParser
43+
* @param BeanDescriptor $foreignBeanDescriptor The BeanDescriptor of FK foreign table
4244
*/
43-
public function __construct(Table $table, ForeignKeyConstraint $foreignKey, NamingStrategyInterface $namingStrategy, string $beanNamespace, AnnotationParser $annotationParser)
44-
{
45+
public function __construct(
46+
Table $table,
47+
ForeignKeyConstraint $foreignKey,
48+
NamingStrategyInterface $namingStrategy,
49+
string $beanNamespace,
50+
AnnotationParser $annotationParser,
51+
BeanDescriptor $foreignBeanDescriptor
52+
) {
4553
parent::__construct($table, $namingStrategy);
4654
$this->foreignKey = $foreignKey;
4755
$this->beanNamespace = $beanNamespace;
4856
$this->annotationParser = $annotationParser;
57+
$this->table = $table;
58+
$this->namingStrategy = $namingStrategy;
59+
$this->foreignBeanDescriptor = $foreignBeanDescriptor;
4960
}
5061

5162
/**
@@ -202,7 +213,7 @@ public function getJsonSerializeCode(): string
202213
return '';
203214
}
204215
$isIncluded = false;
205-
$format = "jsonSerialize(true)";
216+
$format = 'jsonSerialize(true)';
206217
} else {
207218
$isIncluded = $this->findAnnotation(Annotation\JsonInclude::class) !== null;
208219
/** @var Annotation\JsonFormat|null $jsonFormat */
@@ -220,20 +231,49 @@ public function getJsonSerializeCode(): string
220231
$index = $jsonKey ? $jsonKey->key : $this->namingStrategy->getJsonProperty($this);
221232
$getter = $this->getGetterName();
222233
if (!$this->isCompulsory()) {
223-
$code = "\$array['$index'] = (\$object = \$this->$getter()) ? \$object->$format : null;";
234+
$recursiveCode = "\$array['$index'] = (\$object = \$this->$getter()) ? \$object->$format : null;";
235+
$lazyCode = "\$array['$index'] = (\$object = \$this->$getter()) ? {$this->getLazySerializeCode('$object')} : null;";
224236
} else {
225-
$code = "\$array['$index'] = \$this->$getter()->$format;";
237+
$recursiveCode = "\$array['$index'] = \$this->$getter()->$format;";
238+
$lazyCode = "\$array['$index'] = {$this->getLazySerializeCode("\$this->$getter()")};";
226239
}
227-
if (!$isIncluded) {
240+
241+
if ($isIncluded) {
242+
$code = $recursiveCode;
243+
} else {
228244
$code = <<<PHP
229-
if (!\$stopRecursion) {
230-
$code
231-
};
245+
if (\$stopRecursion) {
246+
$lazyCode
247+
} else {
248+
$recursiveCode
249+
}
232250
PHP;
233251
}
234252
return $code;
235253
}
236254

255+
private function getLazySerializeCode(string $propertyAccess): string
256+
{
257+
$rows = [];
258+
foreach ($this->getForeignKey()->getUnquotedForeignColumns() as $column) {
259+
$descriptor = $this->getBeanPropertyDescriptor($column);
260+
$indexName = ltrim($descriptor->getVariableName(), '$');
261+
$columnGetterName = $descriptor->getGetterName();
262+
$rows[] = "'$indexName' => $propertyAccess->$columnGetterName()";
263+
}
264+
return '[' . implode(', ', $rows) . ']';
265+
}
266+
267+
private function getBeanPropertyDescriptor(string $column): AbstractBeanPropertyDescriptor
268+
{
269+
foreach ($this->foreignBeanDescriptor->getBeanPropertyDescriptors() as $descriptor) {
270+
if ($descriptor instanceof ScalarBeanPropertyDescriptor && $descriptor->getColumnName() === $column) {
271+
return $descriptor;
272+
}
273+
}
274+
throw new TDBMException('PropertyDescriptor for `'.$this->table->getName().'`.`' . $column . '` not found in `' . $this->foreignBeanDescriptor->getTable()->getName() . '`');
275+
}
276+
237277
/**
238278
* The code to past in the __clone method.
239279
* @return null|string

src/Utils/PivotTableMethodsDescriptor.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,28 +200,28 @@ public function getCode() : array
200200

201201
$getter = new MethodGenerator($this->getName());
202202
$getter->setDocBlock(sprintf('Returns the list of %s associated to this bean via the %s pivot table.', $remoteBeanName, $this->pivotTable->getName()));
203-
$getter->getDocBlock()->setTag(new ReturnTag([ $fqcnRemoteBeanName.'[]' ]));
203+
$getter->getDocBlock()->setTag(new ReturnTag([ $fqcnRemoteBeanName.'[]' ]))->setWordWrap(false);
204204
$getter->setReturnType('array');
205205
$getter->setBody(sprintf('return $this->_getRelationships(%s);', $pathKey));
206206

207207

208208
$adder = new MethodGenerator('add'.$singularName);
209209
$adder->setDocBlock(sprintf('Adds a relationship with %s associated to this bean via the %s pivot table.', $remoteBeanName, $this->pivotTable->getName()));
210-
$adder->getDocBlock()->setTag(new ParamTag($variableName, [ $fqcnRemoteBeanName ]));
210+
$adder->getDocBlock()->setTag(new ParamTag($variableName, [ $fqcnRemoteBeanName ]))->setWordWrap(false);
211211
$adder->setReturnType('void');
212212
$adder->setParameter(new ParameterGenerator($variableName, $fqcnRemoteBeanName));
213213
$adder->setBody(sprintf('$this->addRelationship(%s, $%s);', $localTableName, $variableName));
214214

215215
$remover = new MethodGenerator('remove'.$singularName);
216216
$remover->setDocBlock(sprintf('Deletes the relationship with %s associated to this bean via the %s pivot table.', $remoteBeanName, $this->pivotTable->getName()));
217-
$remover->getDocBlock()->setTag(new ParamTag($variableName, [ $fqcnRemoteBeanName ]));
217+
$remover->getDocBlock()->setTag(new ParamTag($variableName, [ $fqcnRemoteBeanName ]))->setWordWrap(false);
218218
$remover->setReturnType('void');
219219
$remover->setParameter(new ParameterGenerator($variableName, $fqcnRemoteBeanName));
220220
$remover->setBody(sprintf('$this->_removeRelationship(%s, $%s);', $localTableName, $variableName));
221221

222222
$has = new MethodGenerator('has'.$singularName);
223223
$has->setDocBlock(sprintf('Returns whether this bean is associated with %s via the %s pivot table.', $remoteBeanName, $this->pivotTable->getName()));
224-
$has->getDocBlock()->setTag(new ParamTag($variableName, [ $fqcnRemoteBeanName ]));
224+
$has->getDocBlock()->setTag(new ParamTag($variableName, [ $fqcnRemoteBeanName ]))->setWordWrap(false);
225225
$has->getDocBlock()->setTag(new ReturnTag([ 'bool' ]));
226226
$has->setReturnType('bool');
227227
$has->setParameter(new ParameterGenerator($variableName, $fqcnRemoteBeanName));
@@ -230,7 +230,7 @@ public function getCode() : array
230230
$setter = new MethodGenerator('set'.$pluralName);
231231
$setter->setDocBlock(sprintf('Sets all relationships with %s associated to this bean via the %s pivot table.
232232
Exiting relationships will be removed and replaced by the provided relationships.', $remoteBeanName, $this->pivotTable->getName()));
233-
$setter->getDocBlock()->setTag(new ParamTag($pluralVariableName, [ $fqcnRemoteBeanName.'[]' ]));
233+
$setter->getDocBlock()->setTag(new ParamTag($pluralVariableName, [ $fqcnRemoteBeanName.'[]' ]))->setWordWrap(false)->setWordWrap(false);
234234
$setter->getDocBlock()->setTag(new ReturnTag([ 'void' ]));
235235
$setter->setReturnType('void');
236236
$setter->setParameter(new ParameterGenerator($pluralVariableName, 'array'));

src/Utils/ScalarBeanPropertyDescriptor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ public function getGetterSetterCode(): array
235235
if ($isNullable) {
236236
$types[] = 'null';
237237
}
238-
$getter->getDocBlock()->setTag(new ReturnTag($types));
238+
$getter->getDocBlock()->setTag(new ReturnTag($types))->setWordWrap(false);
239239

240240
$getter->setReturnType($paramType);
241241

@@ -256,7 +256,7 @@ public function getGetterSetterCode(): array
256256
if ($isNullable) {
257257
$types[] = 'null';
258258
}
259-
$setter->getDocBlock()->setTag(new ParamTag($this->column->getName(), $types));
259+
$setter->getDocBlock()->setTag(new ParamTag($this->column->getName(), $types))->setWordWrap(false);
260260

261261
$parameter = new ParameterGenerator($this->column->getName(), $paramType);
262262
$setter->setParameter($parameter);

0 commit comments

Comments
 (0)