Skip to content

Commit 2341cf5

Browse files
authored
Merge pull request #184 from Planetbiru/feature/3.22.1
Feature/3.22.1
2 parents 5a19a4d + ace0c01 commit 2341cf5

File tree

2 files changed

+84
-42
lines changed

2 files changed

+84
-42
lines changed

src/Database/PicoDatabasePersistence.php

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,26 @@ private function addGeneratedValue($info, $firstCall)
11241124
return $this;
11251125
}
11261126

1127+
/**
1128+
* Determines whether a value should be generated for the given property
1129+
* during the first invocation of the generation process.
1130+
*
1131+
* A value will be generated only if:
1132+
* - This is the first call of the generation lifecycle
1133+
* - The specified property does not yet have a value (null or empty string)
1134+
* - No generated value has been assigned previously
1135+
*
1136+
* @param bool $firstCall Indicates whether this is the first call in the generation lifecycle.
1137+
* @param string $prop The property name to be evaluated.
1138+
* @return bool Returns true if a new value should be generated; false otherwise.
1139+
*/
1140+
private function shouldGenerateValueOnFirstCall($firstCall, $prop)
1141+
{
1142+
return $firstCall
1143+
&& ($this->object->get($prop) === null || $this->object->get($prop) === '')
1144+
&& !$this->generatedValue;
1145+
}
1146+
11271147
/**
11281148
* Set a generated value for a specified property based on its generation strategy.
11291149
*
@@ -1134,40 +1154,43 @@ private function addGeneratedValue($info, $firstCall)
11341154
*/
11351155
private function setGeneratedValue($prop, $strategy, $firstCall)
11361156
{
1137-
if(stripos($strategy, "UUID") !== false)
1138-
{
1139-
if($firstCall && ($this->object->get($prop) == null || $this->object->get($prop) == "") && !$this->generatedValue)
1140-
{
1141-
$generatedValue = $this->database->generateNewId();
1142-
$this->object->set($prop, $generatedValue);
1143-
$this->generatedValue = true;
1157+
// Handle IDENTITY strategy separately (DB-driven)
1158+
if (stripos($strategy, 'IDENTITY') !== false) {
1159+
if ($firstCall) {
1160+
$this->requireDbAutoincrement = true;
1161+
} elseif ($this->requireDbAutoincrement && !$this->dbAutoinrementCompleted) {
1162+
$this->object->set(
1163+
$prop,
1164+
$this->database->getDatabaseConnection()->lastInsertId()
1165+
);
1166+
$this->dbAutoinrementCompleted = true;
11441167
}
1168+
1169+
return $this;
11451170
}
1146-
else if(stripos($strategy, "TIMEBASED") !== false)
1147-
{
1148-
if($firstCall && ($this->object->get($prop) == null || $this->object->get($prop) == "") && !$this->generatedValue)
1149-
{
1150-
$generatedValue = $this->database->generateTimeBasedId();
1151-
$this->object->set($prop, $generatedValue);
1171+
1172+
// Map strategy to generator method
1173+
$generatorMap = [
1174+
'UUID' => 'generateUUID',
1175+
'TIMEBASED' => 'generateTimeBasedId',
1176+
'LEGACY_TIMEBASED' => 'generateNewId',
1177+
];
1178+
1179+
foreach ($generatorMap as $key => $method) {
1180+
if (
1181+
stripos($strategy, $key) !== false &&
1182+
$this->shouldGenerateValueOnFirstCall($firstCall, $prop)
1183+
) {
1184+
$this->object->set($prop, $this->database->{$method}());
11521185
$this->generatedValue = true;
1186+
break;
11531187
}
11541188
}
1155-
else if(stripos($strategy, "IDENTITY") !== false)
1156-
{
1157-
if($firstCall)
1158-
{
1159-
$this->requireDbAutoincrement = true;
1160-
}
1161-
else if($this->requireDbAutoincrement && !$this->dbAutoinrementCompleted)
1162-
{
1163-
$generatedValue = $this->database->getDatabaseConnection()->lastInsertId();
1164-
$this->object->set($prop, $generatedValue);
1165-
$this->dbAutoinrementCompleted = true;
1166-
}
1167-
}
1189+
11681190
return $this;
11691191
}
11701192

1193+
11711194
/**
11721195
* Insert the current object's data into the database.
11731196
*
@@ -1275,11 +1298,29 @@ private function fixInsertableValues($values, $info = null)
12751298
}
12761299

12771300
/**
1278-
* 1. TABLE - Indicates that the persistence provider must assign primary keys for the entity using an underlying database table to ensure uniqueness.
1279-
* 2. SEQUENCE - Indicates that the persistence provider must assign primary keys for the entity using a database sequence.
1280-
* 3. IDENTITY - Indicates that the persistence provider must assign primary keys for the entity using a database identity column.
1281-
* 4. AUTO - Indicates that the persistence provider should pick an appropriate strategy for the particular database. The AUTO generation strategy may expect a database resource to exist, or it may attempt to create one. A vendor may provide documentation on how to create such resources in the event that it does not support schema generation or cannot create the schema resource at runtime.
1282-
* 5. UUID - Indicates that the persistence provider must assign primary keys for the entity with a UUID value.
1301+
* 1. TABLE - Indicates that the persistence provider must assign primary keys for the entity
1302+
* using an underlying database table to ensure uniqueness.
1303+
*
1304+
* 2. SEQUENCE - Indicates that the persistence provider must assign primary keys for the entity
1305+
* using a database sequence.
1306+
*
1307+
* 3. IDENTITY - Indicates that the persistence provider must assign primary keys for the entity
1308+
* using a database identity column.
1309+
*
1310+
* 4. AUTO - Indicates that the persistence provider should select an appropriate strategy for
1311+
* the specific database. The AUTO generation strategy may expect a database resource to
1312+
* already exist, or it may attempt to create one. A vendor may provide documentation on how
1313+
* to create such resources if schema generation is not supported or if the resource cannot
1314+
* be created at runtime.
1315+
*
1316+
* 5. UUID - Indicates that the persistence provider must assign primary keys for the entity
1317+
* using a standard UUID value.
1318+
*
1319+
* 6. TIME_BASED - Indicates that the persistence provider must assign primary keys for the entity
1320+
* using the current epoch time in nanoseconds, combined with a 3-hex-digit random suffix.
1321+
*
1322+
* 7. LEGACY_TIMEBASED - Indicates that the persistence provider must assign primary keys for the
1323+
* entity using the legacy, non-standard UUID-based strategy from earlier versions.
12831324
*/
12841325

12851326
if($info->getAutoIncrementKeys() != null)
@@ -1311,7 +1352,7 @@ private function fixInsertableValues($values, $info = null)
13111352
*/
13121353
private function isRequireGenerateValue($strategy, $propertyName)
13131354
{
1314-
return stripos($strategy, "UUID") !== false
1355+
return (stripos($strategy, "UUID") !== false || stripos($strategy, "TIMEBASED") !== false || stripos($strategy, "LEGACY_TIMEBASED") !== false)
13151356
&& ($this->object->get($propertyName) == null || $this->object->get($propertyName) == "")
13161357
&& !$this->generatedValue;
13171358
}

src/Database/PicoDatabaseQueryBuilder.php

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -711,12 +711,10 @@ public function rollback()
711711
*/
712712
public function escapeSQL($query) // NOSONAR
713713
{
714-
// Escape carriage return and newline for all
715-
$query = str_replace(["\r", "\n"], ["\\r", "\\n"], $query);
716-
717714
if (stripos($this->databaseType, PicoDatabaseType::DATABASE_TYPE_MYSQL) !== false
718715
|| stripos($this->databaseType, PicoDatabaseType::DATABASE_TYPE_MARIADB) !== false) {
719-
// MySQL/MariaDB: escape both backslash and single quote
716+
717+
// MySQL / MariaDB
720718
return str_replace(
721719
["\\", "'"],
722720
["\\\\", "\\'"],
@@ -725,25 +723,28 @@ public function escapeSQL($query) // NOSONAR
725723
}
726724

727725
if (stripos($this->databaseType, PicoDatabaseType::DATABASE_TYPE_PGSQL) !== false) {
728-
// PostgreSQL: double single quotes and backslashes (E'' required at usage site)
726+
727+
// PostgreSQL (without E'')
729728
return str_replace(
730-
["\\", "'"],
731-
["\\\\", "''"],
729+
["'", "\\"],
730+
["''", "\\\\"],
732731
$query
733732
);
734733
}
735734

736735
if (stripos($this->databaseType, PicoDatabaseType::DATABASE_TYPE_SQLITE) !== false) {
737-
// SQLite: only escape single quote
736+
737+
// SQLite
738738
return str_replace("'", "''", $query);
739739
}
740740

741741
if (stripos($this->databaseType, PicoDatabaseType::DATABASE_TYPE_SQLSERVER) !== false) {
742-
// SQL Server: only escape single quote
742+
743+
// SQL Server
743744
return str_replace("'", "''", $query);
744745
}
745746

746-
// Default fallback: treat like MySQL
747+
// Default fallback
747748
return str_replace(
748749
["\\", "'"],
749750
["\\\\", "\\'"],

0 commit comments

Comments
 (0)