Skip to content

Commit

Permalink
load databases without accessing classes (#1910)
Browse files Browse the repository at this point in the history
* load databases without accessing classes

* psalm-fix

* added table map psalm type

* stan fixes

* fixed unrelated stan error

* Update tests/Propel/Tests/Runtime/Map/DatabaseMapTest.php

Co-authored-by: Mark Scherer <dereuromark@users.noreply.github.com>

Co-authored-by: Mark Scherer <dereuromark@users.noreply.github.com>
  • Loading branch information
mringler and dereuromark committed Nov 15, 2022
1 parent f9b9e12 commit 1c8062d
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 64 deletions.
80 changes: 52 additions & 28 deletions src/Propel/Generator/Builder/Om/TableMapLoaderScriptBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
use Propel\Common\Util\PathTrait;
use Propel\Generator\Builder\Util\PropelTemplate;
use Propel\Generator\Config\GeneratorConfigInterface;
use Propel\Generator\Exception\BuildException;
use Propel\Generator\Model\Database;
use Propel\Generator\Model\Table;
use Propel\Runtime\Map\DatabaseMap;
use SplFileInfo;

/**
Expand Down Expand Up @@ -46,65 +49,86 @@ public function __construct(GeneratorConfigInterface $generatorConfig)
*/
public function build(array $schemas): string
{
$vars = $this->buildVars($schemas);
$templatePath = $this->getTemplatePath(__DIR__);

$filePath = $templatePath . 'tableMapLoaderScript.php';
$template = new PropelTemplate();
$template->setTemplateFile($filePath);

return $this->renderTemplate($vars);
$vars = [
'databaseNameToTableMapDumps' => $this->buildDatabaseNameToTableMapDumps($schemas),
];

return $template->render($vars);
}

/**
* @param array<\Propel\Generator\Model\Schema> $schemas
*
* @throws \Propel\Generator\Exception\BuildException
*
* @return array
*/
protected function buildVars(array $schemas): array
protected function buildDatabaseNameToTableMapDumps(array $schemas): array
{
$databaseNameToTableMapNames = [];

$entries = [];
foreach ($schemas as $schema) {
foreach ($schema->getDatabases(false) as $database) {
$databaseName = $database->getName();
$tableMapNames = array_map([$this, 'getFullyQualifiedTableMapClassName'], $database->getTables());
if (array_key_exists($databaseName, $databaseNameToTableMapNames)) {
$existing = $databaseNameToTableMapNames[$databaseName];
$tableMapNames = array_merge($existing, $tableMapNames);
if (!$databaseName) {
throw new BuildException('Cannot build table map of unnamed database');
}
sort($tableMapNames);
$databaseNameToTableMapNames[$databaseName] = $tableMapNames;
$tableMapDumps = $this->buildDatabaseMap($database)->dumpMaps();
$entries[] = [$databaseName => $tableMapDumps];
}
}
$databaseNameToTableMapDumps = array_merge_recursive(...$entries);
$this->sortRecursive($databaseNameToTableMapDumps);

return [
'databaseNameToTableMapNames' => $databaseNameToTableMapNames,
];
return $databaseNameToTableMapDumps;
}

/**
* @param \Propel\Generator\Model\Table $table
* @param \Propel\Generator\Model\Database $database
*
* @return string
* @return \Propel\Runtime\Map\DatabaseMap
*/
protected function getFullyQualifiedTableMapClassName(Table $table): string
protected function buildDatabaseMap(Database $database): DatabaseMap
{
$builder = new TableMapBuilder($table);
$builder->setGeneratorConfig($this->generatorConfig);
$databaseName = $database->getName();
$databaseMap = new DatabaseMap($databaseName);
foreach ($database->getTables() as $table) {
$tableName = $table->getName();
$phpName = $table->getPhpName();
$tableMapClass = $this->getFullyQualifiedTableMapClassName($table);
$databaseMap->registerTableMapClassByName($tableName, $phpName, $tableMapClass);
}

return $builder->getFullyQualifiedClassName();
return $databaseMap;
}

/**
* @param array $vars
* @param array $array
*
* @return string
* @return void
*/
protected function renderTemplate(array $vars): string
protected function sortRecursive(array &$array): void
{
$templatePath = $this->getTemplatePath(__DIR__);
ksort($array, SORT_STRING);
array_walk($array, fn (&$value) => is_array($value) && $this->sortRecursive($value));
}

$filePath = $templatePath . 'tableMapLoaderScript.php';
$template = new PropelTemplate();
$template->setTemplateFile($filePath);
/**
* @param \Propel\Generator\Model\Table $table
*
* @return string
*/
protected function getFullyQualifiedTableMapClassName(Table $table): string
{
$builder = new TableMapBuilder($table);
$builder->setGeneratorConfig($this->generatorConfig);

return $template->render($vars);
return $builder->getFullyQualifiedClassName();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Propel/Generator/Manager/AbstractManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use Propel\Generator\Exception\EngineException;
use Propel\Generator\Model\Database;
use Propel\Generator\Model\Schema;
use XsltProcessor;
use XSLTProcessor;

/**
* An abstract base Propel manager to perform work related to the XML schema
Expand Down Expand Up @@ -323,7 +323,7 @@ protected function loadDataModels(): void
// normalize the document using normalizer stylesheet
$xslDom = new DOMDocument('1.0', 'UTF-8');
$xslDom->load($this->xsl->getAbsolutePath());
$xsl = new XsltProcessor();
$xsl = new XSLTProcessor();
$xsl->importStyleSheet($xslDom);
$dom = $xsl->transformToDoc($dom);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Propel/Generator/Model/Table.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php

declare(strict_types=1);

/**
* MIT License. This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Propel\Generator\Model;

use Propel\Generator\Config\GeneratorConfigInterface;
Expand Down
6 changes: 3 additions & 3 deletions src/Propel/Generator/Reverse/SqliteSchemaParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,11 @@ protected function addColumns(Table $table): void

if (preg_match('/^([^\(]+)\(\s*(\d+)\s*,\s*(\d+)\s*\)$/', $fulltype, $matches)) {
$type = $matches[1];
$size = $matches[2];
$scale = $matches[3];
$size = (int)$matches[2];
$scale = (int)$matches[3];
} elseif (preg_match('/^([^\(]+)\(\s*(\d+)\s*\)$/', $fulltype, $matches)) {
$type = $matches[1];
$size = $matches[2];
$size = (int)$matches[2];
} else {
$type = $fulltype;
}
Expand Down
4 changes: 3 additions & 1 deletion src/Propel/Generator/Util/QuickBuilder.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?php declare(strict_types = 1);
<?php

/**
* MIT License. This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Propel\Generator\Util;

use Exception;
Expand Down
4 changes: 3 additions & 1 deletion src/Propel/Generator/Util/VfsTrait.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?php declare(strict_types = 1);
<?php

/**
* MIT License. This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Propel\Generator\Util;

use org\bovigo\vfs\vfsStream;
Expand Down
2 changes: 1 addition & 1 deletion src/Propel/Runtime/Connection/ConnectionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static function create(
): ConnectionInterface {
if (static::$useProfilerConnection) {
$connectionClass = ProfilerConnectionWrapper::class;
} else if (isset($configuration['classname'])) {
} elseif (isset($configuration['classname'])) {
$connectionClass = $configuration['classname'];
} else {
$connectionClass = $defaultConnectionClass;
Expand Down
71 changes: 65 additions & 6 deletions src/Propel/Runtime/Map/DatabaseMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
* @author Hans Lellelid <hans@xmpl.org> (Propel)
* @author John D. McNally <jmcnally@collab.net> (Torque)
* @author Daniel Rall <dlr@collab.net> (Torque)
*
* @psalm-consistent-constructor (instantiated by class name in StandardServiceContainer without arguments)
*
* @psalm-type \Propel\Runtime\Map\MapType = 'tablesByName' | 'tablesByPhpName'
* @psalm-type \Propel\Runtime\Map\TableMapDump array<\Propel\Runtime\Map\MapType, array<string, class-string<\Propel\Runtime\Map\TableMap>>>
*/
class DatabaseMap
{
Expand All @@ -38,14 +43,14 @@ class DatabaseMap
/**
* Tables in the database, using table name as key
*
* @var array<\Propel\Runtime\Map\TableMap|class-string<\Propel\Runtime\Map\TableMap>>
* @var array<string, \Propel\Runtime\Map\TableMap|class-string<\Propel\Runtime\Map\TableMap>>
*/
protected $tables = [];

/**
* Tables in the database, using table phpName as key
*
* @var array<\Propel\Runtime\Map\TableMap|class-string<\Propel\Runtime\Map\TableMap>>
* @var array<string, \Propel\Runtime\Map\TableMap|class-string<\Propel\Runtime\Map\TableMap>>
*/
protected $tablesByPhpName = [];

Expand Down Expand Up @@ -121,7 +126,7 @@ protected function addTableByPhpName(?string $phpName, $tableOrClassMap): void
/**
* Add a new table to the database, using the tablemap class name.
*
* @param string $tableMapClass The name of the table map to add
* @param class-string<\Propel\Runtime\Map\TableMap> $tableMapClass The name of the table map to add
*
* @return \Propel\Runtime\Map\TableMap The TableMap object
*/
Expand All @@ -134,6 +139,41 @@ public function addTableFromMapClass(string $tableMapClass): TableMap
return $this->getTable($table->getName());
}

/**
* Dump table maps. Used during configuration generation.
*
* @psalm-return \Propel\Runtime\Map\TableMapDump
*
* @return array<string, array<string, class-string<\Propel\Runtime\Map\TableMap>>> A dump that can be loaded again with {@link DatabaseMap::loadMapsFromDump()}
*/
public function dumpMaps(): array
{
/**
* @psalm-var \Closure( class-string<\Propel\Runtime\Map\TableMap>|\Propel\Runtime\Map\TableMap ): class-string<\Propel\Runtime\Map\TableMap>
*/
$toClassString = fn ($tableMap) => is_string($tableMap) ? $tableMap : get_class($tableMap);

return [
'tablesByName' => array_map($toClassString, $this->tables),
'tablesByPhpName' => array_map($toClassString, $this->tablesByPhpName),
];
}

/**
* Load internal table maps from dump. Used during Propel initialization.
*
* @psalm-param \Propel\Runtime\Map\TableMapDump $mapsDump
*
* @param array<string, array<string, class-string<\Propel\Runtime\Map\TableMap>>> $mapsDump Table map dump as created by {@link DatabaseMap::dumpMaps()}
*
* @return void
*/
public function loadMapsFromDump(array $mapsDump): void
{
$this->tables = $mapsDump['tablesByName'];
$this->tablesByPhpName = $mapsDump['tablesByPhpName'];
}

/**
* Registers a table map classes (by qualified name) as table belonging
* to this database.
Expand All @@ -150,17 +190,36 @@ public function addTableFromMapClass(string $tableMapClass): TableMap
public function registerTableMapClass(string $tableMapClass): void
{
$tableName = $tableMapClass::TABLE_NAME;
$this->tables[$tableName] = $tableMapClass;

$tablePhpName = $tableMapClass::TABLE_PHP_NAME;
$this->registerTableMapClassByName($tableName, $tablePhpName, $tableMapClass);
}

/**
* Registers a table map classes (by qualified name) as table belonging
* to this database.
*
* Classes added like this will only be instantiated when accessed
* through {@link DatabaseMap::getTable()},
* {@link DatabaseMap::getTableByPhpName()}, or
* {@link DatabaseMap::getTables()}
*
* @param string $tableName Internal name of the table, i.e. 'bookstore_schemas.book'
* @param string|null $tablePhpName PHP name of the table, i.e. 'Book'
* @param class-string<\Propel\Runtime\Map\TableMap> $tableMapClass The name of the table map to add
*
* @return void
*/
public function registerTableMapClassByName(string $tableName, ?string $tablePhpName, string $tableMapClass): void
{
$this->tables[$tableName] = $tableMapClass;
$this->addTableByPhpName($tablePhpName, $tableMapClass);
}

/**
* Registers a list of table map classes (by qualified name) as table maps
* belonging to this database.
*
* @param array<class-string> $tableMapClasses
* @param array<class-string<\Propel\Runtime\Map\TableMap>> $tableMapClasses
*
* @return void
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface ServiceContainerInterface
*
* @var string
*/
public const DEFAULT_DATABASE_MAP_CLASS = '\Propel\Runtime\Map\DatabaseMap';
public const DEFAULT_DATABASE_MAP_CLASS = DatabaseMap::class;

/**
* The name of the default datasource.
Expand All @@ -50,7 +50,7 @@ interface ServiceContainerInterface
*
* @var string
*/
public const DEFAULT_PROFILER_CLASS = '\Propel\Runtime\Util\Profiler';
public const DEFAULT_PROFILER_CLASS = Profiler::class;

/**
* @return string
Expand Down
Loading

0 comments on commit 1c8062d

Please sign in to comment.