Files
mesreleves-php/app/Support/DbCompat.php
T
yann64 236d37976c Compatibilité MySQL + suppression de Redis comme dépendance requise
DbCompat (app/Support/DbCompat.php) :
- like()           → ilike (pgsql) ou like (mysql)
- jsonRegexRaw()   → data::text ~* ? (pgsql) ou CAST(data AS CHAR) REGEXP ? (mysql)
- ftsRaw()         → to_tsvector/plainto_tsquery (pgsql) ou null/fallback LIKE (mysql)
- generatedJsonCol()       → syntaxe colonne générée JSON selon le SGBD
- generatedJsonNestedCol() → idem pour champs imbriqués

Migrations :
- create_releves_table : JSON/JSONB selon SGBD, colonnes générées adaptées,
  index GIN uniquement pour PostgreSQL

Controllers :
- LieuController (search + index) : ilike → DbCompat::like()
- Admin\UserController (index)     : ilike → DbCompat::like()
- RechercheController              : FTS + regex → DbCompat, fallback LIKE MySQL
- ExportController                 : regex → DbCompat::jsonRegexRaw()

UpdateService :
- backupDatabase()  : pg_dump (pgsql) ou mysqldump (mysql)
- restoreBackup()   : psql (pgsql) ou mysql (mysql)

Docker :
- docker-compose.yml       : suppression Redis (plus requis)
- docker-compose.mysql.yml : nouveau fichier pour dev MySQL
- docker-compose.prod.yml  : suppression Redis, DB_IMAGE configurable,
  CACHE_STORE/SESSION_DRIVER/QUEUE_CONNECTION → database par défaut

.env.example :
- DB_PORT commenté avec les deux valeurs (5432/3306)
- CACHE_STORE et QUEUE_CONNECTION commentés (database par défaut)
- Redis marqué optionnel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 18:13:42 +02:00

75 lines
2.2 KiB
PHP

<?php
namespace App\Support;
use Illuminate\Support\Facades\DB;
/**
* Helpers pour les différences de syntaxe SQL entre PostgreSQL et MySQL.
*/
class DbCompat
{
public static function isPgsql(): bool
{
return DB::connection()->getDriverName() === 'pgsql';
}
/** Opérateur LIKE insensible à la casse */
public static function like(): string
{
return self::isPgsql() ? 'ilike' : 'like';
}
/** Caste une colonne JSON en texte brut */
public static function jsonToText(string $column): string
{
return self::isPgsql()
? "{$column}::text"
: "CAST({$column} AS CHAR)";
}
/**
* Condition de correspondance regex (insensible à la casse) sur une colonne JSON.
* Retourne la chaîne à passer à whereRaw() avec un seul binding `?`.
*/
public static function jsonRegexRaw(string $column = 'data'): string
{
return self::isPgsql()
? "{$column}::text ~* ?"
: "CAST({$column} AS CHAR) REGEXP ?";
}
/**
* Condition de recherche plein-texte.
* Retourne null pour MySQL (le caller doit prévoir un fallback LIKE).
*/
public static function ftsRaw(): ?string
{
return self::isPgsql()
? "to_tsvector('french', data::text) @@ plainto_tsquery('french', ?)"
: null;
}
/** Syntaxe de la colonne générée stockée pour extraire un champ JSON de premier niveau */
public static function generatedJsonCol(string $jsonKey): string
{
return self::isPgsql()
? "data->>'$jsonKey'"
: "JSON_UNQUOTE(JSON_EXTRACT(data, '$.$jsonKey'))";
}
/** Syntaxe de la colonne générée stockée pour un champ JSON imbriqué (ex: date_evenement.valeur) */
public static function generatedJsonNestedCol(string $jsonPath): string
{
if (self::isPgsql()) {
// data->'date_evenement'->>'valeur'
$parts = explode('.', $jsonPath);
$last = array_pop($parts);
$chain = implode('', array_map(fn ($p) => "->'{$p}'", $parts));
return "data{$chain}->>'{$last}'";
}
// MySQL: $.date_evenement.valeur
return "JSON_UNQUOTE(JSON_EXTRACT(data, '$.{$jsonPath}'))";
}
}