Skip to content

Commit 9202bc4

Browse files
authored
Merge pull request #18 from blitz-php/1.x-devs
Ameliorations mutiples
2 parents e714d39 + b1d2c88 commit 9202bc4

10 files changed

Lines changed: 212 additions & 84 deletions

File tree

spec/Connection/BaseConnection.spec.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,17 @@
5454

5555
it(": Échappement des identifiants", function() {
5656
expect($this->connection->escapeIdentifiers('users.id'))->toBe('`users`.`id`');
57-
// expect($this->connection->escapeIdentifiers('count(*)'))->toBe('count(*)');
57+
expect($this->connection->escapeIdentifiers('count(id)'))->toBe('count(`id`)');
58+
expect($this->connection->escapeIdentifiers('count(users.id)'))->toBe('count(`users`.`id`)');
5859
expect($this->connection->escapeIdentifiers(['users.id', 'name']))->toBe(['`users`.`id`', '`name`']);
5960
});
6061

62+
it(": Échappement des identifiants reservés", function() {
63+
expect($this->connection->escapeIdentifiers('users.*'))->toBe('`users`.*');
64+
expect($this->connection->escapeIdentifiers(['count(*)', 'count(users.*)']))->toBe(['count(*)', 'count(`users`.*)']);
65+
expect($this->connection->escapeIdentifiers(['users.id', 'name', '*']))->toBe(['`users`.`id`', '`name`', '*']);
66+
});
67+
6168
it(": Échappement des chaînes", function() {
6269
$escaped = $this->connection->escapeString("O'Reilly");
6370
expect($escaped)->toBe("'O''Reilly'");

spec/Utils.spec.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,17 @@
4848
});
4949

5050
it(": isAlias", function() {
51-
expect(Utils::isAlias('user_alias'))->toBe(true);
51+
expect(Utils::isAlias('user_alias'))->toBe(false);
5252
expect(Utils::isAlias('AS user_alias'))->toBe(true);
5353
expect(Utils::isAlias('user-alias'))->toBe(false); // tiret pas autorisé
5454
expect(Utils::isAlias('user.alias'))->toBe(false); // point pas autorisé
5555
});
5656

5757
it(": extractAlias", function() {
5858
expect(Utils::extractAlias('AS alias'))->toBe('alias');
59-
expect(Utils::extractAlias('alias'))->toBe('alias');
59+
expect(Utils::extractAlias('alias'))->toBeNull();
6060
expect(Utils::extractAlias(' AS alias '))->toBe('alias');
61+
expect(Utils::extractAlias('users AS alias '))->toBe('alias');
6162
});
6263

6364
it(": extractOperatorFromColumn", function() {

src/Builder/Concerns/DataMethods.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public function insertUsing(array $columns, BuilderInterface|Closure $query)
167167
public function insertGetId(array $values, ?string $sequence = null)
168168
{
169169
if (is_bool($inserted = $this->insert($values))) {
170-
return $inserted === true ? $this->db->lastId($this->getTable()) : null;
170+
return $inserted === true ? $this->lastId($this->getTable()) : null;
171171
}
172172

173173
return $inserted;
@@ -195,6 +195,14 @@ protected function getKeyName(): string
195195
return 'id';
196196
}
197197

198+
/**
199+
* Récupère le dernier ID généré par l'auto-incrémentation
200+
*/
201+
public function lastId(?string $table = null): ?int
202+
{
203+
return $this->db->lastId($table);
204+
}
205+
198206
/*
199207
|--------------------------------------------------------------------------
200208
| RAW EXPRESSIONS

src/Commands/Generators/Migration.php

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111

1212
namespace BlitzPHP\Database\Commands\Generators;
1313

14-
use BlitzPHP\Cli\Console\Command;
15-
use BlitzPHP\Cli\Traits\GeneratorTrait;
14+
use BlitzPHP\Cli\Commands\Generators\GeneratorCommand;
1615
use InvalidArgumentException;
1716

1817
/**
@@ -21,15 +20,8 @@
2120
* Analyse le nom de la migration pour déterminer automatiquement
2221
* l'action (create/modify) et la table concernée.
2322
*/
24-
class Migration extends Command
23+
class Migration extends GeneratorCommand
2524
{
26-
use GeneratorTrait;
27-
28-
/**
29-
* {@inheritDoc}
30-
*/
31-
protected string $group = 'Générateurs';
32-
3325
/**
3426
* {@inheritDoc}
3527
*/
@@ -61,6 +53,11 @@ class Migration extends Command
6153
'--suffix' => 'Ajoute "Migration" au nom de la classe (par exemple, User => UserMigration)',
6254
];
6355

56+
protected string $component = 'Migration';
57+
protected string $directory = 'Database\Migrations';
58+
protected string $template = 'migration.tpl.php';
59+
protected string $templatePath = __DIR__ . '/Views';
60+
6461
/**
6562
* Mots-clés pour les actions de création
6663
*/
@@ -82,27 +79,6 @@ class Migration extends Command
8279
*/
8380
protected array $dropKeywords = ['drop', 'delete', 'remove'];
8481

85-
/**
86-
* {@inheritDoc}
87-
*/
88-
public function handle()
89-
{
90-
$this->component = 'Migration';
91-
$this->directory = 'Database\Migrations';
92-
$this->template = 'migration.tpl.php';
93-
$this->templatePath = __DIR__ . '/Views';
94-
95-
try {
96-
$this->generateClass($this->parameters());
97-
98-
return EXIT_SUCCESS;
99-
} catch (InvalidArgumentException $e) {
100-
$this->error($e->getMessage());
101-
102-
return EXIT_ERROR;
103-
}
104-
}
105-
10682
/**
10783
* Prépare les options et effectue les remplacements nécessaires.
10884
*/

src/Commands/Generators/Seeder.php

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,14 @@
1111

1212
namespace BlitzPHP\Database\Commands\Generators;
1313

14-
use BlitzPHP\Cli\Console\Command;
15-
use BlitzPHP\Cli\Traits\GeneratorTrait;
14+
use BlitzPHP\Cli\Commands\Generators\GeneratorCommand;
1615

1716
/**
1817
* Génère un fichier squelette de seeder.
1918
*/
20-
class Seeder extends Command
19+
class Seeder extends GeneratorCommand
2120
{
22-
use GeneratorTrait;
23-
24-
/**
25-
* {@inheritDoc}
26-
*/
27-
protected string $group = 'Generateurs';
28-
29-
/**
21+
/**
3022
* {@inheritDoc}
3123
*/
3224
protected string $name = 'make:seeder';
@@ -57,17 +49,9 @@ class Seeder extends Command
5749
'--force' => 'Forcer l\'écrasement du fichier existant.',
5850
];
5951

60-
/**
61-
* {@inheritDoc}
62-
*/
63-
public function handle()
64-
{
65-
$this->component = 'Seeder';
66-
$this->directory = 'Database\Seeds';
67-
$this->template = 'seeder.tpl.php';
68-
$this->templatePath = __DIR__ . '/Views';
69-
70-
$this->classNameLang = 'CLI.generator.className.seeder';
71-
$this->generateClass($this->parameters());
72-
}
52+
protected string $component = 'Seeder';
53+
protected string $directory = 'Database\Seeds';
54+
protected string $template = 'seeder.tpl.php';
55+
protected string $templatePath = __DIR__ . '/Views';
56+
protected string $classNameLang = 'CLI.generator.className.seeder';
7357
}

src/Connection/BaseConnection.php

Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,17 @@ public function escapeIdentifiers(mixed $item): mixed
768768
return array_map([$this, 'escapeIdentifiers'], $item);
769769
}
770770

771+
if ($item instanceof Stringable) {
772+
$item = (string) $item;
773+
}
774+
775+
$item = trim($item);
776+
777+
// Vérifier d'abord si c'est un appel de fonction SQL
778+
if ($processed = $this->processSqlFunctionCall($item)) {
779+
return $processed;
780+
}
781+
771782
if (! isset($this->escapeCache[$item])) {
772783
$this->escapeCache[$item] = $this->doEscapeIdentifiers($item);
773784
}
@@ -777,10 +788,6 @@ public function escapeIdentifiers(mixed $item): mixed
777788

778789
protected function doEscapeIdentifiers(string $item): string
779790
{
780-
if ($this->isReserved($item) || Utils::isSqlFunction($item)) {
781-
return $item;
782-
}
783-
784791
if (str_contains($item, '.')) {
785792
$parts = explode('.', $item);
786793

@@ -795,13 +802,116 @@ protected function doEscapeIdentifiers(string $item): string
795802
*/
796803
protected function escapeIdentifier(string $item): string
797804
{
805+
if ($this->isReserved($item) || Utils::isSqlFunction($item)) {
806+
return $item;
807+
}
808+
798809
if ($this->isEscapedIdentifier($item)) {
799810
return $item;
800811
}
801812

802813
return $this->escapeChar . $item . $this->escapeChar;
803814
}
804815

816+
/**
817+
* Traite un appel de fonction SQL et échappe ses paramètres si nécessaire
818+
*/
819+
protected function processSqlFunctionCall(string $value): ?string
820+
{
821+
// Pattern pour capturer: functionName(param1, param2, ...)
822+
if (preg_match('/^(\w+)\s*\((.*)\)$/', $value, $matches)) {
823+
$functionName = $matches[1];
824+
$parameters = $matches[2];
825+
826+
if (Utils::isSqlFunction($functionName)) {
827+
// Si pas de paramètres, retourner tel quel
828+
if (trim($parameters) === '') {
829+
return $value;
830+
}
831+
832+
// Traiter chaque paramètre
833+
$processedParams = [];
834+
$params = $this->splitParameters($parameters);
835+
836+
foreach ($params as $param) {
837+
$param = trim($param);
838+
$processedParams[] = $this->processSqlFunctionParameter($param);
839+
}
840+
841+
return $functionName . '(' . implode(', ', $processedParams) . ')';
842+
}
843+
}
844+
845+
return null;
846+
}
847+
848+
/**
849+
* Traite un paramètre d'appel de fonction SQL
850+
*/
851+
protected function processSqlFunctionParameter(string $param): string
852+
{
853+
// Si c'est un wildcard
854+
if ($param === '*') {
855+
return $param;
856+
}
857+
858+
// Si le paramètre contient un point, c'est un identifiant qualifié
859+
if (str_contains($param, '.')) {
860+
// Séparer les parties et échapper chaque partie individuellement
861+
$parts = explode('.', $param);
862+
$parts = array_map($this->escapeIdentifier(...), $parts);
863+
864+
return implode('.', $parts);
865+
}
866+
867+
// Si le paramètre est un identifiant simple
868+
if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $param)) {
869+
return $this->escapeIdentifier($param);
870+
}
871+
872+
// Si c'est un appel de fonction imbriqué
873+
if (preg_match('/^(\w+)\s*\(.*\)$/', $param)) {
874+
return $this->processSqlFunctionCall($param) ?? $param;
875+
}
876+
877+
// Sinon, garder tel quel (nombres, chaînes entre quotes, etc.)
878+
return $param;
879+
}
880+
881+
/**
882+
* Sépare les paramètres d'une fonction en gérant les virgules dans les parenthèses
883+
*/
884+
protected function splitParameters(string $parameters): array
885+
{
886+
$params = [];
887+
$current = '';
888+
$depth = 0;
889+
$length = strlen($parameters);
890+
891+
for ($i = 0; $i < $length; $i++) {
892+
$char = $parameters[$i];
893+
894+
if ($char === '(') {
895+
$depth++;
896+
$current .= $char;
897+
} elseif ($char === ')') {
898+
$depth--;
899+
$current .= $char;
900+
} elseif ($char === ',' && $depth === 0) {
901+
$params[] = trim($current);
902+
$current = '';
903+
} else {
904+
$current .= $char;
905+
}
906+
}
907+
908+
if (trim($current) !== '') {
909+
$params[] = trim($current);
910+
}
911+
912+
return $params;
913+
}
914+
805915
/**
806916
* Vérifie si un identifiant est réservé
807917
*/
@@ -1133,7 +1243,11 @@ public function error(): array
11331243
public function lastId(?string $table = null): ?int
11341244
{
11351245
try {
1136-
return (int) $this->pdo->lastInsertId($table);
1246+
if (-1 === $id = $this->result?->lastId() ?? -1) {
1247+
$id = $this->pdo->lastInsertId($table);
1248+
}
1249+
1250+
return (int) $id;
11371251
} catch (PDOException) {
11381252
return null;
11391253
}

0 commit comments

Comments
 (0)