From a6de982ef19301ddf8c02722e2acd1f77db43271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Mon, 14 Aug 2023 13:36:18 +0200 Subject: [PATCH] Migration automatique de table START_C --- config/database.php | 12 + .../2023_08_14_124752_migrate_oci_tables.php | 217 ++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 database/migrations/2023_08_14_124752_migrate_oci_tables.php diff --git a/config/database.php b/config/database.php index ebf8175..e384506 100644 --- a/config/database.php +++ b/config/database.php @@ -63,6 +63,18 @@ return [ ]) : [], ], + 'oracle' => [ + 'driver' => 'oracle', + 'host' => env('DB_OCI_HOST', ''), + 'port' => env('DB_OCI_PORT', '1521'), + 'database' => env('DB_OCI_DATABASE', ''), + 'username' => env('DB_OCI_USERNAME', ''), + 'password' => env('DB_OCI_PASSWORD', ''), + 'charset' => env('DB_OCI_CHARSET', 'AL32UTF8'), + 'prefix' => env('DB_OCI_PREFIX', ''), + 'prefix_schema' => env('DB_OCI_SCHEMA_PREFIX', ''), + ], + 'pgsql' => [ 'driver' => 'pgsql', 'url' => env('DATABASE_URL'), diff --git a/database/migrations/2023_08_14_124752_migrate_oci_tables.php b/database/migrations/2023_08_14_124752_migrate_oci_tables.php new file mode 100644 index 0000000..b910c85 --- /dev/null +++ b/database/migrations/2023_08_14_124752_migrate_oci_tables.php @@ -0,0 +1,217 @@ +tableList as $tableName) { + $header = $this->fetOciTableHeader($tableName); + $this->createTable( + "{$this->tablePrefix}_{$tableName}", + $header + ); + $content = $this->fetchOciTableContent($tableName, $header); + foreach ($content as $row) { + DB::table("{$this->tablePrefix}_{$tableName}")->insert((array)$row); + } + } + } + + /** + * Reverse the migrations. + * + * @return void + * @throws \Error Wont rollback. + */ + public function down(): void + { + throw new \Error('Wont rollback'); + } + + /** + * Create table in SQL + * + * @param string $tableName + * @param array $tableColumns With name, type, size. + * @return void + */ + private function createTable(string $tableName, array $tableColumns) + { + Schema::dropIfExists($tableName); + Schema::create($tableName, function (Blueprint $table) use ($tableColumns) { + foreach ($tableColumns as $tableColumn) { + $tableComment = "{$tableColumn->name} {$tableColumn->type} {$tableColumn->size}"; + switch ($tableColumn->type) { + case 'NUMBER': + $table->bigInteger($tableColumn->name) + ->nullable()->comment($tableComment); + break; + case 'VARCHAR2': + case 'CHAR': + $table->string($tableColumn->name, $tableColumn->size) + ->nullable()->comment($tableComment); + break; + case 'DATE': + $table->dateTime($tableColumn->name) + ->nullable()->comment($tableComment); + break; + default: + throw new Error("Unhandled type {$tableColumn->type}"); + } + } + }); + } + + /** + * Oci table header + * + * @param string $tableName + * @return array with name, type, size + * @throws \Error If connection or query fails. + */ + private function fetOciTableHeader(string $tableName): array + { + $tableName = "{$this->tablePrefix}_{$tableName}"; + $conn = $this->getOciConnection(); + + // Prepare the statement. + $stid = oci_parse($conn, "SELECT * FROM {$tableName}"); + + if (!$stid) { + $e = oci_error($conn); + throw new \Error(htmlentities($e['message'], ENT_QUOTES)); + } + + // Use OCI_DESCRIBE_ONLY if not fetching rows. + oci_execute($stid, OCI_DESCRIBE_ONLY); + + if (!$stid) { + $e = oci_error($conn); + throw new \Error(htmlentities($e['message'], ENT_QUOTES)); + } + + $ncols = oci_num_fields($stid); + + $out = []; + + for ($i = 1; $i <= $ncols; $i++) { + $column_name = oci_field_name($stid, $i); + $column_type = oci_field_type($stid, $i); + $column_size = oci_field_size($stid, $i); + + $out[] = (object)[ + 'name' => $column_name, + 'type' => $column_type, + 'size' => $column_size + ]; + } + + oci_free_statement($stid); + oci_close($conn); + return $out; + } + + /** + * Oci table content + * + * @param string $tableName Table name. + * @param array $header With name, type,size. + * @return array With DB content. + * @throws \Error If connection or query fails. + */ + private function fetchOciTableContent(string $tableName, array $header): array + { + $out = []; + $tableName = "{$this->tablePrefix}_{$tableName}"; + $conn = $this->getOciConnection(); + + // Prepare the statement. + $stid = oci_parse($conn, "SELECT * FROM {$tableName}"); + + if (!$stid) { + $e = oci_error($conn); + throw new \Error(htmlentities($e['message'], ENT_QUOTES)); + } + + $r = oci_execute($stid); + if (!$stid) { + $e = oci_error($conn); + throw new \Error(htmlentities($e['message'], ENT_QUOTES)); + } + + while ($row = oci_fetch_array($stid, OCI_ASSOC + OCI_RETURN_NULLS)) { + $outRow = []; + foreach ($row as $k => $item) { + /** @var string */ + $type = collect($header)->where('name', $k)->firstOrFail()->type; + if ($type === 'DATE' and $item !== null) { + $item = $this->tryToParseCarbon($item); + } + $outRow[$k] = $item; + } + $out[] = (object)$outRow; + } + + oci_free_statement($stid); + oci_close($conn); + return $out; + } + + /** + * get Oci connection + * + * @return resource oci8 connection resource + * @throws \Error If connection fails. + */ + private function getOciConnection() + { + $conn = oci_connect('system', 'secret', 'localhost/XE'); + if (!$conn) { + $e = oci_error(); + throw new \Error(htmlentities($e['message'], ENT_QUOTES)); + } + return $conn; + } + + /** + * Try to parse freaking Start coq dates + * + * @param string $date + * @return \Carbon\Carbon + * @throws \Carbon\Exceptions\InvalidFormatException In case of failure. + */ + private function tryToParseCarbon(string $date): Carbon + { + return Carbon::parse($date); + } +};