diff --git a/src/Builder/BaseBuilder.php b/src/Builder/BaseBuilder.php index 02995a7..2804f98 100644 --- a/src/Builder/BaseBuilder.php +++ b/src/Builder/BaseBuilder.php @@ -307,6 +307,7 @@ public function fromSubquery(BuilderInterface $from, string $alias = ''): self $this->reset(); $this->tables = [$table]; + $this->bindings->merge($from->bindings); return $this; } @@ -489,7 +490,7 @@ public function set($key, $value = ''): self $this->values[$k] = $v; } else { $this->values[$k] = $v; - $this->bindings->add($v); + $this->bindings->add($v, 'values'); } } @@ -756,11 +757,11 @@ public function execute(): ResultInterface { $this->applyBeforeQueryCallbacks(); - $result = $this->query($this->toSql(), $this->bindings->getValues()); - - $this->reset(); - - return $result; + try { + return $this->query($this->toSql(), $this->getBindings()); + } finally { + $this->reset(); + } } /** @@ -1078,7 +1079,7 @@ public function explain(): array { $sql = 'EXPLAIN ' . $this->toSql(); - return $this->query($sql, $this->bindings->getValues())->resultArray(); + return $this->query($sql, $this->getBindings())->resultArray(); } /** @@ -1103,9 +1104,32 @@ public function sql(bool $preserve = false): string return $sql; } + /** + * Nettoyage des bindings + */ + public function cleanBindings(array $bindings): array + { + return $this->bindings->clean($bindings); + } + + /** + * Récupère les bindings utilisés + */ public function getBindings(): array { - return $this->db->prepareBindings($this->bindings->getValues()); + $types = match($this->crud) { + 'select' => ['where', 'having', 'order', 'union'], + 'insert', 'replace' => ['values'], + 'upsert' => ['values', 'uniqueBy'], // Si on a des bindings pour les conflits + 'update' => ['values', 'where', 'join'], + 'delete' => ['where', 'join'], + 'truncate' => null, // Pas de bindings pour TRUNCATE + default => [], // Fallback à tous + }; + + return $types === null + ? [] + : $this->db->prepareBindings($this->bindings->getOrdered($types)); } /** diff --git a/src/Builder/BindingCollection.php b/src/Builder/BindingCollection.php index ef7eba3..b9f5a9d 100644 --- a/src/Builder/BindingCollection.php +++ b/src/Builder/BindingCollection.php @@ -11,32 +11,71 @@ namespace BlitzPHP\Database\Builder; +use BlitzPHP\Database\Query\Expression; +use InvalidArgumentException; use PDO; use PDOStatement; class BindingCollection { - protected array $values = []; + /** + * Types de bindings supportés + */ + public const TYPES = [ + 'select', 'from', 'join', 'where', 'having', + 'order', 'union', 'values', 'uniqueBy', + ]; + + /** + * Bindings organisés par type + * + * @var array> + */ + protected array $bindings = []; + + /** + * Types PDO pour chaque binding (optionnel) + * + * @var array> + */ protected array $types = []; + public function __construct() + { + foreach (self::TYPES as $type) { + $this->bindings[$type] = []; + $this->types[$type] = []; + } + } + /** - * Ajoute un binding + * Ajoute un binding dans un contexte spécifique + * + * @param mixed $value Valeur à binder + * @param string $type Contexte ('where', 'values', etc.) + * @param int|null $pdoType Type PDO (optionnel) + * + * @throws InvalidArgumentException */ - public function add(mixed $value, ?int $type = null): self + public function add(mixed $value, string $type = 'where', ?int $pdoType = null): self { - $this->values[] = $value; - $this->types[] = $type ?? $this->guessType($value); - + if (!in_array($type, self::TYPES, true)) { + throw new InvalidArgumentException("Type de binding invalide: {$type}"); + } + + $this->bindings[$type][] = $value; + $this->types[$type][] = $pdoType ?? $this->guessType($value); + return $this; } /** - * Ajoute plusieurs bindings + * Ajoute plusieurs bindings dans un contexte */ - public function addMany(array $values): self + public function addMany(array $values, string $type = 'where'): self { foreach ($values as $value) { - $this->add($value); + $this->add($value, $type); } return $this; @@ -45,84 +84,156 @@ public function addMany(array $values): self /** * Ajoute un binding nommé */ - public function addNamed(string $name, mixed $value, ?int $type = null): self + public function addNamed(string $name, mixed $value, string $type = 'where', ?int $pdoType = null): self { - $this->values[$name] = $value; - $this->types[$name] = $type ?? $this->guessType($value); + $this->bindings[$type][$name] = $value; + $this->types[$type][$name] = $pdoType ?? $this->guessType($value); return $this; } /** - * Récupère toutes les valeurs + * Récupère tous les bindings d'un contexte + * + * @return list|mixed */ - public function getValues(): array + public function get(string $type, ?string $name = null) { - return $this->values; + $bindings = $this->bindings[$type] ?? []; + + return $name ? ($bindings[$name] ?? null) : $bindings; + } + + /** + * Récupère tous les bindings dans l'ordre de compilation + * + * @param list $types + * + * @return list + */ + public function getOrdered(array $types = []): array + { + if ($types === []) { + $types = self::TYPES; + } + + $result = []; + foreach ($types as $type) { + if (!empty($this->bindings[$type])) { + array_push($result, ...$this->bindings[$type]); + } + } + + return $result; } /** - * Récupère tous les types + * Récupère tous les types dans l'ordre + * + * @param list $types + * + * @return list */ - public function getTypes(): array + public function getTypesOrdered(array $types = []): array { - return $this->types; + if ($types === []) { + $types = self::TYPES; + } + + $result = []; + foreach ($types as $type) { + if (!empty($this->types[$type])) { + array_push($result, ...$this->types[$type]); + } + } + + return $result; } /** - * Récupère un binding + * Vérifie si un contexte a des bindings */ - public function get(string|int $key): mixed + public function has(string $type): bool { - return $this->values[$key] ?? null; + return !empty($this->bindings[$type]); } /** - * Récupère le type d'un binding + * Compte le nombre total de bindings */ - public function getType(string|int $key): ?int + public function count(?string $type = null): int { - return $this->types[$key] ?? null; + if ($type !== null) { + return count($this->bindings[$type] ?? []); + } + + return array_sum(array_map('count', $this->bindings)); } /** - * Vérifie si des bindings existent + * Vérifie si un contexte est vide */ - public function isEmpty(): bool + public function isEmpty(?string $type = null): bool { - return empty($this->values); + return $this->count($type) === 0; } /** - * Vide la collection + * Vide tous les bindings */ - public function clear(): self + public function clear(?string $type = null): self { - $this->values = []; - $this->types = []; - + if ($type !== null) { + $this->bindings[$type] = []; + $this->types[$type] = []; + } else { + foreach (self::TYPES as $t) { + $this->bindings[$t] = []; + $this->types[$t] = []; + } + } + return $this; } /** - * Compte le nombre de bindings + * Vide les bindings d'un contexte spécifique */ - public function count(): int + public function clearType(string $type): self { - return count($this->values); + if (isset($this->bindings[$type])) { + $this->bindings[$type] = []; + $this->types[$type] = []; + } + + return $this; } /** * Fusionne une autre collection */ - public function merge(self $bindings): self + public function merge(self $collection): self { - $this->values = array_merge($this->values, $bindings->values); - $this->types = array_merge($this->types, $bindings->types); - + foreach (self::TYPES as $type) { + array_push($this->bindings[$type], ...$collection->bindings[$type]); + array_push($this->types[$type], ...$collection->types[$type]); + } + return $this; } + /** + * Retire les expressions des bindings (elles ne doivent pas être bindées) + * + * @param list $bindings + * + * @return list + */ + public function clean(array $bindings): array + { + return array_filter($bindings, fn($binding) => !$binding instanceof Expression); + } + /** * Devine le type PDO d'une valeur */ @@ -138,10 +249,21 @@ protected function guessType(mixed $value): int } /** - * Clone la collection + * Pour le débogage */ + public function toArray(): array + { + return $this->bindings; + } + public function __clone() { - // Rien de spécial à faire, les tableaux sont copiés + foreach ($this->bindings as $type => $bindings) { + $this->bindings[$type] = $bindings; + } + + foreach ($this->types as $type => $types) { + $this->types[$type] = $types; + } } -} \ No newline at end of file +} diff --git a/src/Builder/Compilers/MySQL.php b/src/Builder/Compilers/MySQL.php index 2b85768..c19042e 100644 --- a/src/Builder/Compilers/MySQL.php +++ b/src/Builder/Compilers/MySQL.php @@ -15,6 +15,39 @@ class MySQL extends QueryCompiler { + /** + * {@inheritDoc} + */ + public function compileUpdate(BaseBuilder $builder): string + { + $table = $this->db->makeTableName($builder->getTable()); + + $sql = ["UPDATE {$table}"]; + + if ([] !== $builder->joins) { + $sql[] = $this->compileJoins($builder->joins); + } + + $sets = []; + foreach ($builder->values as $column => $value) { + $column = $this->db->escapeIdentifiers($column); + $sets[] = "{$column} = " . $this->wrapValue($value); + } + + $sql[] = "SET " . implode(', ', $sets); + + if ([] !== $builder->wheres) { + $sql[] = 'WHERE'; + $sql[] = $this->compileWheres($builder->wheres); + } + + if ('' !== $limit = $this->compileLimit($builder->limit, null)) { + $sql[] = $limit; + } + + return implode(' ', array_filter($sql)); + } + /** * {@inheritDoc} */ diff --git a/src/Builder/Compilers/Postgre.php b/src/Builder/Compilers/Postgre.php index a788b17..da25a05 100644 --- a/src/Builder/Compilers/Postgre.php +++ b/src/Builder/Compilers/Postgre.php @@ -12,6 +12,7 @@ namespace BlitzPHP\Database\Builder\Compilers; use BlitzPHP\Database\Builder\BaseBuilder; +use BlitzPHP\Database\Builder\JoinClause; class Postgre extends QueryCompiler { @@ -61,11 +62,15 @@ public function compileInsertUsing(BaseBuilder $builder): string */ public function compileUpdate(BaseBuilder $builder): string { - $sql = parent::compileUpdate($builder); + if ($builder->joins === []) { + $sql = $this->compileUpdateStandard($builder); + + return "{$sql} RETURNING *"; + } - return "{$sql} RETURNING *"; + return $this->compileUpdateWithFrom($builder); } - + /** * {@inheritDoc} */ @@ -190,4 +195,54 @@ protected function compileAnyAll(string $type, string $column, string $operator, return "{$column} {$operator} {$type} ({$placeholders})"; } + + /** + * Compilation PostgreSQL avec FROM + */ + protected function compileUpdateWithFrom(BaseBuilder $builder): string + { + $table = $this->db->makeTableName($builder->getTable()); + + $sets = []; + foreach ($builder->values as $column => $value) { + $column = $this->db->escapeIdentifiers($column); + $sets[] = "{$column} = " . $this->wrapValue($value); + } + + $sql = ["UPDATE {$table}"]; + $sql[] = "SET " . implode(', ', $sets); + + // Construction de la clause FROM + $fromTables = []; + $joinConditions = []; + + foreach ($builder->joins as $join) { + if ($join instanceof JoinClause) { + $fromTables[] = $join->getTable(); + + // Convertir les conditions ON en conditions WHERE + foreach ($join->getConditions() as $condition) { + if ($condition['type'] === 'basic') { + $joinConditions[] = $condition['first'] . ' ' . + $condition['operator'] . ' ' . + $condition['second']; + } + } + } + } + + if ($fromTables !== []) { + $sql[] = "FROM " . implode(', ', $fromTables); + } + + // Fusionner les conditions WHERE originales avec les conditions de jointure + $allConditions = array_merge($joinConditions, $builder->wheres); + + if ($allConditions !== []) { + $sql[] = 'WHERE'; + $sql[] = $this->compileWheres($allConditions); + } + + return implode(' ', array_filter($sql)); + } } diff --git a/src/Builder/Compilers/QueryCompiler.php b/src/Builder/Compilers/QueryCompiler.php index bef227f..2749d40 100644 --- a/src/Builder/Compilers/QueryCompiler.php +++ b/src/Builder/Compilers/QueryCompiler.php @@ -14,6 +14,7 @@ use BlitzPHP\Database\Builder\BaseBuilder; use BlitzPHP\Database\Builder\JoinClause; use BlitzPHP\Database\Connection\BaseConnection; +use BlitzPHP\Database\Exceptions\DatabaseException; use BlitzPHP\Database\Query\Expression; use BlitzPHP\Database\Utils; use InvalidArgumentException; @@ -78,15 +79,15 @@ public function compileSelect(BaseBuilder $builder): string $sql[] = $this->compileHavings($builder->havings); } + if ([] !== $builder->unions) { + $sql[] = $this->compileUnions($builder->unions); + } + if ([] !== $builder->orders) { $sql[] = 'ORDER BY'; $sql[] = $this->compileOrders($builder->orders); } - if ([] !== $builder->unions) { - $sql[] = $this->compileUnions($builder->unions); - } - if ('' !== $limit = $this->compileLimit($builder->limit, $builder->offset)) { $sql[] = $limit; } @@ -144,20 +145,33 @@ public function compileInsertUsing(BaseBuilder $builder): string */ public function compileUpdate(BaseBuilder $builder): string { - $table = $this->db->escapeIdentifiers($builder->getTable()); + return $this->compileUpdateStandard($builder); + } + + /** + * Compilation standard sans jointure + */ + protected function compileUpdateStandard(BaseBuilder $builder): string + { + $table = $this->db->makeTableName($builder->getTable()); + + $sql = ["UPDATE {$table}"]; $sets = []; foreach ($builder->values as $column => $value) { $column = $this->db->escapeIdentifiers($column); $sets[] = "{$column} = " . $this->wrapValue($value); } - - $sql = ["UPDATE {$table} SET " . implode(', ', $sets)]; - + if ([] !== $builder->joins) { - $sql[] = $this->compileJoins($builder->joins); + // Si des jointures sont présentes mais non supportées, on lève une exception. + throw new DatabaseException( + "Les jointures dans UPDATE ne sont pas supportées par " . $this->db->getDriver() + ); } + $sql[] = "SET " . implode(', ', $sets); + if ([] !== $builder->wheres) { $sql[] = 'WHERE'; $sql[] = $this->compileWheres($builder->wheres); diff --git a/src/Builder/Compilers/SQLite.php b/src/Builder/Compilers/SQLite.php index 635d959..e81b28d 100644 --- a/src/Builder/Compilers/SQLite.php +++ b/src/Builder/Compilers/SQLite.php @@ -12,9 +12,25 @@ namespace BlitzPHP\Database\Builder\Compilers; use BlitzPHP\Database\Builder\BaseBuilder; +use BlitzPHP\Database\Exceptions\DatabaseException; class SQLite extends QueryCompiler { + /** + * {@inheritDoc} + */ + public function compileUpdate(BaseBuilder $builder): string + { + if ($builder->joins !== []) { + throw new DatabaseException( + "SQLite ne supporte pas les jointures dans les requêtes UPDATE. " . + "Utilisez des sous-requêtes à la place." + ); + } + + return $this->compileUpdateStandard($builder); + } + /** * {@inheritDoc} */ diff --git a/src/Builder/Concerns/AdvancedMethods.php b/src/Builder/Concerns/AdvancedMethods.php index dd88c2b..ee8680b 100644 --- a/src/Builder/Concerns/AdvancedMethods.php +++ b/src/Builder/Concerns/AdvancedMethods.php @@ -564,14 +564,19 @@ public function unionAll(Closure|BuilderInterface $query): static /** * Crée une requête pour UNION */ - protected function createUnionQuery(Closure|BuilderInterface $query): BuilderInterface + protected function createUnionQuery(Closure|BaseBuilder $query): BaseBuilder { if ($query instanceof Closure) { $builder = $this->newQuery(); $query($builder); + + $this->bindings->merge($builder->bindings); + return $builder; } + $this->bindings->merge($query->bindings); + return $query; } } diff --git a/src/Builder/Concerns/CoreMethods.php b/src/Builder/Concerns/CoreMethods.php index 29a8cce..c1529ef 100644 --- a/src/Builder/Concerns/CoreMethods.php +++ b/src/Builder/Concerns/CoreMethods.php @@ -213,7 +213,7 @@ public function whereInSub(string $column, Closure $callback, string $boolean = 'not' => $not, ]); - $this->bindings->addMany($query->bindings->getValues()); + $this->bindings->merge($query->bindings); return $this; } @@ -543,7 +543,7 @@ public function addNestedWhereQuery(BaseBuilder $query, string $boolean = 'and') 'boolean' => $boolean ]; - $this->bindings->addMany($query->bindings->getValues()); + $this->bindings->merge($query->bindings); } return $this; @@ -681,7 +681,7 @@ public function havingInSub(string $column, Closure $callback, string $boolean = 'not' => $not ]); - $this->bindings->addMany($query->bindings->getValues()); + $this->bindings->merge($query->bindings); return $this; } @@ -1383,10 +1383,18 @@ protected function addCondition(string $property, array|string $type, ?array $co } } + // Ajouter les bindings dans le contexte approprié + $context = match($property) { + 'wheres' => 'where', + 'havings' => 'having', + 'orders' => 'order', + default => 'where' + }; + if (isset($condition['values'])) { - $this->bindings->addMany($condition['values']); - } else if (isset($condition['value'])) { - $this->bindings->add($condition['value']); + $this->bindings->addMany($condition['values'], $context); + } else if (isset($condition['value']) && !$condition['value'] instanceof Expression) { + $this->bindings->add($condition['value'], $context); } $this->{$property}[] = $condition; diff --git a/src/Creator/BaseCreator.php b/src/Creator/BaseCreator.php index d5c0f7c..fd6a8bc 100644 --- a/src/Creator/BaseCreator.php +++ b/src/Creator/BaseCreator.php @@ -13,10 +13,9 @@ use BlitzPHP\Contracts\Database\ConnectionInterface; use BlitzPHP\Database\Connection\BaseConnection; +use BlitzPHP\Database\Exceptions\CreatorException; use BlitzPHP\Database\Exceptions\DatabaseException; -use BlitzPHP\Database\Query; -use BlitzPHP\Database\RawSql; -use BlitzPHP\Database\Result\BaseResult; +use BlitzPHP\Database\Query\Expression; use InvalidArgumentException; use RuntimeException; use Throwable; @@ -29,11 +28,6 @@ */ class BaseCreator { - /** - * La connexion a la base de donnees - */ - protected BaseConnection $db; - /** * Liste des champs sous la forme `[name => attributes]`. * @@ -65,11 +59,6 @@ class BaseCreator */ protected array $foreignKeys = []; - /** - * Character set utilisee. - */ - protected string $charset = ''; - /** * requete CREATE DATABASE. * @@ -176,11 +165,45 @@ class BaseCreator protected array $dataCache = []; /** - * Constructor. + * Drapeau de debugage. + * Doit on afficher les erreurs ? + */ + protected bool $debug = false; + + /** + * Character set + */ + protected string $charset = ''; + + /** + * Collation + */ + protected string $collation = ''; + + /** + * Prefix des tables + */ + protected string $prefix = ''; + + /** + * Pilote de la base de donnees */ - public function __construct(BaseConnection $db) + protected string $driver = ''; + + /** + * Constructeur. + * + * @param BaseConnection $db La connexion a la base de donnees + */ + public function __construct(protected BaseConnection $db) { - $this->db = $db; + $config = $this->db->getConfig(); + + $this->debug = $config['debug'] ?? false; + $this->charset = $config['charset'] ?? ''; + $this->collation = $config['collation'] ?? ''; + $this->prefix = $db->getPrefix(); + $this->driver = $db->getDriver(); } /** @@ -220,7 +243,7 @@ public function typeOf(?string $type = null) * * @param bool $ifNotExists Specifie si on doit ajouter la condition IF NOT EXISTS * - * @throws DatabaseException + * @throws CreatorException */ public function createDatabase(string $dbName, bool $ifNotExists = false): bool { @@ -233,94 +256,94 @@ public function createDatabase(string $dbName, bool $ifNotExists = false): bool } if ($this->createDatabaseStr === false) { - if ($this->db->debug) { - throw new DatabaseException('Cette fonctionnalité n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('CREATE DATABASE'); } - return false; // @codeCoverageIgnore + return false; } try { - if (! $this->db->query( - sprintf( - $ifNotExists ? $this->createDatabaseIfStr : $this->createDatabaseStr, - $this->db->escapeIdentifier($dbName), - $this->db->charset, - $this->db->collation - ) - )) { - // @codeCoverageIgnoreStart - if ($this->db->debug) { - throw new DatabaseException('Impossible de créer la base de données spécifiée.'); - } - - return false; - // @codeCoverageIgnoreEnd + $result = $this->db->statement(sprintf( + $ifNotExists ? $this->createDatabaseIfStr : $this->createDatabaseStr, + $this->db->escapeIdentifier($dbName), + $this->charset, + $this->collation + )); + + if (! $result && $this->debug) { + throw CreatorException::unableToCreateDatabase($dbName); } if (! empty($this->dataCache['db_names'])) { $this->dataCache['db_names'][] = $dbName; } - return true; + return $result; } catch (Throwable $e) { - if ($this->db->debug) { - throw new DatabaseException('Impossible de créer la base de données spécifiée.', 0, $e); + if ($this->debug) { + throw CreatorException::unableToCreateDatabase($dbName, $e); } - return false; // @codeCoverageIgnore + return false; } } /** * Determine si une base de donnees existe * - * @throws DatabaseException + * @throws CreatorException */ private function databaseExists(string $dbName): bool { if ($this->checkDatabaseExistStr === null) { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('DATABASE EXISTS'); } return false; } - return $this->db->query($this->checkDatabaseExistStr, $dbName)->first() !== null; + return $this->db->query($this->checkDatabaseExistStr, [$dbName])->first() !== null; } /** * Supprime la base de donnees * - * @throws DatabaseException + * @throws CreatorException */ public function dropDatabase(string $dbName): bool { if ($this->dropDatabaseStr === false) { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('DROP DATABASE'); } return false; } - if (! $this->db->query(sprintf($this->dropDatabaseStr, $this->db->escapeIdentifier($dbName)))) { - if ($this->db->debug) { - throw new DatabaseException('Impossible de supprimer la base de données spécifiée.'); + try { + $result = $this->db->statement(sprintf($this->dropDatabaseStr, $this->db->escapeIdentifier($dbName))); + + if (! $result && $this->debug) { + throw CreatorException::unableToDropDatabase($dbName); + } + + if (! empty($this->dataCache['db_names'])) { + $key = array_search(strtolower($dbName), array_map('strtolower', $this->dataCache['db_names']), true); + if ($key !== false) { + unset($this->dataCache['db_names'][$key]); + } + } + + return $result; + } catch (Throwable $e) { + if ($this->debug) { + throw CreatorException::unableToDropDatabase($dbName, $e); } return false; } - - if (! empty($this->dataCache['db_names'])) { - $key = array_search(strtolower($dbName), array_map('strtolower', $this->dataCache['db_names']), true); - if ($key !== false) { - unset($this->dataCache['db_names'][$key]); - } - } - - return true; } /** @@ -408,8 +431,6 @@ public function addField(array|string $field): static * * @param list|string $fieldName * @param list|string $tableField - * - * @throws DatabaseException */ public function addForeignKey(array|string $fieldName = '', string $tableName = '', array|string $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = ''): static { @@ -431,37 +452,29 @@ public function addForeignKey(array|string $fieldName = '', string $tableName = /** * Supprime une cle. * - * @throws DatabaseException + * @throws CreatorException */ public function dropKey(string $table, string $keyName, bool $prefixKeyName = true): bool { - $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->prefix : '') . $keyName); + $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->prefix : '') . $keyName); $table = $this->db->prefixTable($table); $dropKeyAsConstraint = $this->dropKeyAsConstraint($table, $keyName); if ($dropKeyAsConstraint === true) { - $sql = sprintf( - $this->dropConstraintStr, - $table, - $keyName, - ); + $sql = sprintf($this->dropConstraintStr, $table, $keyName); } else { - $sql = sprintf( - $this->dropIndexStr, - $keyName, - $table, - ); + $sql = sprintf($this->dropIndexStr, $keyName, $table); } if ($sql === '') { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('DROP KEY'); } return false; } - return $this->db->query($sql); + return $this->db->statement($sql); } /** @@ -475,7 +488,7 @@ protected function dropKeyAsConstraint(string $table, string $constraintName): b return false; } - return $this->db->query($sql)->resultArray() !== []; + return $this->db->statement($sql); } /** @@ -494,18 +507,16 @@ public function dropPrimaryKey(string $table, string $keyName = ''): bool $sql = sprintf( 'ALTER TABLE %s DROP CONSTRAINT %s', $this->db->prefixTable($table), - ($keyName === '') ? $this->db->escapeIdentifiers('pk_' . $this->db->prefix . $table) : $this->db->escapeIdentifiers($keyName), + ($keyName === '') ? $this->db->escapeIdentifiers('pk_' . $this->prefix . $table) : $this->db->escapeIdentifiers($keyName), ); - return $this->db->query($sql); + return $this->db->statement($sql); } /** - * @return BaseResult|bool|false|mixed|Query - * - * @throws DatabaseException + * @throws CreatorException */ - public function dropForeignKey(string $table, string $foreignName) + public function dropForeignKey(string $table, string $foreignName): bool { $sql = sprintf( (string) $this->dropConstraintStr, @@ -514,22 +525,21 @@ public function dropForeignKey(string $table, string $foreignName) ); if ($sql === '') { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('DROP FOREIGN KEY'); } return false; } - return $this->db->query($sql); + return $this->db->statement($sql); } /** - * @return mixed - * - * @throws DatabaseException + * @throws InvalidArgumentException + * @throws CreatorException */ - public function createTable(string $table, bool $ifNotExists = false, array $attributes = []) + public function createTable(string $table, bool $ifNotExists = false, array $attributes = []): bool { if ($table === '') { throw new InvalidArgumentException('Un nom de table est nécessaire pour cette opération.'); @@ -542,7 +552,7 @@ public function createTable(string $table, bool $ifNotExists = false, array $att } // Si la table existe pas la peine d'aller plus loin - if ($ifNotExists === true && $this->db->tableExists($table, false)) { + if ($ifNotExists === true && $this->db->tableExists($table)) { $this->reset(); return true; @@ -550,7 +560,7 @@ public function createTable(string $table, bool $ifNotExists = false, array $att $sql = $this->_createTable($table, $attributes); - if (($result = $this->db->query($sql)) !== false) { + if (true === $result = $this->db->statement($sql)) { if (isset($this->dataCache['table_names']) && ! in_array($table, $this->dataCache['table_names'], true)) { $this->dataCache['table_names'][] = $table; } @@ -558,7 +568,7 @@ public function createTable(string $table, bool $ifNotExists = false, array $att // La plupart des bases de données ne permettent pas de créer des index à partir de l'instruction CREATE TABLE if (! empty($this->keys)) { for ($i = 0, $sqls = $this->_processIndexes($table), $c = count($sqls); $i < $c; $i++) { - $this->db->query($sqls[$i]); + $this->db->statement($sqls[$i]); } } } @@ -613,21 +623,19 @@ protected function _createTableAttributes(array $attributes): string } /** - * @return mixed - * - * @throws DatabaseException + * @throws CreatorException */ - public function dropTable(string $tableName, bool $ifExists = false, bool $cascade = false) + public function dropTable(string $tableName, bool $ifExists = false, bool $cascade = false): bool { if ($tableName === '') { - if ($this->db->debug) { - throw new DatabaseException('Un nom de table est nécessaire pour cette opération.'); + if ($this->debug) { + throw CreatorException::needTableName(); } return false; } - $prefix = $this->db->getPrefix(); + $prefix = $this->prefix; if ($prefix !== '' && str_starts_with($tableName, $prefix)) { $tableName = substr($tableName, strlen($prefix)); } @@ -638,11 +646,11 @@ public function dropTable(string $tableName, bool $ifExists = false, bool $casca $this->db->disableForeignKeyChecks(); - $query = $this->db->query($query); + $result = $this->db->statement($query); $this->db->enableForeignKeyChecks(); - if ($query && ! empty($this->dataCache['table_names'])) { + if ($result === true && ! empty($this->dataCache['table_names'])) { $key = array_search( strtolower($prefix . $tableName), array_map('strtolower', $this->dataCache['table_names']), @@ -654,7 +662,7 @@ public function dropTable(string $tableName, bool $ifExists = false, bool $casca } } - return $query; + return $result; } /** @@ -680,25 +688,24 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade) } /** - * @return mixed - * - * @throws DatabaseException + * @throws InvalidArgumentException + * @throws CreatorException */ - public function renameTable(string $tableName, string $newTableName) + public function renameTable(string $tableName, string $newTableName): bool { if ($tableName === '' || $newTableName === '') { throw new InvalidArgumentException('Un nom de table est nécessaire pour cette opération.'); } if ($this->renameTableStr === false) { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('RENAME TABLE'); } return false; } - $result = $this->db->query(sprintf( + $result = $this->db->statement(sprintf( $this->renameTableStr, $this->db->prefixTable($tableName), $this->db->prefixTable($newTableName) @@ -706,13 +713,13 @@ public function renameTable(string $tableName, string $newTableName) if ($result && ! empty($this->dataCache['table_names'])) { $key = array_search( - strtolower($this->db->prefix . $tableName), + strtolower($this->prefix . $tableName), array_map('strtolower', $this->dataCache['table_names']), true ); if ($key !== false) { - $this->dataCache['table_names'][$key] = $this->db->prefix . $newTableName; + $this->dataCache['table_names'][$key] = $this->prefix . $newTableName; } } @@ -722,7 +729,7 @@ public function renameTable(string $tableName, string $newTableName) /** * @param array|string $field * - * @throws DatabaseException + * @throws CreatorException */ public function addColumn(string $table, array|string $field): bool { @@ -735,19 +742,19 @@ public function addColumn(string $table, array|string $field): bool $this->addField([$name => $field[$name]]); } - $sqls = $this->_alterTable('ADD', $this->db->prefix . $table, $this->_processFields()); + $sqls = $this->_alterTable('ADD', $this->prefix . $table, $this->_processFields()); $this->reset(); if ($sqls === false) { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('ADD COLUMN'); } return false; } foreach ($sqls as $sql) { - if ($this->db->query($sql) === false) { + if ($this->db->statement($sql) === false) { return false; } } @@ -758,23 +765,21 @@ public function addColumn(string $table, array|string $field): bool /** * @param list|string $columnName Noms des champs à supprimer * - * @return mixed - * - * @throws DatabaseException + * @throws CreatorException */ - public function dropColumn(string $table, array|string $columnName) + public function dropColumn(string $table, array|string $columnName): bool { - $sql = $this->_alterTable('DROP', $this->db->prefix . $table, $columnName); + $sql = $this->_alterTable('DROP', $this->prefix . $table, $columnName); if ($sql === false) { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('DROP COLUMN'); } return false; } - return $this->db->query($sql); + return $this->db->statement($sql); } /** @@ -795,12 +800,12 @@ public function modifyColumn(string $table, array|string $field): bool throw new RuntimeException('Les informations du champ sont requises'); } - $sqls = $this->_alterTable('CHANGE', $this->db->prefix . $table, $this->_processFields()); + $sqls = $this->_alterTable('CHANGE', $this->prefix . $table, $this->_processFields()); $this->reset(); if ($sqls === false) { - if ($this->db->debug) { - throw new DatabaseException('Cette fonction n\'est pas disponible pour la base de données que vous utilisez.'); + if ($this->debug) { + throw CreatorException::unsupportedFeature('MODIFY COLUMN'); } return false; @@ -808,7 +813,7 @@ public function modifyColumn(string $table, array|string $field): bool if (is_array($sqls)) { foreach ($sqls as $sql) { - if ($this->db->query($sql) === false) { + if ($this->db->statement($sql) === false) { return false; } } @@ -827,7 +832,7 @@ public function modifyColumn(string $table, array|string $field): bool */ public function renameColumn(string $table, string $from, string $to): bool { - $field = array_filter($this->db->getFieldData($table), static fn ($field) => $field->name === $from); + $field = array_filter($this->db->getColumnData($table), static fn ($field) => $field->name === $from); $field = array_shift($field); if (null === $field) { @@ -1042,7 +1047,7 @@ protected function _attributeDefault(array &$attributes, array &$field) // Remplacer l'attribut NULL si c'est notre valeur par défaut $attributes['NULL'] = true; $field['null'] = empty($this->null) ? '' : ' ' . $this->null; - } elseif ($attributes['DEFAULT'] instanceof RawSql) { + } elseif ($attributes['DEFAULT'] instanceof Expression) { $field['default'] = $this->default . $attributes['DEFAULT']; } else { $field['default'] = $this->default . $this->db->escape($attributes['DEFAULT']); @@ -1085,7 +1090,7 @@ protected function _processPrimaryKeys(string $table, bool $asQuery = false): st if (isset($this->primaryKeys['fields']) && $this->primaryKeys['fields'] !== []) { if ($asQuery === true) { - $sql .= 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->db->prefix . $table) . ' ADD '; + $sql .= 'ALTER TABLE ' . $this->db->prefixTable($table) . ' ADD '; } else { $sql .= ",\n\t"; } @@ -1107,7 +1112,7 @@ public function processIndexes(string $table): bool $fk = $this->foreignKeys; if ([] === $this->fields) { - $fieldData = $this->db->getFieldData($this->db->prefix . $table); + $fieldData = $this->db->getColumnData($this->db->prefixTable($table)); $this->fields = array_combine( array_map(static fn ($columnName) => $columnName->name, $fieldData), @@ -1118,7 +1123,7 @@ public function processIndexes(string $table): bool $fields = $this->fields; if ([] !== $this->keys) { - $sqls = $this->_processIndexes($this->db->prefix . $table, true); + $sqls = $this->_processIndexes($this->prefix . $table, true); } if ([] !== $this->primaryKeys) { @@ -1168,12 +1173,12 @@ protected function _processIndexes(string $table, bool $asQuery = false): array $this->keys[$i]['keyName']); if (in_array($i, $this->uniqueKeys, true)) { - if ($this->db->driver === 'SQLite3') { + if ($this->driver === 'sqlite') { $sqls[] = 'CREATE UNIQUE INDEX ' . $keyName . ' ON ' . $this->db->escapeIdentifiers($table) . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; } else { - $sqls[] = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table) + $sqls[] = 'ALTER TABLE ' . $this->db->prefixTable($table) . ' ADD CONSTRAINT ' . $keyName . ' UNIQUE (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; } @@ -1182,7 +1187,7 @@ protected function _processIndexes(string $table, bool $asQuery = false): array } $sqls[] = 'CREATE INDEX ' . $keyName - . ' ON ' . $this->db->escapeIdentifiers($table) + . ' ON ' . $this->db->prefixTable($table) . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; } @@ -1223,15 +1228,15 @@ protected function _processForeignKeys(string $table, bool $asQuery = false): ar $nameIndex = $fkey['fkName'] !== '' ? $fkey['fkName'] : - $table . '_' . implode('_', $fkey['field']) . ($this->db->driver === 'OCI8' ? '_fk' : '_foreign'); + $table . '_' . implode('_', $fkey['field']) . ($this->driver === 'OCI8' ? '_fk' : '_foreign'); $nameIndexFilled = $this->db->escapeIdentifiers($nameIndex); $foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field'])); - $referenceTableFilled = $this->db->escapeIdentifiers($this->db->prefix . $fkey['referenceTable']); + $referenceTableFilled = $this->db->escapeIdentifiers($this->prefix . $fkey['referenceTable']); $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); if ($asQuery === true) { - $sqls[$index] .= 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->db->prefix . $table) . ' ADD '; + $sqls[$index] .= 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->prefix . $table) . ' ADD '; } else { $sqls[$index] .= ",\n\t"; } @@ -1243,7 +1248,7 @@ protected function _processForeignKeys(string $table, bool $asQuery = false): ar $sqls[$index] .= ' ON DELETE ' . $fkey['onDelete']; } - if ($this->db->driver !== 'OCI8' && $fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $this->fkAllowActions, true)) { + if ($this->driver !== 'OCI8' && $fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $this->fkAllowActions, true)) { $sqls[$index] .= ' ON UPDATE ' . $fkey['onUpdate']; } } diff --git a/src/Creator/MySQL.php b/src/Creator/MySQL.php index fa55a68..02275c0 100644 --- a/src/Creator/MySQL.php +++ b/src/Creator/MySQL.php @@ -151,11 +151,11 @@ protected function _createTableAttributes(array $attributes): string } if (! empty($this->db->charset) && ! strpos($sql, 'CHARACTER SET') && ! strpos($sql, 'CHARSET')) { - $sql .= ' DEFAULT CHARACTER SET = ' . $this->db->escapeString($this->db->charset); + $sql .= ' DEFAULT CHARACTER SET = ' . $this->db->escapeString($this->charset); } if (! empty($this->db->collation) && ! strpos($sql, 'COLLATE')) { - $sql .= ' COLLATE = ' . $this->db->escapeString($this->db->collation); + $sql .= ' COLLATE = ' . $this->db->escapeString($this->collation); } return $sql; @@ -269,10 +269,10 @@ public function dropKey(string $table, string $keyName, bool $prefixKeyName = tr $sql = sprintf( $this->dropIndexStr, $this->db->escapeIdentifiers($keyName), - $this->db->escapeIdentifiers($this->db->prefix . $table), + $this->db->prefixTable($table), ); - return $this->db->query($sql); + return $this->db->statement($sql); } /** @@ -282,9 +282,9 @@ public function dropPrimaryKey(string $table, string $keyName = ''): bool { $sql = sprintf( 'ALTER TABLE %s DROP PRIMARY KEY', - $this->db->escapeIdentifiers($this->db->prefix . $table) + $this->db->prefixTable($table) ); - return $this->db->query($sql); + return $this->db->statement($sql); } } diff --git a/src/Creator/Postgre.php b/src/Creator/Postgre.php index cc83ebd..9e0645d 100644 --- a/src/Creator/Postgre.php +++ b/src/Creator/Postgre.php @@ -11,9 +11,6 @@ namespace BlitzPHP\Database\Creator; -use BlitzPHP\Database\Connection\BaseConnection; -use BlitzPHP\Database\Connection\Postgre as ConnectionPostgre; - /** * Createur Postgre * @@ -56,13 +53,6 @@ class Postgre extends BaseCreator */ protected string $null = 'NULL'; - /** - * {@inheritDoc} - * - * @var ConnectionPostgre - */ - protected BaseConnection $db; - /** * {@inheritDoc} */ @@ -250,13 +240,15 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str */ protected function _dropKeyAsConstraint(string $table, string $constraintName): string { + $schema = $this->db->getConfig('schema'); + return "SELECT con.conname FROM pg_catalog.pg_constraint con INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace - WHERE nsp.nspname = '{$this->db->schema}' + WHERE nsp.nspname = '{$schema}' AND rel.relname = '" . trim($table, '"') . "' AND con.conname = '" . trim($constraintName, '"') . "'"; } diff --git a/src/Creator/SQLite.php b/src/Creator/SQLite.php index 1cc3f27..860cfd2 100644 --- a/src/Creator/SQLite.php +++ b/src/Creator/SQLite.php @@ -14,6 +14,7 @@ use BlitzPHP\Database\Connection\BaseConnection; use BlitzPHP\Database\Connection\SQLite as SQLiteConnection; use BlitzPHP\Database\Creator\SQLite\Table; +use BlitzPHP\Database\Exceptions\CreatorException; use BlitzPHP\Database\Exceptions\DatabaseException; /** @@ -70,17 +71,17 @@ class SQLite extends BaseCreator 'year' => 'INTEGER', 'binary' => 'BLOB', - 'char' => 'VARCHAR', + 'char' => 'TEXT', 'longText' => 'TEXT', 'mediumText' => 'TEXT', - 'string' => 'VARCHAR', + 'string' => 'TEXT', 'text' => 'TEXT', - 'uuid' => ['VARCHAR', 36], - 'ipAddress' => ['VARCHAR', 45], - 'macAddress' => ['VARCHAR', 17], + 'uuid' => ['TEXT', 36], + 'ipAddress' => ['TEXT', 45], + 'macAddress' => ['TEXT', 17], - 'enum' => 'VARCHAR CHECK ({column} in ({allowed}))', + 'enum' => 'TEXT CHECK ({column} in ({allowed}))', 'set' => false, 'json' => 'TEXT', @@ -129,8 +130,8 @@ public function dropDatabase(string $dbName): bool { // Dans SQLite, une bd est effacée quand on supprime un fichier if (! is_file($dbName)) { - if ($this->db->debug) { - throw new DatabaseException('Impossible de supprimer la base de données spécifiée.'); + if ($this->debug) { + throw CreatorException::unableToDropDatabase($dbName); } return false; @@ -140,17 +141,17 @@ public function dropDatabase(string $dbName): bool $this->db->close(); if (! @unlink($dbName)) { - if ($this->db->debug) { - throw new DatabaseException('Impossible de supprimer la base de données spécifiée.'); + if ($this->debug) { + throw CreatorException::unableToDropDatabase($dbName); } return false; } - if (! empty($this->db->dataCache['db_names'])) { - $key = array_search(strtolower($dbName), array_map('strtolower', $this->db->dataCache['db_names']), true); + if (! empty($this->dataCache['db_names'])) { + $key = array_search(strtolower($dbName), array_map('strtolower', $this->dataCache['db_names']), true); if ($key !== false) { - unset($this->db->dataCache['db_names'][$key]); + unset($this->dataCache['db_names'][$key]); } } @@ -169,12 +170,12 @@ public function dropColumn(string $table, $columnNames): bool $columns = is_array($columnNames) ? $columnNames : array_map(trim(...), explode(',', $columnNames)); $result = (new Table($this->db, $this)) - ->fromTable($this->db->prefix . $table) + ->fromTable($this->prefix . $table) ->dropColumn($columns) ->run(); - if (! $result && $this->db->debug) { - throw new DatabaseException(sprintf( + if (! $result && $this->debug) { + throw new CreatorException(sprintf( 'Failed to drop column%s "%s" on "%s" table.', count($columns) > 1 ? 's' : '', implode('", "', $columns), @@ -228,12 +229,22 @@ protected function _alterTable(string $alterType, string $table, $processedField */ protected function _processColumn(array $processedField): string { - if ($processedField['type'] === 'TEXT' && str_starts_with($processedField['length'], "('")) { - $processedField['type'] .= ' CHECK(' . $this->db->escapeIdentifiers($processedField['name']) - . ' IN ' . $processedField['length'] . ')'; - } + $column = $this->db->escapeIdentifiers($processedField['name']); + + if ($processedField['type'] === 'TEXT') { + // Retirer les parenthèses autour de la contrainte + $constraint = trim($processedField['length'], '()'); + + if (str_starts_with($constraint, "'")) { + // Cas énumération : ('A','B','C') + $processedField['type'] .= ' CHECK(' . $column . ' IN (' . $constraint . '))'; + } elseif (ctype_digit($constraint) && (int)$constraint > 0) { + // Cas longueur numérique : (255) + $processedField['type'] .= ' CHECK(length(' . $column . ') <= ' . (int)$constraint . ')'; + } + } - return $this->db->escapeIdentifiers($processedField['name']) + return $column . ' ' . $processedField['type'] . $processedField['auto_increment'] . $processedField['null'] @@ -293,7 +304,7 @@ public function dropForeignKey(string $table, string $foreignName): bool // Sinon, nous devons copier la table et la recréer sans que la clé étrangère ne soit impliquée. $sqlTable = new Table($this->db, $this); - return $sqlTable->fromTable($this->db->prefix . $table) + return $sqlTable->fromTable($this->prefix . $table) ->dropForeignKey($foreignName) ->run(); } @@ -305,7 +316,7 @@ public function dropPrimaryKey(string $table, string $keyName = ''): bool { $sqlTable = new Table($this->db, $this); - return $sqlTable->fromTable($this->db->prefix . $table) + return $sqlTable->fromTable($this->prefix . $table) ->dropPrimaryKey() ->run(); } @@ -313,14 +324,14 @@ public function dropPrimaryKey(string $table, string $keyName = ''): bool /** * {@inheritDoc} */ - public function addForeignKey(array|string $fieldName = '', string $tableName = '', array|string $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = ''): self + public function addForeignKey(array|string $fieldName = '', string $tableName = '', array|string $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = ''): static { $fkName = ''; if ($fkName === '') { return parent::addForeignKey($fieldName, $tableName, $tableField, $onUpdate, $onDelete, $fkName); } - throw new DatabaseException('SQLite ne supporte pas les noms de clés étrangères. BlitzPHP se referera à sa suivant le format: prefix_table_column_referencecolumn_foreign'); + throw new CreatorException('SQLite ne supporte pas les noms de clés étrangères. BlitzPHP se referera à sa suivant le format: prefix_table_column_referencecolumn_foreign'); } /** @@ -334,7 +345,7 @@ protected function _processPrimaryKeys(string $table, bool $asQuery = false): st $sqlTable = new Table($this->db, $this); - $sqlTable->fromTable($this->db->prefix . $table) + $sqlTable->fromTable($this->prefix . $table) ->addPrimaryKey($this->primaryKeys) ->run(); @@ -368,7 +379,7 @@ protected function _processForeignKeys(string $table, bool $asQuery = false): ar $sqlTable = new Table($this->db, $this); - $sqlTable->fromTable($this->db->prefix . $table) + $sqlTable->fromTable($this->prefix . $table) ->addForeignKey($this->foreignKeys) ->run(); diff --git a/src/Creator/SQLite/Table.php b/src/Creator/SQLite/Table.php index dd1b998..198cb6f 100644 --- a/src/Creator/SQLite/Table.php +++ b/src/Creator/SQLite/Table.php @@ -67,7 +67,7 @@ public function fromTable(string $table): self { $this->prefixedTableName = $table; - $prefix = $this->db->prefix; + $prefix = $this->db->getPrefix(); if (! empty($prefix) && str_starts_with($table, $prefix)) { $table = substr($table, strlen($prefix)); @@ -102,7 +102,7 @@ public function fromTable(string $table): self */ public function run(): bool { - $this->db->query('PRAGMA foreign_keys = OFF'); + $this->db->disableForeignKeyChecks(); $this->db->transStart(); @@ -118,7 +118,7 @@ public function run(): bool $success = $this->db->transComplete(); - $this->db->query('PRAGMA foreign_keys = ON'); + $this->db->enableForeignKeyChecks(); $this->db->resetDataCache(); @@ -291,10 +291,12 @@ protected function createTable() } } + $prefix = $this->db->getPrefix(); + foreach ($this->foreignKeys as $foreignKey) { $this->creator->addForeignKey( $foreignKey->column_name, - trim($foreignKey->foreign_table_name, $this->db->DBPrefix), + trim($foreignKey->foreign_table_name, $prefix), $foreignKey->foreign_column_name ); } @@ -325,8 +327,8 @@ protected function copyData(): void array_map(fn ($item) => $this->db->protectIdentifiers($item), $newFields) ); - $this->db->query( - "INSERT INTO {$this->prefixedTableName}({$newFields}) SELECT {$exFields} FROM {$this->db->DBPrefix}temp_{$this->tableName}" + $this->db->statement( + "INSERT INTO {$this->prefixedTableName}({$newFields}) SELECT {$exFields} FROM {$this->db->getPrefix()}temp_{$this->tableName}" ); } diff --git a/src/Exceptions/CreatorException.php b/src/Exceptions/CreatorException.php index 1465897..83cbb97 100644 --- a/src/Exceptions/CreatorException.php +++ b/src/Exceptions/CreatorException.php @@ -11,6 +11,8 @@ namespace BlitzPHP\Database\Exceptions; +use Throwable; + /** * Exception pour la couche Creator */ @@ -39,4 +41,19 @@ public static function invalidFieldType(string $type): self [$type] )); } + + public static function unableToCreateDatabase(string $name, ?Throwable $previous = null): self + { + return new static(static::t('Impossible de créer la base de données "%s".', [$name]), previous: $previous); + } + + public static function unableToDropDatabase(string $name, ?Throwable $previous = null): self + { + return new static(static::t('Impossible de supprimer la base de données "%s".', [$name]), previous: $previous); + } + + public static function needTableName(): self + { + return new static(static::t('Un nom de table est nécessaire pour cette opération.')); + } }