Skip to content

Commit eaa0e28

Browse files
committed
Generating DaoFactory with ZendCode
This enables us to modify DaoFactory generation on the fly. This is needed for #115.
1 parent 18f4b45 commit eaa0e28

File tree

5 files changed

+259
-69
lines changed

5 files changed

+259
-69
lines changed

src/Utils/BaseCodeGeneratorListener.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,36 @@ public function onBaseDaoFindByIndexGenerated(MethodGenerator $methodGenerator,
135135
{
136136
return $methodGenerator;
137137
}
138+
139+
/**
140+
* @param BeanDescriptor[] $beanDescriptors
141+
*/
142+
public function onDaoFactoryGenerated(FileGenerator $fileGenerator, array $beanDescriptors, ConfigurationInterface $configuration): ?FileGenerator
143+
{
144+
return $fileGenerator;
145+
}
146+
147+
/**
148+
* @param BeanDescriptor[] $beanDescriptors
149+
*/
150+
public function onDaoFactoryConstructorGenerated(MethodGenerator $methodGenerator, array $beanDescriptors, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator
151+
{
152+
return $methodGenerator;
153+
}
154+
155+
/**
156+
* @param BeanDescriptor[] $beanDescriptor
157+
*/
158+
public function onDaoFactoryGetterGenerated(MethodGenerator $methodGenerator, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator
159+
{
160+
return $methodGenerator;
161+
}
162+
163+
/**
164+
* @param BeanDescriptor[] $beanDescriptor
165+
*/
166+
public function onDaoFactorySetterGenerated(MethodGenerator $methodGenerator, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator
167+
{
168+
return $methodGenerator;
169+
}
138170
}

src/Utils/CodeGeneratorEventDispatcher.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,4 +263,60 @@ public function onBaseDaoFindByIndexGenerated(MethodGenerator $methodGenerator,
263263
}
264264
return $methodGenerator;
265265
}
266+
267+
/**
268+
* @param BeanDescriptor[] $beanDescriptors
269+
*/
270+
public function onDaoFactoryGenerated(FileGenerator $fileGenerator, array $beanDescriptors, ConfigurationInterface $configuration): ?FileGenerator
271+
{
272+
foreach ($this->listeners as $listener) {
273+
$fileGenerator = $listener->onDaoFactoryGenerated($fileGenerator, $beanDescriptors, $configuration);
274+
if ($fileGenerator === null) {
275+
break;
276+
}
277+
}
278+
return $fileGenerator;
279+
}
280+
281+
/**
282+
* @param BeanDescriptor[] $beanDescriptors
283+
*/
284+
public function onDaoFactoryConstructorGenerated(MethodGenerator $methodGenerator, array $beanDescriptors, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator
285+
{
286+
foreach ($this->listeners as $listener) {
287+
$methodGenerator = $listener->onDaoFactoryConstructorGenerated($methodGenerator, $beanDescriptors, $configuration, $classGenerator);
288+
if ($methodGenerator === null) {
289+
break;
290+
}
291+
}
292+
return $methodGenerator;
293+
}
294+
295+
/**
296+
* @param BeanDescriptor[] $beanDescriptor
297+
*/
298+
public function onDaoFactoryGetterGenerated(MethodGenerator $methodGenerator, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator
299+
{
300+
foreach ($this->listeners as $listener) {
301+
$methodGenerator = $listener->onDaoFactoryGetterGenerated($methodGenerator, $beanDescriptor, $configuration, $classGenerator);
302+
if ($methodGenerator === null) {
303+
break;
304+
}
305+
}
306+
return $methodGenerator;
307+
}
308+
309+
/**
310+
* @param BeanDescriptor[] $beanDescriptor
311+
*/
312+
public function onDaoFactorySetterGenerated(MethodGenerator $methodGenerator, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator
313+
{
314+
foreach ($this->listeners as $listener) {
315+
$methodGenerator = $listener->onDaoFactorySetterGenerated($methodGenerator, $beanDescriptor, $configuration, $classGenerator);
316+
if ($methodGenerator === null) {
317+
break;
318+
}
319+
}
320+
return $methodGenerator;
321+
}
266322
}

src/Utils/CodeGeneratorListenerInterface.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,24 @@ public function onBaseDaoFindOneFromSqlGenerated(MethodGenerator $methodGenerato
7979
public function onBaseDaoSetDefaultSortGenerated(MethodGenerator $methodGenerator, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator;
8080

8181
public function onBaseDaoFindByIndexGenerated(MethodGenerator $methodGenerator, Index $index, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator;
82+
83+
/**
84+
* @param BeanDescriptor[] $beanDescriptors
85+
*/
86+
public function onDaoFactoryGenerated(FileGenerator $fileGenerator, array $beanDescriptors, ConfigurationInterface $configuration): ?FileGenerator;
87+
88+
/**
89+
* @param BeanDescriptor[] $beanDescriptors
90+
*/
91+
public function onDaoFactoryConstructorGenerated(MethodGenerator $methodGenerator, array $beanDescriptors, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator;
92+
93+
/**
94+
* @param BeanDescriptor[] $beanDescriptor
95+
*/
96+
public function onDaoFactoryGetterGenerated(MethodGenerator $methodGenerator, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator;
97+
98+
/**
99+
* @param BeanDescriptor[] $beanDescriptor
100+
*/
101+
public function onDaoFactorySetterGenerated(MethodGenerator $methodGenerator, BeanDescriptor $beanDescriptor, ConfigurationInterface $configuration, ClassGenerator $classGenerator): ?MethodGenerator;
82102
}

src/Utils/TDBMDaoGenerator.php

Lines changed: 94 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,26 @@
77
use Doctrine\DBAL\Schema\Schema;
88
use Doctrine\DBAL\Schema\Table;
99
use Doctrine\DBAL\Types\Type;
10+
use Psr\Container\ContainerInterface;
11+
use TheCodingMachine\TDBM\Schema\ForeignKeys;
12+
use TheCodingMachine\TDBM\TDBMService;
13+
use Zend\Code\Generator\AbstractMemberGenerator;
14+
use Zend\Code\Generator\ClassGenerator;
15+
use Zend\Code\Generator\DocBlock\Tag\VarTag;
16+
use Zend\Code\Generator\DocBlockGenerator;
17+
use Zend\Code\Generator\FileGenerator;
18+
use Zend\Code\Generator\MethodGenerator;
19+
use Zend\Code\Generator\ParameterGenerator;
20+
use Zend\Code\Generator\PropertyGenerator;
1021
use function str_replace;
1122
use TheCodingMachine\TDBM\ConfigurationInterface;
1223
use TheCodingMachine\TDBM\TDBMException;
1324
use TheCodingMachine\TDBM\TDBMSchemaAnalyzer;
1425
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1526
use Symfony\Component\Filesystem\Filesystem;
27+
use function strpos;
28+
use function substr;
29+
use function var_export;
1630

1731
/**
1832
* This class generates automatically DAOs and Beans for TDBM.
@@ -88,7 +102,7 @@ public function generateAllDaosAndBeans(): void
88102
}
89103

90104

91-
$this->generateFactory($tableList);
105+
$this->generateFactory($beanDescriptors);
92106

93107
// Let's call the list of listeners
94108
$this->eventDispatcher->onGenerate($this->configuration, $beanDescriptors);
@@ -279,93 +293,104 @@ private function psr2Fix(string $content): string
279293
/**
280294
* Generates the factory bean.
281295
*
282-
* @param Table[] $tableList
296+
* @param BeanDescriptor[] $beanDescriptors
283297
* @throws TDBMException
284298
*/
285-
private function generateFactory(array $tableList) : void
299+
private function generateFactory(array $beanDescriptors) : void
286300
{
287301
$daoNamespace = $this->configuration->getDaoNamespace();
288302
$daoFactoryClassName = $this->namingStrategy->getDaoFactoryClassName();
289303

304+
$file = new FileGenerator();
305+
$file->setDocBlock(new DocBlockGenerator(<<<DOC
306+
This file has been automatically generated by TDBM.
307+
DO NOT edit this file, as it might be overwritten.
308+
DOC
309+
)
310+
);
311+
$class = new ClassGenerator();
312+
$file->setClass($class);
313+
$class->setName($daoFactoryClassName);
314+
$file->setNamespace($daoNamespace.'\\Generated');
315+
316+
$class->setDocBlock(new DocBlockGenerator("The $daoFactoryClassName provides an easy access to all DAOs generated by TDBM."));
317+
318+
$containerProperty = new PropertyGenerator('container');
319+
$containerProperty->setVisibility(AbstractMemberGenerator::VISIBILITY_PRIVATE);
320+
$containerProperty->setDocBlock(new DocBlockGenerator(null, null, [new VarTag(null, ['\\'.ContainerInterface::class])]));
321+
$class->addPropertyFromGenerator($containerProperty);
322+
323+
$constructorMethod = new MethodGenerator(
324+
'__construct',
325+
[ new ParameterGenerator('container', ContainerInterface::class) ],
326+
MethodGenerator::FLAG_PUBLIC,
327+
'$this->container = $container;'
328+
);
329+
$constructorMethod = $this->configuration->getCodeGeneratorListener()->onDaoFactoryConstructorGenerated($constructorMethod, $beanDescriptors, $this->configuration, $class);
330+
if ($constructorMethod !== null) {
331+
$class->addMethodFromGenerator($constructorMethod);
332+
}
333+
290334
// For each table, let's write a property.
335+
foreach ($beanDescriptors as $beanDescriptor) {
336+
$daoClassName = $beanDescriptor->getDaoClassName();
337+
$daoInstanceName = self::toVariableName($daoClassName);
291338

292-
$str = "<?php
293-
declare(strict_types=1);
339+
$daoInstanceProperty = new PropertyGenerator($daoInstanceName);
340+
$daoInstanceProperty->setVisibility(AbstractMemberGenerator::VISIBILITY_PRIVATE);
341+
$daoInstanceProperty->setDocBlock(new DocBlockGenerator(null, null, [new VarTag(null, ['\\' . $daoNamespace . '\\' . $daoClassName, 'null'])]));
342+
$class->addPropertyFromGenerator($daoInstanceProperty);
294343

295-
/*
296-
* This file has been automatically generated by TDBM.
297-
* DO NOT edit this file, as it might be overwritten.
298-
*/
344+
$fullClassNameVarExport = var_export($daoNamespace.'\\'.$daoClassName, true);
345+
$getterBody = <<<BODY
346+
if (!\$this->$daoInstanceName) {
347+
\$this->$daoInstanceName = \$this->container->get($fullClassNameVarExport);
348+
}
299349
300-
namespace {$daoNamespace}\\Generated;
350+
return \$this->$daoInstanceName;
351+
BODY;
352+
353+
$getterMethod = new MethodGenerator(
354+
'get' . $daoClassName,
355+
[],
356+
MethodGenerator::FLAG_PUBLIC,
357+
$getterBody
358+
);
359+
$getterMethod->setReturnType($daoNamespace.'\\'.$daoClassName);
360+
$getterMethod = $this->configuration->getCodeGeneratorListener()->onDaoFactoryGetterGenerated($getterMethod, $beanDescriptor, $this->configuration, $class);
361+
if ($getterMethod !== null) {
362+
$class->addMethodFromGenerator($getterMethod);
363+
}
301364

302-
use Psr\Container\ContainerInterface;
303-
";
304-
foreach ($tableList as $table) {
305-
$tableName = $table->getName();
306-
$daoClassName = $this->namingStrategy->getDaoClassName($tableName);
307-
$str .= "use {$daoNamespace}\\".$daoClassName.";\n";
365+
$setterMethod = new MethodGenerator(
366+
'set' . $daoClassName,
367+
[new ParameterGenerator($daoInstanceName, '\\' . $daoNamespace . '\\' . $daoClassName)],
368+
MethodGenerator::FLAG_PUBLIC,
369+
'$this->' . $daoInstanceName . ' = $' . $daoInstanceName . ';'
370+
);
371+
$setterMethod->setReturnType('void');
372+
$setterMethod = $this->configuration->getCodeGeneratorListener()->onDaoFactorySetterGenerated($setterMethod, $beanDescriptor, $this->configuration, $class);
373+
if ($setterMethod !== null) {
374+
$class->addMethodFromGenerator($setterMethod);
375+
}
308376
}
309377

310-
$str .= "
311-
/**
312-
* The $daoFactoryClassName provides an easy access to all DAOs generated by TDBM.
313-
*
314-
*/
315-
class $daoFactoryClassName
316-
{
317-
private \$container;
378+
$file = $this->configuration->getCodeGeneratorListener()->onDaoFactoryGenerated($file, $beanDescriptors, $this->configuration);
318379

319-
public function __construct(ContainerInterface \$container)
320-
{
321-
\$this->container = \$container;
322-
}
380+
if ($file !== null) {
381+
$possibleFileName = $this->configuration->getPathFinder()->getPath($daoNamespace.'\\Generated\\'.$daoFactoryClassName)->getPathname();
323382

383+
$fileContent = $file->generate();
324384

325-
";
326-
327-
foreach ($tableList as $table) {
328-
$tableName = $table->getName();
329-
$daoClassName = $this->namingStrategy->getDaoClassName($tableName);
330-
$daoInstanceName = self::toVariableName($daoClassName);
385+
// Hard code PSR-2 fix
386+
$fileContent = $this->psr2Fix($fileContent);
387+
// Add the declare strict-types directive
388+
$commentEnd = strpos($fileContent, ' */') + 3;
389+
$fileContent = substr($fileContent, 0, $commentEnd) . "\n\ndeclare(strict_types=1);" . substr($fileContent, $commentEnd + 1);
331390

332-
$str .= ' /**
333-
* @var '.$daoClassName.'|null
334-
*/
335-
private $'.$daoInstanceName.';
336-
337-
/**
338-
* Returns an instance of the '.$daoClassName.' class.
339-
*
340-
* @return '.$daoClassName.'
341-
*/
342-
public function get'.$daoClassName.'() : '.$daoClassName.'
343-
{
344-
if (!$this->'.$daoInstanceName.') {
345-
$this->'.$daoInstanceName.' = $this->container->get('.$daoClassName.'::class);
391+
$this->dumpFile($possibleFileName, $fileContent);
346392
}
347-
348-
return $this->'.$daoInstanceName.';
349-
}
350-
351-
/**
352-
* Override the instance of the '.$daoClassName.' class that will be returned by the factory getter.
353-
*
354-
* @param '.$daoClassName.' $'.$daoInstanceName.'
355-
*/
356-
public function set'.$daoClassName.'('.$daoClassName.' $'.$daoInstanceName.') : void
357-
{
358-
$this->'.$daoInstanceName.' = $'.$daoInstanceName.';
359-
}';
360-
}
361-
362-
$str .= '
363-
}
364-
';
365-
366-
$possibleFileName = $this->configuration->getPathFinder()->getPath($daoNamespace.'\\Generated\\'.$daoFactoryClassName)->getPathname();
367393

368-
$this->dumpFile($possibleFileName, $str);
369394
}
370395

371396
/**

0 commit comments

Comments
 (0)