diff --git a/Module.php b/Module.php index 38dc81c3df39f6fdc10844f07198076aae9d050a..2f023a7ced2b3642b7b61ae19ae3a65c4a42f782 100644 --- a/Module.php +++ b/Module.php @@ -9,15 +9,8 @@ use Laminas\Mvc\MvcEvent; */ class Module { - public function onBootstrap(MvcEvent $e) - { - - } - - - public function getConfig() { return include __DIR__ . '/config/module.config.php'; } -} +} \ No newline at end of file diff --git a/config/module.config.php b/config/module.config.php index b993871588bc49ad86c0572b4309a85e02710f32..7d4bc094a599921fa5d83ac2f0b6703c3f51acb8 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -1,3 +1,60 @@ <?php -return []; \ No newline at end of file +namespace Unicaen\BddAdmin; + +return [ + 'unicaen-bddadmin' => [ + + 'connection' => [ + 'default' => [ + 'driver' => 'Postgresql', // par défaut, ou Oracle ou Mysql + 'host' => '', + 'port' => '', + 'dbname' => '', + 'user' => '', + 'password' => '', + ], + // Autres instances de la BDD + ], + + 'ddl' => [ + 'dir' => 'data/ddl', + 'columns_positions_file' => 'data/ddl_columns_pos.php', + ], + + 'data' => [ + 'sources' => [], + 'actions' => [], + 'config' => [], // configuration par tables + ], + + 'migration' => [ + 'dir' => 'Application/src/Migration', + ], + + 'id_column' => 'id', + + 'histo' => [ + 'user_id' => null, + 'histo_creation_column' => 'histo_creation', + 'histo_modification_column' => 'histo_modification', + 'histo_destruction_column' => 'histo_destruction', + 'histo_createur_id_column' => 'histo_createur_id', + 'histo_modificateur_id_column' => 'histo_modificateur_id', + 'histo_destructeur_id_column' => 'histo_destructeur_id', + ], + + 'import' => [ + 'source_id' => null, + 'source_id_column' => 'source_id', + 'source_code_column' => 'source_code', + ], + ], + + + 'service_manager' => [ + 'factories' => [ + Bdd::class => BddFactory::class, + ], + ], +]; \ No newline at end of file diff --git a/doc/options.md b/doc/options.md index 5ad34c2e81d80512d837bda5b6d5aa4d8cea0c83..2aea7af8767ab3ee9e0382d4e1955e016449dc7e 100644 --- a/doc/options.md +++ b/doc/options.md @@ -1,9 +1,4 @@ # Options - - -- hasOption -- getOption -- setOption - getOptions - setOptions \ No newline at end of file diff --git a/src/Bdd.php b/src/Bdd.php index 0ae32bf0e6e8155f244815273475a0c9c9b48240..b8af3cab41a5a05d6f563be35e9d6f133d2dd55e 100644 --- a/src/Bdd.php +++ b/src/Bdd.php @@ -2,14 +2,13 @@ namespace Unicaen\BddAdmin; +use Unicaen\BddAdmin\Data\DataManager; use Unicaen\BddAdmin\Ddl\Ddl; use Unicaen\BddAdmin\Ddl\DdlDiff; use Unicaen\BddAdmin\Ddl\DdlFilters; use Unicaen\BddAdmin\Driver\DriverInterface; use Unicaen\BddAdmin\Event\EventManagerAwareTrait; use Unicaen\BddAdmin\Exception\BddCompileException; -use Unicaen\BddAdmin\Exception\BddException; -use Unicaen\BddAdmin\Exception\BddIndexExistsException; use Unicaen\BddAdmin\Logger\DefaultLogger; use Unicaen\BddAdmin\Logger\LoggerAwareTrait; use Unicaen\BddAdmin\Manager\CompilableInterface; @@ -30,15 +29,33 @@ use Unicaen\BddAdmin\Manager\ViewManagerInterface; use \Exception; use Unicaen\BddAdmin\Manager\VoidManager; use Unicaen\BddAdmin\Migration\MigrationManager; +use Unicaen\BddAdmin\Trait\OptionsTrait; class Bdd { use EventManagerAwareTrait; use LoggerAwareTrait; - - const OPTION_DDL_DIR = 'ddl_dir'; - const OPTION_MIGRATION_DIR = 'migration_dir'; - const OPTION_COLUMNS_POSITIONS_FILE = 'columns_positions_file'; + use OptionsTrait; + + const CONNECTION_DEFAULT = 'default'; + + const OPTION_CONNECTION = 'connection'; + const OPTION_DDL = 'ddl'; + const OPTION_DATA = 'data'; + const OPTION_MIGRATION = 'migration'; + const OPTION_ID_COLUMN = 'id_column'; + const OPTION_HISTO = 'histo'; + const OPTION_HISTO_USER_ID = 'histo/user_id'; + const OPTION_HISTO_CREATION_COLUMN = 'histo/histo_creation_column'; + const OPTION_HISTO_MODIFICATION_COLUMN = 'histo/histo_modification_column'; + const OPTION_HISTO_DESTRUCTION_COLUMN = 'histo/histo_destruction_column'; + const OPTION_HISTO_CREATEUR_ID_COLUMN = 'histo/histo_createur_id_column'; + const OPTION_HISTO_MODIFICATEUR_ID_COLUMN = 'histo/histo_modificateur_id_column'; + const OPTION_HISTO_DESTRUCTEUR_ID_COLUMN = 'histo/histo_destructeur_id_column'; + const OPTION_IMPORT = 'import'; + const OPTION_IMPORT_SOURCE_ID = 'import/source_id'; + const OPTION_IMPORT_SOURCE_ID_COLUMN = 'import/source_id_column'; + const OPTION_IMPORT_SOURCE_CODE_COLUMN = 'import/source_code_column'; const FETCH_ALL = 32; const FETCH_EACH = 16; @@ -106,9 +123,12 @@ class Bdd Ddl::SCHEMA . '.drop' => 'Suppression des schémas', ]; - private array $config; + private string $connection = self::CONNECTION_DEFAULT; - private array $options = []; + /** @var array|Bdd[] */ + private array $bdds = []; + + private array $config; private ?DriverInterface $driver = null; @@ -125,19 +145,21 @@ class Bdd protected bool $inCopy = false; - private DataUpdater $dataUpdater; + private DataManager $data; - /** - * Bdd constructor. - * - * @param array $config - */ - public function __construct(array $config = []) + public function __construct(array $options = [], string $connection = self::CONNECTION_DEFAULT) { - if (!empty($config)) { - $this->setConfig($config); + $this->connection = $connection; + + if (!empty($options)) { + // Compatibilité avec l'ancienne configuration des connections + if (!isset($options[self::OPTION_CONNECTION]) && isset($options['host'])) { + $options = [self::OPTION_CONNECTION => [$connection => $options]]; + } + $this->setOptions($options); + $this->connect(); } // On positionne un logger par défaut si on est en mode console, sinon non @@ -148,9 +170,62 @@ class Bdd - /** - * @return self - */ + public function hasConnection(string $connection): bool + { + $connections = $this->options[self::OPTION_CONNECTION]; + + return array_key_exists($connection, $connections); + } + + + + public function getBdd(string $connection): self + { + if (!array_key_exists($connection, $this->bdds)) { + if ($this->hasConnection($connection)) { + $this->bdds[$connection] = new self($this->getOptions(), $connection); + } else { + throw new \Exception('La connexion "' . $connection . '" n\'est pas présente en config, rubrique unicaen-bddadmin/'.self::OPTION_CONNECTION); + } + } + + return $this->bdds[$connection]; + } + + + + public function getHistoUserId(): ?int + { + return $this->getOption(self::OPTION_HISTO_USER_ID); + } + + + + public function setHistoUserId(int $histoUserId): self + { + $this->setOption(self::OPTION_HISTO_USER_ID, $histoUserId); + + return $this; + } + + + + public function getSourceId(): ?int + { + return $this->getOption(self::OPTION_IMPORT_SOURCE_ID); + } + + + + public function setSourceId(int $sourceOseId): self + { + $this->setOption(self::OPTION_IMPORT_SOURCE_ID, $sourceOseId); + + return $this; + } + + + public function beginTransaction(): self { $this->driver->beginTransaction(); @@ -160,12 +235,6 @@ class Bdd - /** - * @return $this - * @throws BddCompileException - * @throws BddException - * @throws BddIndexExistsException - */ public function commitTransaction(): self { $this->driver->commitTransaction(); @@ -175,9 +244,6 @@ class Bdd - /** - * @return $this - */ public function rollbackTransaction(): self { $this->driver->rollbackTransaction(); @@ -187,59 +253,48 @@ class Bdd - /** - * @param string $sql - * @param array $params - * - * @return bool - * @throws BddCompileException - * @throws BddException - * @throws BddIndexExistsException - */ - public function exec(string $sql, array $params = [], array $types = []) + public function exec(string $sql, array $params = [], array $types = []): self { $this->driver->exec($sql, $params, $types); - return true; + return $this; } - public function queryCollect(string $sql, string $description = null) + public function queryCollect(string $sql, string $description = null): self { if ($this->queryCollect) { $this->queries[$sql] = $description; } else { $this->exec($sql); } + + return $this; } - /** - * @param string $sql - * @param array $params - * @param array $options - * - * @return array|null|SelectParser - * @throws BddCompileException - * @throws BddException - * @throws BddIndexExistsException - */ - public function select(string $sql, array $params = [], array $options = []) + public function select(string $sql, array $params = [], array $options = []): array|null|SelectParser { return $this->driver->select($sql, $params, $options); } - public function selectOne(string $sql, array $params = [], string $column = null): mixed + public function selectOne(string $sql, array $params = [], string $column = null, array $options = []): mixed { - $res = $this->select($sql, $params, ['fetch' => self::FETCH_ONE]); + $options['fetch'] = self::FETCH_ONE; + $res = $this->select($sql, $params, $options); if (empty($res)) return null; if (is_array($res) && !empty($column)) { + if (!isset($res[$column])){ + $column = strtolower($column); + $res = array_change_key_case($res, CASE_LOWER); + } + return $res[$column]; } @@ -248,9 +303,10 @@ class Bdd - public function selectEach(string $sql, array $params = []): SelectParser + public function selectEach(string $sql, array $params = [], array $options = []): SelectParser { - return $this->select($sql, $params, ['fetch' => self::FETCH_EACH]); + $options['fetch'] = self::FETCH_EACH; + return $this->select($sql, $params, $options); } @@ -271,23 +327,18 @@ class Bdd - public function getConfig(): array + public function connect(): self { - return $this->config; - } - - - - public function setConfig(array $config): self - { - $this->config = $config; if ($this->driver) { $this->driver->disconnect(); } - $driverClass = isset($config['driver']) ? $config['driver'] : 'Oracle'; - $driverClass = "Unicaen\BddAdmin\Driver\\$driverClass\Driver"; + + $connectionOptions = $this->getOption(self::OPTION_CONNECTION . '/' . $this->connection, []); + + $driverClass = isset($connectionOptions['driver']) ? $connectionOptions['driver'] : 'Postgresql'; + $driverClass = "Unicaen\BddAdmin\Driver\\$driverClass\Driver"; $this->driver = new $driverClass($this); - $this->driver->connect(); + $this->driver->connect($connectionOptions); return $this; } @@ -332,61 +383,14 @@ class Bdd - public function hasOption(string $name): bool + public function data(): DataManager { - return array_key_exists($name, $this->options); - } - - - - public function getOption(string $name): mixed - { - if ($this->hasOption($name)) { - return $this->options[$name]; - } else { - return null; + if (!isset($this->data)) { + $this->data = new DataManager($this); + $this->data->setOptions($this->getOption(self::OPTION_DATA, [])); } - } - - - public function setOption(string $name, mixed $value): self - { - $this->options[$name] = $value; - - return $this; - } - - - - public function getOptions(): array - { - return $this->options; - } - - - - public function setOptions(array $options, bool $clearOthers = false): self - { - if ($clearOthers) { - $this->options = []; - } - foreach ($options as $name => $option) { - $this->setOption($name, $option); - } - - return $this; - } - - - - public function dataUpdater(): DataUpdater - { - if (!isset($this->dataUpdater)) { - $this->dataUpdater = new DataUpdater($this); - } - - return $this->dataUpdater; + return $this->data; } @@ -395,6 +399,7 @@ class Bdd { if (!isset($this->migration)) { $this->migration = new MigrationManager($this); + $this->migration->setOptions($this->getOption(self::OPTION_MIGRATION, [])); } return $this->migration; @@ -497,9 +502,8 @@ class Bdd { $this->logBegin("Récupération de la DDL"); $filters = DdlFilters::normalize($filters); - $ddl = new Ddl(); - $ddl->setDir($this->getOption(self::OPTION_DDL_DIR)); - $ddl->setColumnsPosFile($this->getOption(self::OPTION_COLUMNS_POSITIONS_FILE)); + $ddl = new Ddl(); + $ddl->setOptions($this->getOption(self::OPTION_DDL, [])); $managers = $this->managerList(); foreach ($managers as $type => $libelle) { if (!($filters->isExplicit() && $filters->get($type)->isEmpty())) { @@ -519,13 +523,8 @@ class Bdd public function getRefDdl(): Ddl { - $ddlDir = $this->getOption(self::OPTION_DDL_DIR); - - if (!is_dir($ddlDir)){ - throw new \Exception('Erreur sur le répertoire de DDL au niveau du projet'); - } $ddl = new Ddl(); - $ddl->setDir($ddlDir); + $ddl->setOptions($this->getOption(self::OPTION_DDL, [])); $ddl->loadFromDir(); return $ddl; @@ -536,7 +535,7 @@ class Bdd protected function alterDdlObject(ManagerInterface $manager, string $action, array $kold, array $knew): array { $this->queryCollect = true; - $this->queries = []; + $this->queries = []; $renames = []; foreach ($kold as $koldIndex => $koldData) { @@ -746,8 +745,8 @@ class Bdd $new = $bdd; } $diff = new DdlDiff(); - $cc = count($this->changements); - $c = 0; + $cc = count($this->changements); + $c = 0; foreach ($this->changements as $changement => $label) { [$ddlName, $action] = explode('.', $changement); $manager = $this->manager($ddlName); @@ -782,8 +781,8 @@ class Bdd } $diff = new DdlDiff(); - $cc = count($this->changements); - $c = 0; + $cc = count($this->changements); + $c = 0; foreach ($this->changements as $changement => $label) { [$ddlName, $action] = explode('.', $changement); $manager = $this->manager($ddlName); @@ -847,12 +846,6 @@ class Bdd - /** - * @return array - * @throws BddCompileException - * @throws BddException - * @throws BddIndexExistsException - */ public function compilerTout(): array { $this->logBegin("Compilation de tous les objets de la BDD"); @@ -903,8 +896,8 @@ class Bdd } } $schDdl = $source->schema()->get(); - $sDdl = $source->sequence()->get(); - $tDdl = $source->table()->get(null, $excludes); + $sDdl = $source->sequence()->get(); + $tDdl = $source->table()->get(null, $excludes); $this->drop(); $this->create([Ddl::SCHEMA => $schDdl, Ddl::SEQUENCE => $sDdl, Ddl::TABLE => $tDdl]); @@ -930,9 +923,9 @@ class Bdd if ($filters instanceof DdlFilters) { $filters = $filters->toArray(); } - $filters[Ddl::SCHEMA] = ['excludes' => '%']; + $filters[Ddl::SCHEMA] = ['excludes' => '%']; $filters[Ddl::SEQUENCE] = ['excludes' => '%']; - $filters[Ddl::TABLE] = ['excludes' => '%']; + $filters[Ddl::TABLE] = ['excludes' => '%']; $this->create($source, $filters); @@ -980,7 +973,7 @@ class Bdd foreach ($tables as $table) { $fnc = isset($fncs[$table]) ? $fncs[$table] : null; if (false !== $fnc) { - $tmpname = tempnam(sys_get_temp_dir(), uniqid()); + $tmpname = tempnam(sys_get_temp_dir(), uniqid()); $tmpNames[] = $tmpname; $this->getTable($table)->save($tmpname, $fnc); if (file_exists($tmpname)) { diff --git a/src/BddFactory.php b/src/BddFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..5c508439e5fd87290f84545282796498fabcc1f8 --- /dev/null +++ b/src/BddFactory.php @@ -0,0 +1,30 @@ +<?php + +namespace Unicaen\BddAdmin; + +use Psr\Container\ContainerInterface; + +/** + * Description of BddFactory + * + * @author Laurent Lécluse <laurent.lecluse at unicaen.fr> + */ +class BddFactory +{ + + /** + * @param ContainerInterface $container + * @param string $requestedName + * @param array|null $options + * + * @return Bdd + */ + public function __invoke(ContainerInterface $container, $requestedName, $options = null): Bdd + { + $config = $container->get('config')['unicaen-bddadmin']; + + $bdd = new Bdd($config); + + return $bdd; + } +} \ No newline at end of file diff --git a/src/DataUpdater.php b/src/Data/DataManager.php similarity index 87% rename from src/DataUpdater.php rename to src/Data/DataManager.php index e8c7680ebfdc4f12fc23b087ef712f731f09bdcf..8e869ca8de49c8d16608b5ee93b1590d936ab5e3 100644 --- a/src/DataUpdater.php +++ b/src/Data/DataManager.php @@ -1,15 +1,18 @@ <?php -namespace Unicaen\BddAdmin; +namespace Unicaen\BddAdmin\Data; -class DataUpdater +use Unicaen\BddAdmin\Bdd; +use Unicaen\BddAdmin\BddAwareTrait; +use Unicaen\BddAdmin\Trait\OptionsTrait; + +class DataManager { use BddAwareTrait; + use OptionsTrait; private array $config = []; - private string $defaultIdColumn = 'ID'; - private array $sources = []; private array $sourcesData = []; @@ -28,7 +31,7 @@ class DataUpdater - public function run(string $action, ?string $table = null) + public function run(string $action, ?string $table = null): DataManager { if (!isset($this->actions[$action])) { throw new \Exception('Action "' . $action . '" inconnue'); @@ -47,6 +50,8 @@ class DataUpdater $this->syncTable($table, $action, $config); } } + + return $this; } @@ -56,6 +61,8 @@ class DataUpdater $tableObject = $this->getBdd()->getTable($table); $ddl = $tableObject->getDdl(); + $idCol = $this->getBdd()->getOption(Bdd::OPTION_ID_COLUMN); + $data = null; foreach ($this->sources as $i => $source) { if (is_object($source) && method_exists($source, $table)) { @@ -83,7 +90,7 @@ class DataUpdater $result = $tableObject->merge( $data, - $config['key'] ?? $this->defaultIdColumn, + $config['key'] ?? $idCol, $config['options'] ?? [] ); if ($result['insert'] + $result['update'] + $result['delete'] > 0) { @@ -108,9 +115,9 @@ class DataUpdater /** * @param array $config * - * @return DataUpdater + * @return DataManager */ - public function setConfig(array $config): DataUpdater + public function setConfig(array $config): DataManager { $this->config = $config; @@ -119,7 +126,7 @@ class DataUpdater - public function addConfig(string $table, array $config): DataUpdater + public function addConfig(string $table, array $config): DataManager { $this->config[$table] = $config; @@ -138,7 +145,7 @@ class DataUpdater - public function addSource(string|array|object $source): DataUpdater + public function addSource(string|array|object $source): DataManager { $this->sources[] = $source; @@ -157,7 +164,7 @@ class DataUpdater - public function addAction(string $name, string $libelle): DataUpdater + public function addAction(string $name, string $libelle): DataManager { $this->actions[$name] = $libelle; diff --git a/src/Ddl/Ddl.php b/src/Ddl/Ddl.php index 51d5af6e2f85e043949afe83a11f4038294f15a6..c35c2b8b57f35fda565c9652d3510f09d1da3408 100644 --- a/src/Ddl/Ddl.php +++ b/src/Ddl/Ddl.php @@ -2,8 +2,15 @@ namespace Unicaen\BddAdmin\Ddl; -class Ddl implements \Iterator, \ArrayAccess +use Unicaen\BddAdmin\Trait\OptionsTrait; +use Iterator; +use ArrayAccess; +use Unicaen\BddAdmin\Util; + +class Ddl implements Iterator, ArrayAccess { + use OptionsTrait; + const TABLE = 'table'; const VIEW = 'view'; const SEQUENCE = 'sequence'; @@ -18,44 +25,37 @@ class Ddl implements \Iterator, \ArrayAccess const TRIGGER = 'trigger'; const SCHEMA = 'schema'; - protected array $data = []; + const OPTION_DIR = 'dir'; + const OPTION_COLUMNS_POSITIONS_FILE = 'columns_positions_file'; - protected ?string $dir = null; - - protected ?string $columnsPosFile = null; + protected array $data = []; public function getDir(): ?string { - if ($this->dir) { - return $this->dir; - } - return $this->dir; + return $this->getOption(self::OPTION_DIR); } public function setDir(?string $dir): Ddl { - $this->dir = $dir; - - return $this; + return $this->setOption(self::OPTION_DIR, $dir); } - public function getColumnsPosFile(): ?string + public function getColumnsPositionsFile(): ?string { - return $this->columnsPosFile; + return $this->getOption(self::OPTION_COLUMNS_POSITIONS_FILE); } - public function setColumnsPosFile(?string $columnsPosFile): Ddl + public function setColumnsPositionsFile(?string $columnsPositionsFile): Ddl { - $this->columnsPosFile = $columnsPosFile; - return $this; + return $this->setOption(self::OPTION_COLUMNS_POSITIONS_FILE, $columnsPositionsFile); } @@ -235,37 +235,8 @@ class Ddl implements \Iterator, \ArrayAccess - public function arrayExport($var, string $indent = ""): string - { - switch (gettype($var)) { - case "array": - $indexed = array_keys($var) === range(0, count($var) - 1); - $r = []; - $maxKeyLen = 0; - foreach ($var as $key => $value) { - $key = $this->arrayExport($key); - $keyLen = strlen($key); - if ($keyLen > $maxKeyLen) $maxKeyLen = $keyLen; - } - foreach ($var as $key => $value) { - $key = $this->arrayExport($key); - $r[] = "$indent " - . ($indexed ? "" : str_pad($key, $maxKeyLen, ' ') . " => ") - . $this->arrayExport($value, "$indent "); - } - - return "[\n" . implode(",\n", $r) . ",\n" . $indent . "]"; - case "boolean": - return $var ? "TRUE" : "FALSE"; - default: - return var_export($var, true); - } - } - - - /** - * On passe un tableau de positions de colonnes ou bien on utilise le fichier de config des positions, + * On passe un tableau de positions de colonnes ou bien, on utilise le fichier de config des positions, * et cela réorganise l'ordonnancement. * * @param array|null $positions @@ -275,10 +246,10 @@ class Ddl implements \Iterator, \ArrayAccess public function applyColumnPositions(array|null $positions = null): array { if (null === $positions) { - $colPosFile = $this->getColumnsPosFile(); + $colPosFile = $this->getColumnsPositionsFile(); if ($colPosFile && file_exists($colPosFile)) { $positions = require $colPosFile; - if (!is_array($positions)){ + if (!is_array($positions)) { throw new \exception('Le fichier des positions doit retourner un tableau PHP'); } } @@ -352,7 +323,7 @@ class Ddl implements \Iterator, \ArrayAccess public function writeArray(string $filename, array $data): self { - $ddlString = "<?php\n\n//@" . "formatter:off\n\nreturn " . $this->arrayExport($data) . ";\n\n//@" . "formatter:on\n"; + $ddlString = "<?php\n\n//@" . "formatter:off\n\nreturn " . Util::arrayExport($data) . ";\n\n//@" . "formatter:on\n"; file_put_contents($filename, $ddlString); @@ -366,7 +337,7 @@ class Ddl implements \Iterator, \ArrayAccess $data = $this->data; asort($data); - $ddlString = "<?php\n\n//@" . "formatter:off\n\nreturn " . $this->arrayExport($data) . ";\n\n//@" . "formatter:on\n"; + $ddlString = "<?php\n\n//@" . "formatter:off\n\nreturn " . Util::arrayExport($data) . ";\n\n//@" . "formatter:on\n"; return $ddlString; } @@ -404,7 +375,7 @@ class Ddl implements \Iterator, \ArrayAccess public function saveToDir(?string $dirname = null) { if (!$dirname) { - $dirname = $this->dir; + $dirname = $this->getDir(); } if (!$dirname) { throw new \Exception('Un répertoire doit être spécifié pour mettre à jour la DDL'); @@ -448,9 +419,9 @@ class Ddl implements \Iterator, \ArrayAccess } } - if ($this->getColumnsPosFile()){ + if ($this->getColumnsPositionsFile()) { $positions = $this->applyColumnPositions(); - $this->writeArray($this->getColumnsPosFile(), $positions); + $this->writeArray($this->getColumnsPositionsFile(), $positions); } } @@ -459,17 +430,19 @@ class Ddl implements \Iterator, \ArrayAccess public function loadFromDir(?string $dir = null) { if (!$dir) { - $dir = $this->dir; + $dir = $this->getDir(); } if (!$dir) { throw new \Exception('Un répertoire doit être spécifié pour charger la DDL'); } - if (substr($dir, -1) != '/') $dir .= '/'; + if (!str_ends_with($dir, '/')){ + $dir .= '/'; + } $this->data = []; if (file_exists($dir . self::SEQUENCE . '.php')) { - $sequences = require $dir . self::SEQUENCE . '.php'; + $sequences = require $dir . self::SEQUENCE . '.php'; $this->data[self::SEQUENCE] = []; foreach ($sequences as $sequence) { $this->data[self::SEQUENCE][$sequence] = ['name' => $sequence]; @@ -478,7 +451,7 @@ class Ddl implements \Iterator, \ArrayAccess if (file_exists($dir . self::PACKAGE) && is_dir($dir . self::PACKAGE)) { $this->data[self::PACKAGE] = []; - $data = scandir($dir . self::PACKAGE); + $data = scandir($dir . self::PACKAGE); foreach ($data as $name) { if ($name != '.' && $name != '..') { $this->data[self::PACKAGE][$name] = ['name' => $name]; @@ -496,10 +469,10 @@ class Ddl implements \Iterator, \ArrayAccess foreach ($arrays as $type) { if (file_exists($dir . $type) && is_dir($dir . $type)) { $this->data[$type] = []; - $data = scandir($dir . $type); + $data = scandir($dir . $type); foreach ($data as $name) { if ($name != '.' && $name != '..') { - $def = require $dir . $type . '/' . $name; + $def = require $dir . $type . '/' . $name; $this->data[$type][$def['name']] = $def; } } @@ -510,11 +483,11 @@ class Ddl implements \Iterator, \ArrayAccess foreach ($sqls as $type) { if (file_exists($dir . $type) && is_dir($dir . $type)) { $this->data[$type] = []; - $data = scandir($dir . $type); + $data = scandir($dir . $type); foreach ($data as $name) { if ($name != '.' && $name != '..') { - $def = file_get_contents($dir . $type . '/' . $name); - $name = substr($name, 0, -4); + $def = file_get_contents($dir . $type . '/' . $name); + $name = substr($name, 0, -4); $this->data[$type][$name] = ['name' => $name, 'definition' => $def]; } } diff --git a/src/Driver/DriverInterface.php b/src/Driver/DriverInterface.php index 59e715a0b7830cba1f48472e4d8935bd57eacf57..0fc0e5a3e5080575b3da9ade5b33a264d2f2469b 100644 --- a/src/Driver/DriverInterface.php +++ b/src/Driver/DriverInterface.php @@ -4,7 +4,7 @@ namespace Unicaen\BddAdmin\Driver; interface DriverInterface { - public function connect(): DriverInterface; + public function connect(array $options): DriverInterface; @@ -32,10 +32,12 @@ interface DriverInterface - public function fetch($statement); + public function fetch($statement, array $options = []); public function getDdlClass(string $name): ?string; + + public function getColsCase(): int; } \ No newline at end of file diff --git a/src/Driver/Mysql/Driver.php b/src/Driver/Mysql/Driver.php index 9e2b92ef9989bc25465a9ff59b126e544a6fc4ad..349adcc60e19bcec35e169bd6af03cac53778427 100644 --- a/src/Driver/Mysql/Driver.php +++ b/src/Driver/Mysql/Driver.php @@ -46,25 +46,29 @@ class Driver implements DriverInterface - public function connect(): DriverInterface + public function getColsCase(): int { - $config = $this->bdd->getConfig(); - $host = isset($config['host']) ? $config['host'] : null; - $port = isset($config['port']) ? $config['port'] : null; - $dbname = isset($config['dbname']) ? $config['dbname'] : null; - $username = isset($config['username']) ? $config['username'] : null; - $password = isset($config['password']) ? $config['password'] : null; - $charset = isset($config['charset']) ? $config['charset'] : 'UTF8'; + return -1; // pas CASE_UPPER ni CASE_LOWER + } + + + public function connect($options): DriverInterface + { + $host = $options['host'] ?? null; + $port = $options['port'] ?? 3306; + $dbname = $options['dbname'] ?? null; + $user = $options['user'] ?? $options['username'] ?? null; + $password = $options['password'] ?? null; + $charset = $options['charset'] ?? $options['characterset'] ?? 'UTF8'; if (!$host) throw new BddException('host non fourni'); - if (!$port) throw new BddException('port non fourni'); if (!$dbname) throw new BddException('dbname non fourni'); - if (!$username) throw new BddException('username non fourni'); + if (!$user) throw new BddException('user non fourni'); if (!$password) throw new BddException('password non fourni'); try { $dsn = "mysql:dbname=$dbname;host=$host;port=$port;charset=$charset"; - $this->connexion = new PDO($dsn, $username, $password); + $this->connexion = new PDO($dsn, $user, $password); } catch (\PDOException $e) { throw new BddException($e->getMessage(), $e->getCode(), $e); } @@ -99,26 +103,6 @@ class Driver implements DriverInterface $statement = $this->connexion->prepare($sql); - /* - foreach ($params as $key => $val) { - $type = isset($types[$key]) ? $types[$key] : null; - switch ($type) { - case Bdd::TYPE_CLOB: - ${$key} = oci_new_descriptor($this->connexion, OCI_D_LOB); - ${$key}->writeTemporary($params[$key], OCI_TEMP_CLOB); - oci_bind_by_name($statement, ':' . $key, ${$key}, -1, OCI_B_CLOB); - break; - case Bdd::TYPE_BLOB: - ${$key} = oci_new_descriptor($this->connexion, OCI_D_LOB); - ${$key}->writeTemporary($params[$key], OCI_TEMP_BLOB); - oci_bind_by_name($statement, ':' . $key, ${$key}, -1, OCI_B_BLOB); - break; - default: - $statement->bindParam(':' . $key, $val); - break; - } - }*/ - $statement->execute($params); if (0 !== ($errCode = (int)$statement->errorCode())) { $errInfo = $statement->errorInfo(); @@ -202,6 +186,7 @@ class Driver implements DriverInterface { $defaultOptions = [ 'fetch' => Bdd::FETCH_ALL, + 'case' => -1, 'types' => [], ]; $options = array_merge($defaultOptions, $options); @@ -214,7 +199,13 @@ class Driver implements DriverInterface case Bdd::FETCH_EACH: return new SelectParser($this, $options, $statement); case Bdd::FETCH_ALL: - return $statement->fetchAll(PDO::FETCH_ASSOC); + $data = $statement->fetchAll(PDO::FETCH_ASSOC); + if (CASE_UPPER == $options['case'] || CASE_LOWER == $options['case']){ + foreach( $data as $index => $line){ + $data[$index] = array_change_key_case($line, $options['case']); + } + } + return $data; /*if ($res) { foreach ($res as $l => $r) { foreach ($r as $c => $v) { @@ -234,6 +225,7 @@ class Driver implements DriverInterface { $defaultOptions = [ 'types' => [], + 'case' => -1, ]; $options = array_merge($defaultOptions, $options); $result = $statement->fetch(PDO::FETCH_ASSOC); @@ -246,6 +238,10 @@ class Driver implements DriverInterface } }*/ + if (CASE_UPPER == $options['case'] || CASE_LOWER == $options['case']){ + $result = array_change_key_case($result, $options['case']); + } + return $result; } diff --git a/src/Driver/Oracle/Driver.php b/src/Driver/Oracle/Driver.php index 8e3f709f5aab907975436b8bbb82e8911e2054e2..5a6346eb399bb83f9dbcb14f2837c537a2b311ba 100644 --- a/src/Driver/Oracle/Driver.php +++ b/src/Driver/Oracle/Driver.php @@ -12,28 +12,15 @@ use Unicaen\BddAdmin\SelectParser; class Driver implements DriverInterface { - /** - * @var Bdd - */ - private $bdd; + private Bdd $bdd; - /** - * @var resource - */ + /** @var resource */ private $connexion; - /** - * @var int - */ - private $commitMode = OCI_COMMIT_ON_SUCCESS; + private int $commitMode = OCI_COMMIT_ON_SUCCESS; - /** - * Driver constructor. - * - * @param Bdd $bdd - */ public function __construct(Bdd $bdd) { $this->bdd = $bdd; @@ -41,28 +28,31 @@ class Driver implements DriverInterface - public function connect(): DriverInterface + public function getColsCase(): int { - $config = $this->bdd->getConfig(); + return CASE_UPPER; + } + + - $host = $config['host'] ?? null; - $port = $config['port'] ?? null; - $dbname = $config['dbname'] ?? null; - $username = $config['username'] ?? $config['user']?? null; - $password = $config['password'] ?? null; - $charset = $config['characterset'] ?? $config['charset'] ?? 'AL32UTF8'; + public function connect(array $options): DriverInterface + { + $host = $options['host'] ?? null; + $port = $options['port'] ?? 1521; + $dbname = $options['dbname'] ?? null; + $user = $options['user'] ?? $options['username'] ?? null; + $password = $options['password'] ?? null; + $charset = $options['charset'] ?? $options['characterset'] ?? 'AL32UTF8'; if (!$host) throw new BddException('host non fourni'); - if (!$port) throw new BddException('port non fourni'); if (!$dbname) throw new BddException('dbname non fourni'); - if (!$username) throw new BddException('username ou user non fourni'); + if (!$user) throw new BddException('user non fourni'); if (!$password) throw new BddException('password non fourni'); - if (!$charset) throw new BddException('characterset ou charset non fourni'); putenv("NLS_LANGUAGE=FRENCH"); $cs = $host . ':' . $port . '/' . $dbname; - $this->connexion = oci_pconnect($username, $password, $cs, $charset); + $this->connexion = oci_pconnect($user, $password, $cs, $charset); if (!$this->connexion) { $error = oci_error(); throw $this->sendException($error); @@ -156,9 +146,6 @@ class Driver implements DriverInterface - /** - * @return self - */ public function beginTransaction(): DriverInterface { $this->commitMode = OCI_NO_AUTO_COMMIT; @@ -168,12 +155,6 @@ class Driver implements DriverInterface - /** - * @return $this - * @throws BddCompileException - * @throws BddException - * @throws BddIndexExistsException - */ public function commitTransaction(): DriverInterface { $this->commitMode = OCI_COMMIT_ON_SUCCESS; @@ -187,9 +168,6 @@ class Driver implements DriverInterface - /** - * @return $this - */ public function rollbackTransaction(): DriverInterface { oci_rollback($this->connexion); @@ -200,15 +178,6 @@ class Driver implements DriverInterface - /** - * @param string $sql - * @param array $params - * - * @return bool - * @throws BddCompileException - * @throws BddException - * @throws BddIndexExistsException - */ public function exec(string $sql, array $params = [], array $types = []): bool { $statement = $this->execStatement($sql, $params, $types); @@ -233,6 +202,7 @@ class Driver implements DriverInterface { $defaultOptions = [ 'fetch' => Bdd::FETCH_ALL, + 'case' => -1, 'types' => [], ]; $options = array_merge($defaultOptions, $options); @@ -252,8 +222,12 @@ class Driver implements DriverInterface } oci_free_statement($statement); if ($res) { + $changeCase = CASE_UPPER == $options['case'] || CASE_LOWER == $options['case']; foreach ($res as $l => $r) { - foreach ($r as $c => $v) { + if ($changeCase){ + $res[$l] = array_change_key_case($r, $options['case']); + } + foreach ($res[$l] as $c => $v) { $type = isset($options['types'][$c]) ? $options['types'][$c] : null; $res[$l][$c] = $this->bddToPhpConvertVar($v, $type); } @@ -270,12 +244,16 @@ class Driver implements DriverInterface { $defaultOptions = [ 'types' => [], + 'case' => -1, ]; $options = array_merge($defaultOptions, $options); $result = oci_fetch_array($statement, OCI_ASSOC + OCI_RETURN_NULLS + OCI_RETURN_LOBS); if (false == $result) { oci_free_statement($statement); } else { + if (CASE_LOWER == $options['case'] || CASE_UPPER == $options['case']){ + $result = array_change_key_case($result, $options['case']); + } foreach ($result as $c => $v) { $type = isset($options['types'][$c]) ? $options['types'][$c] : null; $result[$c] = $this->bddToPhpConvertVar($v, $type); diff --git a/src/Driver/Oracle/TableManager.php b/src/Driver/Oracle/TableManager.php index 13e7388f26754fb58b0946b8b6e0295bda5c0578..4b4b7a652c725bfed556e4c12983d1681735e75d 100644 --- a/src/Driver/Oracle/TableManager.php +++ b/src/Driver/Oracle/TableManager.php @@ -362,8 +362,10 @@ class TableManager extends AbstractManager implements TableManagerInterface public function majSequence(array $data): void { + $idCol = $this->bdd->getOption(Bdd::OPTION_ID_COLUMN); + if (!isset($data['sequence'])) return; - if (!isset($data['columns']['ID'])) return; + if (!isset($data['columns'][$idCol])) return; if ($this->sendEvent()->getReturn('no-exec')) return; diff --git a/src/Driver/Postgresql/Driver.php b/src/Driver/Postgresql/Driver.php index 73497bebdec3c8b724eda774f69a0ea00effacf5..730ae3c0b8d9d7a05957582731fd4b779d1775e8 100644 --- a/src/Driver/Postgresql/Driver.php +++ b/src/Driver/Postgresql/Driver.php @@ -47,25 +47,29 @@ class Driver implements DriverInterface - public function connect(): DriverInterface + public function getColsCase(): int { - $config = $this->bdd->getConfig(); - $host = $config['host'] ?? null; - $port = $config['port'] ?? 5342; - $dbname = $config['dbname'] ?? null; - $username = $config['username'] ?? $config['user']?? null; - $password = $config['password'] ?? null; - $charset = $config['charset'] ?? 'UTF8'; + return CASE_LOWER; + } + + + + public function connect($options): DriverInterface + { + $host = $options['host'] ?? null; + $port = $options['port'] ?? 5342; + $dbname = $options['dbname'] ?? null; + $user = $options['user'] ?? $options['username'] ?? null; + $password = $options['password'] ?? null; if (!$host) throw new BddException('host non fourni'); - if (!$port) throw new BddException('port non fourni'); if (!$dbname) throw new BddException('dbname non fourni'); - if (!$username) throw new BddException('username non fourni'); + if (!$user) throw new BddException('username non fourni'); if (!$password) throw new BddException('password non fourni'); try { - $dsn = "pgsql:dbname=$dbname;host=$host;port=$port"; - $this->connexion = new PDO($dsn, $username, $password); + $dsn = "pgsql:dbname=$dbname;host=$host;port=$port"; + $this->connexion = new PDO($dsn, $user, $password); } catch (\PDOException $e) { throw new BddException($e->getMessage(), $e->getCode(), $e); } @@ -88,7 +92,7 @@ class Driver implements DriverInterface private function execStatement($sql, array $params = [], array $types = []) { - /*foreach ($params as $name => $val) { + foreach ($params as $name => $val) { if (is_bool($val)) { $params[$name] = $val ? 'TRUE' : 'FALSE'; } elseif ($val instanceof \DateTime) { @@ -96,30 +100,10 @@ class Driver implements DriverInterface } else { $params[$name] = $val; } - }*/ + } $statement = $this->connexion->prepare($sql); - /* - foreach ($params as $key => $val) { - $type = isset($types[$key]) ? $types[$key] : null; - switch ($type) { - case Bdd::TYPE_CLOB: - ${$key} = oci_new_descriptor($this->connexion, OCI_D_LOB); - ${$key}->writeTemporary($params[$key], OCI_TEMP_CLOB); - oci_bind_by_name($statement, ':' . $key, ${$key}, -1, OCI_B_CLOB); - break; - case Bdd::TYPE_BLOB: - ${$key} = oci_new_descriptor($this->connexion, OCI_D_LOB); - ${$key}->writeTemporary($params[$key], OCI_TEMP_BLOB); - oci_bind_by_name($statement, ':' . $key, ${$key}, -1, OCI_B_BLOB); - break; - default: - $statement->bindParam(':' . $key, $val); - break; - } - }*/ - $statement->execute($params); if (0 !== ($errCode = (int)$statement->errorCode())) { $errInfo = $statement->errorInfo(); @@ -173,7 +157,7 @@ class Driver implements DriverInterface /** * @param string $sql - * @param array $params + * @param array $params * * @return bool * @throws BddCompileException @@ -191,8 +175,8 @@ class Driver implements DriverInterface /** * @param string $sql - * @param array $params - * @param int $fetchMode + * @param array $params + * @param int $fetchMode * * @return null|array|SelectParser * @throws BddCompileException @@ -203,9 +187,10 @@ class Driver implements DriverInterface { $defaultOptions = [ 'fetch' => Bdd::FETCH_ALL, + 'case' => -1, 'types' => [], ]; - $options = array_merge($defaultOptions, $options); + $options = array_merge($defaultOptions, $options); $statement = $this->execStatement($sql, $params); @@ -215,7 +200,14 @@ class Driver implements DriverInterface case Bdd::FETCH_EACH: return new SelectParser($this, $options, $statement); case Bdd::FETCH_ALL: - return $statement->fetchAll(PDO::FETCH_ASSOC); + $data = $statement->fetchAll(PDO::FETCH_ASSOC); + if (CASE_UPPER == $options['case'] || CASE_LOWER == $options['case']) { + foreach ($data as $index => $line) { + $data[$index] = array_change_key_case($line, $options['case']); + } + } + return $data; + /*if ($res) { foreach ($res as $l => $r) { foreach ($r as $c => $v) { @@ -235,9 +227,10 @@ class Driver implements DriverInterface { $defaultOptions = [ 'types' => [], + 'case' => -1, ]; - $options = array_merge($defaultOptions, $options); - $result = $statement->fetch(PDO::FETCH_ASSOC); + $options = array_merge($defaultOptions, $options); + $result = $statement->fetch(PDO::FETCH_ASSOC); if (false == $result) { unset($statement); }/* else { @@ -247,6 +240,10 @@ class Driver implements DriverInterface } }*/ + if (CASE_LOWER == $options['case'] || CASE_UPPER == $options['case']){ + $result = array_change_key_case($result, $options['case']); + } + return $result; } diff --git a/src/Driver/Postgresql/TableManager.php b/src/Driver/Postgresql/TableManager.php index 73f437ba0e917b756faa76dfff52a71922fef53a..8b30de009bf0d5b349310a39e14827c54fac99c6 100644 --- a/src/Driver/Postgresql/TableManager.php +++ b/src/Driver/Postgresql/TableManager.php @@ -462,7 +462,10 @@ class TableManager extends AbstractManager implements TableManagerInterface public function majSequence(array $data): void { if (!isset($data['sequence'])) return; - if (!isset($data['columns']['id'])) return; + + $idCol = $this->bdd->getOption(Bdd::OPTION_ID_COLUMN); + + if (!isset($data['columns'][$idCol])) return; if ($this->sendEvent()->getReturn('no-exec')) return; diff --git a/src/Migration/MigrationManager.php b/src/Migration/MigrationManager.php index a042cfa2fb404ed71c42e6bfc76dec0fe8a4ad36..9edc1b05b743a2c004d7cb06a5fa308599cc22c1 100644 --- a/src/Migration/MigrationManager.php +++ b/src/Migration/MigrationManager.php @@ -5,9 +5,13 @@ namespace Unicaen\BddAdmin\Migration; use Unicaen\BddAdmin\Bdd; use Unicaen\BddAdmin\Ddl\Ddl; use Unicaen\BddAdmin\Ddl\DdlFilters; +use Unicaen\BddAdmin\Trait\OptionsTrait; class MigrationManager { + use OptionsTrait; + + const string OPTION_DIR = 'dir'; protected Ddl $ref; @@ -28,6 +32,20 @@ class MigrationManager + public function getDir(): ?string + { + return $this->getOption(self::OPTION_DIR); + } + + + + public function setDir(?string $dir): MigrationManager + { + return $this->setOption(self::OPTION_DIR, $dir); + } + + + public function getBdd(): Bdd { return $this->bdd; @@ -195,7 +213,7 @@ class MigrationManager && $migration instanceof AbstractMigration && (method_exists($migration, $contexte)) ) { - $traducs = [ + $traducs = [ 'before' => 'AVANT', 'after' => 'APRES', ]; @@ -223,9 +241,9 @@ class MigrationManager public function init(Ddl $ref, DdlFilters|array $filters = []) { - $this->ref = $ref; + $this->ref = $ref; $this->filters = DdlFilters::normalize($filters); - $this->old = $this->getBdd()->getDdl($this->filters); + $this->old = $this->getBdd()->getDdl($this->filters); } diff --git a/src/Table.php b/src/Table.php index b79900c6415c247707d2c49c44c54523c85b97ec..fb7261c47f70f965704bc3c3685b5cbada9934a8 100644 --- a/src/Table.php +++ b/src/Table.php @@ -62,26 +62,42 @@ class Table public function hasHistorique(): bool { - $ddl = $this->getDdl(); - $hasHisto = isset($ddl['columns']['HISTO_CREATION']) - && isset($ddl['columns']['HISTO_MODIFICATION']) - && isset($ddl['columns']['HISTO_DESTRUCTION']) - && isset($ddl['columns']['HISTO_CREATEUR_ID']) - && isset($ddl['columns']['HISTO_MODIFICATEUR_ID']) - && isset($ddl['columns']['HISTO_DESTRUCTEUR_ID']); - - return $hasHisto; + $ddl = $this->getDdl(); + + $histoCols = [ + Bdd::OPTION_HISTO_CREATION_COLUMN, + Bdd::OPTION_HISTO_MODIFICATION_COLUMN, + Bdd::OPTION_HISTO_DESTRUCTION_COLUMN, + Bdd::OPTION_HISTO_CREATEUR_ID_COLUMN, + Bdd::OPTION_HISTO_MODIFICATEUR_ID_COLUMN, + Bdd::OPTION_HISTO_DESTRUCTEUR_ID_COLUMN, + ]; + + foreach ($histoCols as $histoCol) { + $columnName = $this->getBdd()->getOption($histoCol); + if (!$columnName) { + return false; + } + if (!isset($ddl['columns'][$columnName])) { + return false; + } + } + return true; } public function hasImport(): bool { + $sourceIdCol = $this->getBdd()->getOption(Bdd::OPTION_IMPORT_SOURCE_ID_COLUMN); + if (!$sourceIdCol) return false; + + $sourceCodeCol = $this->getBdd()->getOption(Bdd::OPTION_IMPORT_SOURCE_CODE_COLUMN); + if (!$sourceCodeCol) return false; + $ddl = $this->getDdl(); - $hasImport = isset($ddl['columns']['SOURCE_ID']) - && isset($ddl['columns']['SOURCE_CODE']); - return $hasImport; + return isset($ddl['columns'][$sourceIdCol]) && isset($ddl['columns'][$sourceCodeCol]); } @@ -106,6 +122,7 @@ class Table $defaultOptions = [ 'custom-select' => null, 'fetch' => Bdd::FETCH_ALL, + 'case' => -1, 'types' => $this->makeTypesOptions(), 'key' => null, 'orderBy' => '', @@ -154,7 +171,7 @@ class Table { $options = ['types' => $this->makeTypesOptions(), 'fetch' => Bdd::FETCH_EACH]; - $count = (int)$source->select('SELECT count(*) C FROM ' . $this->getName(), [], ['fetch' => Bdd::FETCH_ONE])['C']; + $count = (int)$source->selectOne('SELECT count(*) c FROM ' . $this->getName(), [], 'c', ['case' => CASE_LOWER]); $r = $source->select('SELECT * FROM ' . $this->getName(), [], $options); if (!$this->getBdd()->isInCopy()) { @@ -193,7 +210,7 @@ class Table { $options = ['types' => $this->makeTypesOptions(), 'fetch' => Bdd::FETCH_EACH]; - $count = (int)$this->getBdd()->select('SELECT count(*) C FROM ' . $this->getName(), [], ['fetch' => Bdd::FETCH_ONE])['C']; + $count = (int)$this->getBdd()->selectOne('SELECT count(*) c FROM ' . $this->getName(), [], 'c', ['case' => CASE_LOWER]); $r = $this->getBdd()->select('SELECT * FROM ' . $this->getName(), [], $options); if (!$this->getBdd()->isInCopy()) { @@ -292,22 +309,31 @@ class Table { $bdd = $this->getBdd(); - if (!isset($data['ID']) && $this->hasId() && $this->hasSequence()) { + $idCol = $this->getBdd()->getOption(Bdd::OPTION_ID_COLUMN); + + if (!isset($data[$idCol]) && $this->hasId() && $this->hasSequence()) { $this->lastInsertId = $this->getBdd()->sequence()->nextVal($this->ddl['sequence']); - $data['ID'] = $this->lastInsertId; + $data[$idCol] = $this->lastInsertId; } - $histoUserId = (int)$bdd->getOption('histo-user-id'); + $histoUserId = (int)$bdd->getHistoUserId(); if ($histoUserId && $this->hasHistorique()) { - if (!isset($data['HISTO_CREATION'])) $data['HISTO_CREATION'] = new \DateTime(); - if (!isset($data['HISTO_CREATEUR_ID'])) $data['HISTO_CREATEUR_ID'] = $histoUserId; - if (!isset($data['HISTO_MODIFICATION'])) $data['HISTO_MODIFICATION'] = new \DateTime(); - if (!isset($data['HISTO_MODIFICATEUR_ID'])) $data['HISTO_MODIFICATEUR_ID'] = $histoUserId; + $histoCreationCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_CREATION_COLUMN); + $histoCreateurIdCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_CREATEUR_ID_COLUMN); + $histoModificationCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_MODIFICATION_COLUMN); + $histoModificateurIdCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_MODIFICATEUR_ID_COLUMN); + + if (!isset($data[$histoCreationCol])) $data[$histoCreationCol] = new \DateTime(); + if (!isset($data[$histoCreateurIdCol])) $data[$histoCreateurIdCol] = $histoUserId; + if (!isset($data[$histoModificationCol])) $data[$histoModificationCol] = new \DateTime(); + if (!isset($data[$histoModificateurIdCol])) $data[$histoModificateurIdCol] = $histoUserId; } - $sourceId = (int)$bdd->getOption('source-id'); + $sourceId = (int)$bdd->getSourceId(); if ($sourceId && $this->hasImport()) { - if (!isset($data['SOURCE_ID'])) $data['SOURCE_ID'] = $sourceId; + $sourceIdCol = $bdd->getOption(Bdd::OPTION_IMPORT_SOURCE_ID_COLUMN); + + if (!isset($data[$sourceIdCol])) $data[$sourceIdCol] = $sourceId; } $cols = []; @@ -329,7 +355,8 @@ class Table $vals = implode(", ", $vals); $sql = "INSERT INTO " . $this->name . " ($cols) VALUES ($vals)"; - return $bdd->exec($sql, $params, $this->makeTypesOptions()); + $bdd->exec($sql, $params, $this->makeTypesOptions()); + return true; } @@ -340,10 +367,13 @@ class Table $params = []; - $histoUserId = (int)$bdd->getOption('histo-user-id'); + $histoUserId = (int)$bdd->getHistoUserId(); if ($histoUserId && $this->hasHistorique()) { - if (!isset($data['HISTO_MODIFICATION'])) $data['HISTO_MODIFICATION'] = new \DateTime(); - if (!isset($data['HISTO_MODIFICATEUR_ID'])) $data['HISTO_MODIFICATEUR_ID'] = $histoUserId; + $histoModificationCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_MODIFICATION_COLUMN); + $histoModificateurIdCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_MODIFICATEUR_ID_COLUMN); + + if (!isset($data[$histoModificationCol])) $data[$histoModificationCol] = new \DateTime(); + if (!isset($data[$histoModificateurIdCol])) $data[$histoModificateurIdCol] = $histoUserId; } $dataSql = ''; @@ -411,11 +441,14 @@ class Table $ddl = $this->getDdl(); $bdd = $this->getBdd(); - $histoUserId = (int)$bdd->getOption('histo-user-id'); + $histoUserId = (int)$bdd->getHistoUserId(); $hasHistorique = $this->hasHistorique(); + $idCol = $this->getBdd()->getOption(Bdd::OPTION_ID_COLUMN); + if (empty($options['where']) && $hasHistorique) { - $options['where'] = 'HISTO_DESTRUCTION IS NULL'; + $histoDestructionCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_DESTRUCTION_COLUMN); + $options['where'] = $histoDestructionCol . ' IS NULL'; } /* Mise en forme des nouvelles données */ @@ -455,10 +488,13 @@ class Table } if (empty($n) && $options['soft-delete'] && $hasHistorique && $histoUserId) { // SOFT DELETE + $histoDestructionCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_DESTRUCTION_COLUMN); + $histoDestructeurIdCol = $this->getBdd()->getOption(Bdd::OPTION_HISTO_DESTRUCTEUR_ID_COLUMN); + //On ne delete pas mais on historise $n = $o; - $n['HISTO_DESTRUCTEUR_ID'] = $histoUserId; - $n['HISTO_DESTRUCTION'] = new \DateTime(); + $n[$histoDestructionCol] = new \DateTime(); + $n[$histoDestructeurIdCol] = $histoUserId; $this->update($n, $this->makeKeyArray($o, $k)); $result['soft-delete']++; } elseif (empty($n) && !$options['soft-delete']) { // DELETE @@ -473,7 +509,7 @@ class Table $oldc = $o[$c] ?? null; if ($newc instanceof \DateTime) $newc = $newc->format('Y-m-d H:i:s'); if ($oldc instanceof \DateTime) $oldc = $oldc->format('Y-m-d H:i:s'); - if ($newc != $oldc && array_key_exists($c, $n) && $c != 'ID') { + if ($newc != $oldc && array_key_exists($c, $n) && $c != $idCol) { $ok = empty($options['update-cols']); // OK par défaut si une liste n'a pas été établie manuellement if (in_array($c, $options['update-cols'])) $ok = true; @@ -487,8 +523,8 @@ class Table // dans ce cas, on considère quand même que les 2 chiffres sont identiques $toUpdate[$c] = $n[$c]; } - }else{ - $toUpdate[$c] = $n[$c]; + } else { + $toUpdate[$c] = $n[$c]; } } } @@ -507,8 +543,8 @@ class Table $result['insert']++; if ($options['return-insert-data']) { $insertedData = []; - if (isset($n['ID'])) { - $insertedData['ID'] = $n['ID']; + if (isset($n[$idCol])) { + $insertedData[$idCol] = $n[$idCol]; } foreach ($key as $null => $kc) { $insertedData[$kc] = $n[$kc]; @@ -529,7 +565,7 @@ class Table private function makeKeyArray(array $data, array|string|null $key = null): array { if (!$key && $this->hasId()) { - $key = 'ID'; + $key = $this->getBdd()->getOption(Bdd::OPTION_ID_COLUMN); } $key = (array)$key; @@ -579,7 +615,9 @@ class Table return ' WHERE ' . $where; } if ($where && !is_array($where) && $this->hasId()) { - $where = ['ID' => $where]; + $idCol = $this->getBdd()->getOption(Bdd::OPTION_ID_COLUMN); + + $where = [$idCol => $where]; } @@ -619,7 +657,9 @@ class Table { $ddl = $this->getDdl(); - return isset($ddl['columns']['ID']); + $idCol = $this->getBdd()->getOption(Bdd::OPTION_ID_COLUMN); + + return isset($ddl['columns'][$idCol]); } diff --git a/src/Trait/OptionsTrait.php b/src/Trait/OptionsTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..b002527272744936ca9f1b80257792f8a44e2b69 --- /dev/null +++ b/src/Trait/OptionsTrait.php @@ -0,0 +1,89 @@ +<?php + +namespace Unicaen\BddAdmin\Trait; + +trait OptionsTrait +{ + private array $options = []; + + + public function hasOption(string $name): bool + { + if (str_contains($name, '/')){ + $temp = &$this->options; + $names = explode('/', $name); + foreach ($names as $name) { + if (!array_key_exists($name, $temp)){ + return false; + } + $temp = &$temp[$name]; + } + return true; + }else{ + return array_key_exists($name, $this->options); + } + } + + + + public function getOption(string $name, mixed $default = null): mixed + { + if ($this->hasOption($name)) { + if (str_contains($name, '/')){ + $temp = &$this->options; + $names = explode('/', $name); + foreach ($names as $name) { + $temp = &$temp[$name]; + } + return $temp; + }else{ + return $this->options[$name]; + } + } else { + return $default; + } + } + + + + public function setOption(string $name, mixed $value): self + { + if (str_contains($name, '/')) { + $temp = &$this->options; + $names = explode('/', $name); + foreach ($names as $name) { + if (!isset($temp[$name])){ + $temp[$name] = []; + } + $temp = &$temp[$name]; + } + + $temp = $value; + }else{ + $this->options[$name] = $value; + } + + return $this; + } + + + + public function getOptions(): array + { + return $this->options; + } + + + + public function setOptions(array $options, bool $clearOthers = false): self + { + if ($clearOthers) { + $this->options = []; + } + foreach ($options as $name => $option) { + $this->setOption($name, $option); + } + + return $this; + } +} \ No newline at end of file diff --git a/src/Util.php b/src/Util.php index a7dc04aadce630bc8a71fcc4247592b4a260cc1c..e9fc0991909db67c38abeee0a3906a7fc69d99a4 100644 --- a/src/Util.php +++ b/src/Util.php @@ -33,4 +33,33 @@ class Util return [null, $object]; } } + + + + static public function arrayExport($var, string $indent = ""): string + { + switch (gettype($var)) { + case "array": + $indexed = array_keys($var) === range(0, count($var) - 1); + $r = []; + $maxKeyLen = 0; + foreach ($var as $key => $value) { + $key = self::arrayExport($key); + $keyLen = strlen($key); + if ($keyLen > $maxKeyLen) $maxKeyLen = $keyLen; + } + foreach ($var as $key => $value) { + $key = self::arrayExport($key); + $r[] = "$indent " + . ($indexed ? "" : str_pad($key, $maxKeyLen, ' ') . " => ") + . self::arrayExport($value, "$indent "); + } + + return "[\n" . implode(",\n", $r) . ",\n" . $indent . "]"; + case "boolean": + return $var ? "TRUE" : "FALSE"; + default: + return var_export($var, true); + } + } } \ No newline at end of file diff --git a/tests/AbstractBddTestCase.php b/tests/AbstractBddTestCase.php index 0ab3082ba7a12218610ff615f721be71181c6afb..b83c33c7c6294ae8c3edd316302f07e3bd06e49b 100644 --- a/tests/AbstractBddTestCase.php +++ b/tests/AbstractBddTestCase.php @@ -2,6 +2,7 @@ use PHPUnit\Framework\TestCase; use Unicaen\BddAdmin\Bdd; +use Unicaen\BddAdmin\Util; abstract class AbstractBddTestCase extends TestCase { @@ -82,38 +83,10 @@ abstract class AbstractBddTestCase extends TestCase private function error(string $message): bool { echo 'Données calculées :' . "\n"; - echo $this->arrayExport($this->calc); + echo Util::arrayExport($this->calc); $this->assertNotTrue(true, $message); return false; } - - - public function arrayExport($var, string $indent = ""): string - { - switch (gettype($var)) { - case "array": - $indexed = array_keys($var) === range(0, count($var) - 1); - $r = []; - $maxKeyLen = 0; - foreach ($var as $key => $value) { - $key = $this->arrayExport($key); - $keyLen = strlen($key); - if ($keyLen > $maxKeyLen) $maxKeyLen = $keyLen; - } - foreach ($var as $key => $value) { - $key = $this->arrayExport($key); - $r[] = "$indent " - . ($indexed ? "" : str_pad($key, $maxKeyLen, ' ') . " => ") - . $this->arrayExport($value, "$indent "); - } - - return "[\n" . implode(",\n", $r) . ",\n" . $indent . "]"; - case "boolean": - return $var ? "TRUE" : "FALSE"; - default: - return var_export($var, true); - } - } }