Skip to content

Commit

Permalink
added type to store UUIDs as binary (UUID_BINARY)
Browse files Browse the repository at this point in the history
  • Loading branch information
mringler committed Nov 24, 2022
1 parent b35fb89 commit e705c03
Show file tree
Hide file tree
Showing 35 changed files with 826 additions and 67 deletions.
38 changes: 38 additions & 0 deletions src/Propel/Generator/Builder/Om/AbstractOMBuilder.php
Expand Up @@ -14,10 +14,12 @@
use Propel\Generator\Exception\InvalidArgumentException;
use Propel\Generator\Exception\LogicException;
use Propel\Generator\Exception\RuntimeException;
use Propel\Generator\Exception\SchemaException;
use Propel\Generator\Model\Column;
use Propel\Generator\Model\CrossForeignKeys;
use Propel\Generator\Model\ForeignKey;
use Propel\Generator\Model\Table;
use Propel\Generator\Model\VendorInfo;

/**
* Baseclass for OM-building classes.
Expand Down Expand Up @@ -1189,4 +1191,40 @@ abstract protected function addClassBody(string &$script): void;
* @return void
*/
abstract protected function addClassClose(string &$script): void;

/**
* Returns the vendor info from the table for the configured platform.
*
* @return \Propel\Generator\Model\VendorInfo
*/
protected function getVendorInfo(): VendorInfo
{
$dbVendorId = $this->getPlatform()->getDatabaseType();

return $this->getTable()->getVendorInfoForType($dbVendorId);
}

/**
* Returns the value for the uuid swap flag as set in the vendor information
* block in schema.xml as a literal ('true' or 'false').
*
* @psalm-return 'true'|'false'
*
* @see \Propel\Runtime\Util\UuidConverter::uuidToBin()
*
* @throws \Propel\Generator\Exception\SchemaException
*
* @return string
*/
protected function getUuidSwapFlagLiteral(): string
{
$vendorInformation = $this->getVendorInfo();

$uuidSwapFlag = $vendorInformation->getParameter('UuidSwapFlag') ?? 'true';
if (!in_array($uuidSwapFlag, ['true', 'false'], true)) {
throw new SchemaException('Value for /database/vendor/parameter[name="UuidSwapFlag"] must be "true" or "false", but it is ' . $uuidSwapFlag);
}

return $uuidSwapFlag;
}
}
64 changes: 56 additions & 8 deletions src/Propel/Generator/Builder/Om/ObjectBuilder.php
Expand Up @@ -323,6 +323,12 @@ protected function addClassBody(string &$script): void
}

$table = $this->getTable();

$additionalModelClasses = $table->getAdditionalModelClassImports();
if ($additionalModelClasses) {
$this->declareClasses(...$additionalModelClasses);
}

if (!$table->isAlias()) {
$this->addConstants($script);
$this->addAttributes($script);
Expand Down Expand Up @@ -1709,6 +1715,13 @@ protected function addLazyLoaderBody(string &$script, Column $column): void
} elseif ($column->isPhpObjectType()) {
$script .= "
\$this->$clo = (\$firstColumn !== null) ? new " . $column->getPhpType() . '($firstColumn) : null;';
} elseif ($column->getType() === PropelTypes::UUID_BINARY) {
$uuidSwapFlag = $this->getUuidSwapFlagLiteral();
$script .= "
if (is_resource(\$firstColumn)) {
\$firstColumn = stream_get_contents(\$firstColumn);
}
\$this->$clo = (\$firstColumn) ? UuidConverter::binToUuid(\$firstColumn, $uuidSwapFlag) : null;";
} else {
$script .= "
\$this->$clo = \$firstColumn;";
Expand Down Expand Up @@ -2716,6 +2729,13 @@ protected function addHydrateBody(string &$script): void
}
$script .= "
\$this->$clo = (null !== \$col) ? PropelDateTime::newInstance(\$col, null, '$dateTimeClass') : null;";
} elseif ($col->isUuidBinaryType()) {
$uuidSwapFlag = $this->getUuidSwapFlagLiteral();
$script .= "
if (is_resource(\$col)) {
\$col = stream_get_contents(\$col);
}
\$this->$clo = (\$col) ? UuidConverter::binToUuid(\$col, $uuidSwapFlag) : null;";
} elseif ($col->isPhpPrimitiveType()) {
$script .= "
\$this->$clo = (null !== \$col) ? (" . $col->getPhpType() . ') $col : null;';
Expand Down Expand Up @@ -2745,8 +2765,8 @@ protected function addHydrateBody(string &$script): void

if ($this->getBuildProperty('generator.objectModel.addSaveMethod')) {
$script .= "
\$this->resetModified();
";
\$this->resetModified();";
}

$script .= "
Expand Down Expand Up @@ -2950,10 +2970,11 @@ protected function addBuildCriteriaBody(string &$script): void
\$criteria = new Criteria(" . $this->getTableMapClass() . "::DATABASE_NAME);
";
foreach ($this->getTable()->getColumns() as $col) {
$clo = $col->getLowercasedName();
$accessValueStatement = $this->getAccessValueStatement($col);
$columnConstant = $this->getColumnConstant($col);
$script .= "
if (\$this->isColumnModified(" . $this->getColumnConstant($col) . ")) {
\$criteria->add(" . $this->getColumnConstant($col) . ", \$this->$clo);
if (\$this->isColumnModified($columnConstant)) {
\$criteria->add($columnConstant, $accessValueStatement);
}";
}
}
Expand Down Expand Up @@ -6599,12 +6620,15 @@ protected function addDoInsertBodyRaw(): string
\$stmt = \$con->prepare(\$sql);
foreach (\$modifiedColumns as \$identifier => \$columnName) {
switch (\$columnName) {";

$tab = ' ';
foreach ($table->getColumns() as $column) {
$columnNameCase = var_export($this->quoteIdentifier($column->getName()), true);
$accessValueStatement = $this->getAccessValueStatement($column);
$bindValueStatement = $platform->getColumnBindingPHP($column, '$identifier', $accessValueStatement, $tab);
$script .= "
case $columnNameCase:";
$script .= $platform->getColumnBindingPHP($column, '$identifier', '$this->' . $column->getLowercasedName(), ' ');
$script .= "
case $columnNameCase:$bindValueStatement
break;";
}
$script .= "
Expand Down Expand Up @@ -6645,6 +6669,30 @@ protected function addDoInsertBodyRaw(): string
return $script;
}

/**
* Get the statement how a column value is accessed in the script.
*
* Note that this is not necessarily just the getter. If the value is
* stored on the model in an encoded format, the statement returned by
* this method includes the statement to decode the value.
*
* @param \Propel\Generator\Model\Column $column
*
* @return string
*/
protected function getAccessValueStatement(Column $column): string
{
$columnName = $column->getLowercasedName();

if ($column->isUuidBinaryType()) {
$uuidSwapFlag = $this->getUuidSwapFlagLiteral();

return "(\$this->$columnName) ? UuidConverter::uuidToBin(\$this->$columnName, $uuidSwapFlag) : null";
}

return "\$this->$columnName";
}

/**
* get the doUpdate() method code
*
Expand Down
8 changes: 8 additions & 0 deletions src/Propel/Generator/Builder/Om/QueryBuilder.php
Expand Up @@ -174,6 +174,10 @@ protected function addClassBody(string &$script): void
);
$this->declareClassFromBuilder($this->getStubQueryBuilder(), 'Child');
$this->declareClassFromBuilder($this->getTableMapBuilder());
$additionalModelClasses = $table->getAdditionalModelClassImports();
if ($additionalModelClasses) {
$this->declareClasses(...$additionalModelClasses);
}

// apply behaviors
$this->applyBehaviorModifier('queryAttributes', $script, ' ');
Expand Down Expand Up @@ -1147,6 +1151,10 @@ public function filterBy$colPhpName(\$$variableName = null, ?string \$comparison
if (is_string(\$$variableName)) {
\$$variableName = in_array(strtolower(\$$variableName), array('false', 'off', '-', 'no', 'n', '0', '')) ? false : true;
}";
} elseif ($col->isUuidBinaryType()) {
$uuidSwapFlag = $this->getUuidSwapFlagLiteral();
$script .= "
\$$variableName = UuidConverter::uuidToBinRecursive(\$$variableName, $uuidSwapFlag);";
}
$script .= "
Expand Down
10 changes: 10 additions & 0 deletions src/Propel/Generator/Model/Column.php
Expand Up @@ -1333,6 +1333,16 @@ public function isUuidType(): bool
return PropelTypes::isUuidType($this->getType());
}

/**
* Returns whether this column is a uuid bin type.
*
* @return bool
*/
public function isUuidBinaryType(): bool
{
return $this->getType() === PropelTypes::UUID_BINARY;
}

/**
* Returns whether the column is an array column.
*
Expand Down
9 changes: 9 additions & 0 deletions src/Propel/Generator/Model/PropelTypes.php
Expand Up @@ -351,6 +351,11 @@ class PropelTypes
*/
public const UUID_NATIVE_TYPE = 'string';

/**
* @var string
*/
public const UUID_BINARY = 'UUID_BINARY';

/**
* Propel mapping types.
*
Expand Down Expand Up @@ -392,6 +397,7 @@ class PropelTypes
self::SET,
self::JSON,
self::UUID,
self::UUID_BINARY,
];

/**
Expand Down Expand Up @@ -433,6 +439,7 @@ class PropelTypes
self::GEOMETRY => self::GEOMETRY,
self::JSON => self::JSON_TYPE,
self::UUID => self::UUID_NATIVE_TYPE,
self::UUID_BINARY => self::UUID_NATIVE_TYPE,
];

/**
Expand Down Expand Up @@ -479,6 +486,7 @@ class PropelTypes
self::BU_TIMESTAMP => PDO::PARAM_STR,
self::JSON => PDO::PARAM_STR,
self::UUID => PDO::PARAM_STR,
self::UUID_BINARY => PDO::PARAM_LOB,
];

/**
Expand Down Expand Up @@ -639,6 +647,7 @@ public static function isUuidType(string $type): bool
{
return in_array($type, [
self::UUID,
self::UUID_BINARY,
], true);
}

Expand Down
65 changes: 65 additions & 0 deletions src/Propel/Generator/Model/Table.php
Expand Up @@ -18,6 +18,7 @@
use Propel\Generator\Platform\MysqlPlatform;
use Propel\Generator\Platform\PlatformInterface;
use Propel\Runtime\Exception\RuntimeException;
use Propel\Runtime\Util\UuidConverter;

/**
* Data about a table used in an application.
Expand Down Expand Up @@ -1858,6 +1859,31 @@ public function getDatabase(): ?Database
return $this->database;
}

/**
* Returns a VendorInfo object by its vendor type id (i.e. "mysql").
*
* Vendor information is set in schema.xml for the table or the whole
* database. The method returns database-wide vendor information extended
* and possibly overridden by table vendor information.
*
* @see \Propel\Generator\Model\MappingModel::getVendorInfoForType()
*
* @param string $type Vendor id, i.e. "mysql"
*
* @return \Propel\Generator\Model\VendorInfo
*/
public function getVendorInfoForType(string $type): VendorInfo
{
$tableVendorInfo = parent::getVendorInfoForType($type);
$db = $this->getDatabase();
if (!$db) {
return $tableVendorInfo;
}
$databaseVendorInfo = $db->getVendorInfoForType($type);

return $databaseVendorInfo->getMergedVendorInfo($tableVendorInfo);
}

/**
* Get the database that contains this table.
*
Expand Down Expand Up @@ -2205,4 +2231,43 @@ public function setIdentifierQuoting(?bool $identifierQuoting): void
{
$this->identifierQuoting = $identifierQuoting;
}

/**
* Check if this table contains columns of the given type.
*
* @param string $type The type to check for, i.e. PropelTypes::BOOLEAN
*
* @return bool
*/
public function containsColumnsOfType(string $type): bool
{
foreach ($this->columns as $column) {
if ($column->getType() === $type) {
return true;
}
}

return false;
}

/**
* Get additional class imports for model and query classes needed by the columns.
*
* @psalm-return array<class-string>
*
* @see \Propel\Generator\Builder\Om\ObjectBuilder::addClassBody()
* @see \Propel\Generator\Builder\Om\QueryBuilder::addClassBody()
*
* @return array<string>|null
*/
public function getAdditionalModelClassImports(): ?array
{
if ($this->containsColumnsOfType(PropelTypes::UUID_BINARY)) {
return [
UuidConverter::class,
];
}

return null;
}
}
1 change: 1 addition & 0 deletions src/Propel/Generator/Platform/MssqlPlatform.php
Expand Up @@ -58,6 +58,7 @@ protected function initialize(): void
$this->setSchemaDomainMapping(new Domain(PropelTypes::ENUM, 'TINYINT'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::SET, 'INT'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::UUID, 'UNIQUEIDENTIFIER'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::UUID_BINARY, 'BINARY(16)'));
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/Propel/Generator/Platform/MysqlPlatform.php
Expand Up @@ -66,6 +66,7 @@ protected function initialize(): void
$this->setSchemaDomainMapping(new Domain(PropelTypes::ENUM, 'TINYINT'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::SET, 'INT'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::REAL, 'DOUBLE'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::UUID_BINARY, 'BINARY(16)'));
}

/**
Expand Down Expand Up @@ -331,9 +332,7 @@ public function getAddTableDDL(Table $table): string
*/
protected function getTableOptions(Table $table): array
{
$dbVI = $table->getDatabase()->getVendorInfoForType('mysql');
$tableVI = $table->getVendorInfoForType('mysql');
$vi = $dbVI->getMergedVendorInfo($tableVI);
$vi = $table->getVendorInfoForType('mysql');
$tableOptions = [];
// List of supported table options
// see http://dev.mysql.com/doc/refman/5.5/en/create-table.html
Expand Down
1 change: 1 addition & 0 deletions src/Propel/Generator/Platform/OraclePlatform.php
Expand Up @@ -61,6 +61,7 @@ protected function initialize(): void
$this->setSchemaDomainMapping(new Domain(PropelTypes::ENUM, 'NUMBER', 3, 0));
$this->setSchemaDomainMapping(new Domain(PropelTypes::SET, 'NUMBER'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::UUID, 'UUID'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::UUID_BINARY, 'RAW(16)'));
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/Propel/Generator/Platform/PgsqlPlatform.php
Expand Up @@ -63,6 +63,7 @@ protected function initialize(): void
$this->setSchemaDomainMapping(new Domain(PropelTypes::DECIMAL, 'NUMERIC'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::DATETIME, 'TIMESTAMP'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::UUID, 'uuid'));
$this->setSchemaDomainMapping(new Domain(PropelTypes::UUID_BINARY, 'BYTEA'));
}

/**
Expand Down
7 changes: 7 additions & 0 deletions src/Propel/Generator/Platform/PlatformInterface.php
Expand Up @@ -338,4 +338,11 @@ public function isIdentifierQuotingEnabled(): bool;
* @return void
*/
public function setIdentifierQuoting(bool $enabled): void;

/**
* @param \Propel\Generator\Model\Table $table
*
* @return string
*/
public function getAddTableDDL(Table $table): string;
}

0 comments on commit e705c03

Please sign in to comment.