Skip to content

Commit a510dea

Browse files
committed
Merge branch 'master' into bugfix/issue1489-mysql_types
2 parents 8cd7c43 + 4a2032b commit a510dea

29 files changed

+491
-72
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ jobs:
1616
matrix:
1717
php-version: [ '7.4', '8.2' ]
1818
db-type: [ sqlite, mysql, pgsql, agnostic ]
19-
symfony-version: [ '4-min', '4-max', '5-min', '5-max', '6-min', '6-max' ]
19+
symfony-version: [ '5-min', '5-max', '6-min', '6-max', '7-min', '7-max']
2020
exclude:
21-
- symfony-version: '4-min'
22-
php-version: '8.2'
2321
- symfony-version: '6-min'
2422
php-version: '7.4'
2523
- symfony-version: '6-max'
2624
php-version: '7.4'
25+
- symfony-version: '7-min'
26+
php-version: '7.4'
27+
- symfony-version: '7-max'
28+
php-version: '7.4'
2729
env:
2830
DB_NAME: 'propel_tests'
2931
DB_USER: 'propel'
@@ -125,6 +127,8 @@ jobs:
125127
else
126128
vendor/bin/phpunit -c tests/${{ matrix.db-type }}.phpunit.xml
127129
fi
130+
env:
131+
SYMFONY_VERSION: ${{ matrix.symfony-version }}
128132

129133
- name: Code Coverage Report
130134
if: success() && matrix.php-version == '7.4' && matrix.symfony-version == '5-max'
@@ -166,6 +170,8 @@ jobs:
166170
run: composer install --prefer-dist --no-interaction
167171

168172
- name: PHPStan
173+
env:
174+
PHPSTAN: 1
169175
run: composer stan
170176

171177
- name: Psalm

composer.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
"require": {
1919
"php": ">=7.4",
2020
"psr/log": "^1.0 || ^2.0 || ^3.0",
21-
"symfony/yaml": "^4.4.0 || ^5.0.0 || ^6.0.0",
22-
"symfony/config": "^4.4.0 || ^5.0.0 || ^6.0.0",
23-
"symfony/console": "^4.4.0 || ^5.0.0 || ^6.0.0",
24-
"symfony/filesystem": "^4.4.0 || ^5.0.0 || ^6.0.0",
25-
"symfony/finder": "^4.4.0 || ^5.0.0 || ^6.0.0",
26-
"symfony/translation": "^4.4.0 || ^5.0.0 || ^6.0.0",
27-
"symfony/validator": "^4.4.0 || ^5.0.0 || ^6.0.0"
21+
"symfony/yaml": "^5.0.0 || ^6.0.0 || ^7.0.0",
22+
"symfony/config": "^5.0.0 || ^6.0.0 || ^7.0.0",
23+
"symfony/console": "^5.0.0 || ^6.0.0 || ^7.0.0",
24+
"symfony/filesystem": "^5.0.0 || ^6.0.0 || ^7.0.0",
25+
"symfony/finder": "^5.0.0 || ^6.0.0 || ^7.0.0",
26+
"symfony/translation": "^5.0.0 || ^6.0.0 || ^7.0.0",
27+
"symfony/validator": "^5.0.0 || ^6.0.0 || ^7.0.0"
2828
},
2929
"require-dev": {
3030
"ext-pdo": "*",

src/Propel/Generator/Behavior/Timestampable/TimestampableBehavior.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function preUpdate(AbstractOMBuilder $builder): string
106106
: '\\Propel\\Runtime\\Util\\PropelDateTime::createHighPrecision()';
107107

108108
return 'if ($this->isModified() && !$this->isColumnModified(' . $this->getColumnConstant('update_column', $builder) . ")) {
109-
\$this->" . $this->getColumnSetter('update_column') . "(${valueSource});
109+
\$this->" . $this->getColumnSetter('update_column') . "({$valueSource});
110110
}";
111111
}
112112

@@ -131,7 +131,7 @@ public function preInsert(AbstractOMBuilder $builder): string
131131
: '$highPrecision';
132132
$script .= "
133133
if (!\$this->isColumnModified(" . $this->getColumnConstant('create_column', $builder) . ")) {
134-
\$this->" . $this->getColumnSetter('create_column') . "(${valueSource});
134+
\$this->" . $this->getColumnSetter('create_column') . "({$valueSource});
135135
}";
136136
}
137137

@@ -141,7 +141,7 @@ public function preInsert(AbstractOMBuilder $builder): string
141141
: '$highPrecision';
142142
$script .= "
143143
if (!\$this->isColumnModified(" . $this->getColumnConstant('update_column', $builder) . ")) {
144-
\$this->" . $this->getColumnSetter('update_column') . "(${valueSource});
144+
\$this->" . $this->getColumnSetter('update_column') . "({$valueSource});
145145
}";
146146
}
147147

src/Propel/Generator/Builder/Om/AbstractOMBuilder.php

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -686,34 +686,43 @@ public function getFKPhpNameAffix(ForeignKey $fk, bool $plural = false): string
686686
* @return string
687687
*/
688688
protected function getCrossFKsPhpNameAffix(CrossForeignKeys $crossFKs, bool $plural = true): string
689+
{
690+
$baseName = $this->buildCombineCrossFKsPhpNameAffix($crossFKs, false);
691+
692+
$existingTable = $this->getDatabase()->getTableByPhpName($baseName);
693+
$isNameCollision = $existingTable && $this->getTable()->isConnectedWithTable($existingTable);
694+
695+
return ($plural || $isNameCollision) ? $this->buildCombineCrossFKsPhpNameAffix($crossFKs, $plural, $isNameCollision) : $baseName;
696+
}
697+
698+
/**
699+
* @param \Propel\Generator\Model\CrossForeignKeys $crossFKs
700+
* @param bool $plural
701+
* @param bool $withPrefix
702+
*
703+
* @return string
704+
*/
705+
protected function buildCombineCrossFKsPhpNameAffix(CrossForeignKeys $crossFKs, bool $plural = true, bool $withPrefix = false): string
689706
{
690707
$names = [];
708+
if ($withPrefix) {
709+
$names[] = 'Cross';
710+
}
711+
$fks = $crossFKs->getCrossForeignKeys();
712+
$lastCrossFk = array_pop($fks);
713+
$unclassifiedPrimaryKeys = $crossFKs->getUnclassifiedPrimaryKeys();
714+
$lastIsPlural = $plural && !$unclassifiedPrimaryKeys;
691715

692-
if ($plural) {
693-
if ($crossFKs->getUnclassifiedPrimaryKeys()) {
694-
//we have a non fk as pk as well, so we need to make pluralisation on our own and can't
695-
//rely on getFKPhpNameAffix's pluralisation
696-
foreach ($crossFKs->getCrossForeignKeys() as $fk) {
697-
$names[] = $this->getFKPhpNameAffix($fk, false);
698-
}
699-
} else {
700-
//we have only fks, so give us names with plural and return those
701-
$lastIdx = count($crossFKs->getCrossForeignKeys()) - 1;
702-
foreach ($crossFKs->getCrossForeignKeys() as $idx => $fk) {
703-
$needPlural = $idx === $lastIdx; //only last fk should be plural
704-
$names[] = $this->getFKPhpNameAffix($fk, $needPlural);
705-
}
716+
foreach ($fks as $fk) {
717+
$names[] = $this->getFKPhpNameAffix($fk, false);
718+
}
719+
$names[] = $this->getFKPhpNameAffix($lastCrossFk, $lastIsPlural);
706720

707-
return implode('', $names);
708-
}
709-
} else {
710-
// no plural, so $plural=false
711-
foreach ($crossFKs->getCrossForeignKeys() as $fk) {
712-
$names[] = $this->getFKPhpNameAffix($fk, false);
713-
}
721+
if (!$unclassifiedPrimaryKeys) {
722+
return implode('', $names);
714723
}
715724

716-
foreach ($crossFKs->getUnclassifiedPrimaryKeys() as $pk) {
725+
foreach ($unclassifiedPrimaryKeys as $pk) {
717726
$names[] = $pk->getPhpName();
718727
}
719728

src/Propel/Generator/Command/MigrationUpCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ protected function configure()
4444
*
4545
* @throws \Propel\Runtime\Exception\RuntimeException
4646
*/
47-
protected function execute(InputInterface $input, OutputInterface $output)
47+
protected function execute(InputInterface $input, OutputInterface $output): int
4848
{
4949
$configOptions = [];
5050

src/Propel/Generator/Model/CrossForeignKeys.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public function getIncomingForeignKey(): ?ForeignKey
132132
*/
133133
public function isAtLeastOneLocalPrimaryKeyNotCovered(ForeignKey $fk): bool
134134
{
135-
$primaryKeys = $fk->getLocalPrimaryKeys();
135+
$primaryKeys = $fk->getLocalColumnObjects();
136136
foreach ($primaryKeys as $primaryKey) {
137137
$covered = false;
138138
foreach ($this->getCrossForeignKeys() as $crossFK) {

src/Propel/Generator/Model/ForeignKey.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ public function isAtLeastOneLocalColumnRequired(): bool
874874
*/
875875
public function isAtLeastOneLocalPrimaryKeyIsRequired(): bool
876876
{
877-
foreach ($this->getLocalPrimaryKeys() as $pk) {
877+
foreach ($this->getLocalColumnObjects() as $pk) {
878878
if ($pk->isNotNull() && !$pk->hasDefaultValue()) {
879879
return true;
880880
}

src/Propel/Generator/Model/Table.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,4 +2288,18 @@ public function getAdditionalModelClassImports(): ?array
22882288

22892289
return null;
22902290
}
2291+
2292+
/**
2293+
* Check if there is a FK rellation between the current table and the given
2294+
* table in either direction.
2295+
*
2296+
* @param \Propel\Generator\Model\Table $table
2297+
*
2298+
* @return bool
2299+
*/
2300+
public function isConnectedWithTable(Table $table): bool
2301+
{
2302+
return $this->getForeignKeysReferencingTable($table->getName()) ||
2303+
$table->getForeignKeysReferencingTable($this->getName());
2304+
}
22912305
}

src/Propel/Generator/Platform/PgsqlPlatform.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use Propel\Generator\Exception\EngineException;
1212
use Propel\Generator\Model\Column;
13+
use Propel\Generator\Model\ColumnDefaultValue;
1314
use Propel\Generator\Model\Database;
1415
use Propel\Generator\Model\Diff\ColumnDiff;
1516
use Propel\Generator\Model\Diff\TableDiff;
@@ -515,6 +516,16 @@ public function getColumnDDL(Column $col): string
515516
$ddl[] = $sqlType;
516517
}
517518

519+
if (
520+
$col->getDefaultValue()
521+
&& $col->getDefaultValue()->isExpression()
522+
&& $col->getDefaultValue()->getValue() === 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'
523+
) {
524+
$col->setDefaultValue(
525+
new ColumnDefaultValue('CURRENT_TIMESTAMP', ColumnDefaultValue::TYPE_EXPR),
526+
);
527+
}
528+
518529
$default = $this->getColumnDefaultValueDDL($col);
519530
if ($default) {
520531
$ddl[] = $default;

src/Propel/Generator/Platform/SqlitePlatform.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ public function getColumnDDL(Column $col): string
492492
if (
493493
$col->getDefaultValue()
494494
&& $col->getDefaultValue()->isExpression()
495-
&& $col->getDefaultValue()->getValue() === 'CURRENT_TIMESTAMP'
495+
&& in_array($col->getDefaultValue()->getValue(), ['CURRENT_TIMESTAMP', 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'])
496496
) {
497497
//sqlite use CURRENT_TIMESTAMP different than mysql/pgsql etc
498498
//we set it to the more common behavior

src/Propel/Generator/Platform/Util/AlterTableStatementMerger.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace Propel\Generator\Platform\Util;
1010

1111
use Propel\Generator\Model\Table;
12+
use Propel\Generator\Util\SqlParser;
1213

1314
/**
1415
* Merges several ALTER TABLE statements when creating migrations.
@@ -66,7 +67,10 @@ public function __construct(Table $table)
6667
*/
6768
public function mergeStatements(string $sql): string
6869
{
69-
$statements = explode(';', $sql);
70+
$sqlParser = new SqlParser();
71+
$sqlParser->setSQL($sql);
72+
$statements = $sqlParser->explodeIntoStatements();
73+
7074
$blocks = [];
7175
$currentBlock = [];
7276

src/Propel/Generator/Reverse/MysqlSchemaParser.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ public function getColumnFromRow(array $row, Table $table): Column
233233
$column = new Column($columnName);
234234
$column->setTable($table);
235235

236-
$domain = $this->extractTypeDomain($type, $default, $column->getFullyQualifiedName());
236+
$domain = $this->extractTypeDomain($type, $default, $column->getFullyQualifiedName(), $extra);
237237
$column->setDomain($domain);
238238

239239
$autoincrement = (strpos($extra, 'auto_increment') !== false);
@@ -253,10 +253,11 @@ public function getColumnFromRow(array $row, Table $table): Column
253253
* @param string $typeDeclaration MySQL type declaration string (like "VARCHAR(16) CHARACTER SET utf8mb4", "INT UNSIGNED", etc)
254254
* @param string|null $defaultValueLiteral Default value declaration
255255
* @param string $columnName Used when printing warninga
256+
* @param string $extra Additional type specification (i.e. UNSIGNED)
256257
*
257258
* @return \Propel\Generator\Model\Domain
258259
*/
259-
protected function extractTypeDomain(string $typeDeclaration, ?string $defaultValueLiteral, string $columnName): Domain
260+
protected function extractTypeDomain(string $typeDeclaration, ?string $defaultValueLiteral, string $columnName, string $extra): Domain
260261
{
261262
[$nativeType, $sqlType, $size, $scale] = $this->parseType($typeDeclaration);
262263

@@ -281,7 +282,7 @@ protected function extractTypeDomain(string $typeDeclaration, ?string $defaultVa
281282
$domain->replaceSize($size);
282283
$domain->replaceScale($scale);
283284

284-
$defaultValue = $this->extractDefaultValue($defaultValueLiteral, $propelType, $nativeType);
285+
$defaultValue = $this->extractDefaultValue($defaultValueLiteral, $propelType, $nativeType, $extra);
285286
if ($defaultValue) {
286287
$domain->setDefaultValue($defaultValue);
287288
}
@@ -343,10 +344,11 @@ protected function parseType(string $typeDeclaration): array
343344
* @param string|null $parsedValue Default value declaration
344345
* @param string $propelType Column type indicator from \Propel\Generator\Model\PropelTypes
345346
* @param string $nativeType MySQL type name
347+
* @param string $extra Additional type specification (i.e. UNSIGNED)
346348
*
347349
* @return \Propel\Generator\Model\ColumnDefaultValue|null
348350
*/
349-
protected function extractDefaultValue(?string $parsedValue, string $propelType, string $nativeType): ?ColumnDefaultValue
351+
protected function extractDefaultValue(?string $parsedValue, string $propelType, string $nativeType, string $extra): ?ColumnDefaultValue
350352
{
351353
// BLOBs can't have any default values in MySQL
352354
$isBlob = preg_match('~blob|text~', $nativeType);
@@ -367,6 +369,9 @@ protected function extractDefaultValue(?string $parsedValue, string $propelType,
367369

368370
if (in_array($default, ['CURRENT_TIMESTAMP', 'current_timestamp()'], true)) {
369371
$default = 'CURRENT_TIMESTAMP';
372+
if (strpos(strtolower($extra), 'on update current_timestamp') !== false) {
373+
$default = 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';
374+
}
370375
$type = ColumnDefaultValue::TYPE_EXPR;
371376
} else {
372377
$type = ColumnDefaultValue::TYPE_VALUE;

src/Propel/Generator/Util/SqlParser.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,37 @@ public function explodeIntoStatements(): array
232232
public function getNextStatement(): string
233233
{
234234
$isAfterBackslash = false;
235+
$isCommentLine = false;
235236
$isInString = false;
236237
$stringQuotes = '';
237238
$parsedString = '';
238239
$lowercaseString = ''; // helper variable for performance sake
239240
while ($this->pos <= $this->len) {
240241
$char = $this->sql[$this->pos] ?? '';
242+
243+
$newLine = !isset($this->sql[$this->pos - 1]) || $this->sql[$this->pos - 1] === PHP_EOL;
244+
245+
// Skip comments
246+
if ($isCommentLine === true) {
247+
$this->pos++;
248+
if ($char === PHP_EOL) {
249+
$isCommentLine = false; // end of comments line
250+
}
251+
252+
continue;
253+
}
241254
// check flags for strings or escaper
242255
switch ($char) {
256+
case '#':
257+
// detect comment line
258+
if ($newLine === true && $isCommentLine === false) {
259+
$this->pos++;
260+
$isCommentLine = true;
261+
262+
continue 2;
263+
}
264+
265+
break;
243266
case '\\':
244267
$isAfterBackslash = true;
245268

@@ -295,8 +318,9 @@ public function getNextStatement(): string
295318
// check for end of statement
296319
if ($char . $nextChars == $this->delimiter) {
297320
$this->pos += $i; // increase position
321+
$parsedTrimmedString = trim($parsedString);
298322

299-
return trim($parsedString);
323+
return $parsedTrimmedString ?: $parsedString; // to check empty line to avoid stop parsing
300324
}
301325
// avoid using strtolower on the whole parsed string every time new character is added
302326
// there is also no point in adding characters which are in the string

0 commit comments

Comments
 (0)