From c3b3943b19fabbbb3495cadfd65ef79bac1c4ebf Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 6 Jul 2025 14:53:33 -0400 Subject: [PATCH 01/10] feat: add `Oracle` database support with corresponding test classes for improved functionality. --- .github/workflows/build-oracle.yml | 43 +++++++++++++++++++++ tests/TestCase.php | 8 +++- tests/oracle/CacheManagementTest.php | 17 ++++++++ tests/oracle/ExceptionHandlingTest.php | 17 ++++++++ tests/oracle/ExtensibilityTest.php | 17 ++++++++ tests/oracle/NodeAppendTest.php | 17 ++++++++ tests/oracle/NodeDeleteTest.php | 17 ++++++++ tests/oracle/NodeInsertTest.php | 17 ++++++++ tests/oracle/NodePrependTest.php | 17 ++++++++ tests/oracle/NodeStateTest.php | 17 ++++++++ tests/oracle/QueryBehaviorTest.php | 17 ++++++++ tests/oracle/TreeTraversalTest.php | 17 ++++++++ tests/oracle/ValidationAndStructureTest.php | 17 ++++++++ 13 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build-oracle.yml create mode 100644 tests/oracle/CacheManagementTest.php create mode 100644 tests/oracle/ExceptionHandlingTest.php create mode 100644 tests/oracle/ExtensibilityTest.php create mode 100644 tests/oracle/NodeAppendTest.php create mode 100644 tests/oracle/NodeDeleteTest.php create mode 100644 tests/oracle/NodeInsertTest.php create mode 100644 tests/oracle/NodePrependTest.php create mode 100644 tests/oracle/NodeStateTest.php create mode 100644 tests/oracle/QueryBehaviorTest.php create mode 100644 tests/oracle/TreeTraversalTest.php create mode 100644 tests/oracle/ValidationAndStructureTest.php diff --git a/.github/workflows/build-oracle.yml b/.github/workflows/build-oracle.yml new file mode 100644 index 0000000..ff0cbc4 --- /dev/null +++ b/.github/workflows/build-oracle.yml @@ -0,0 +1,43 @@ +on: + pull_request: + paths-ignore: + - 'docs/**' + - 'README.md' + - 'CHANGELOG.md' + - '.gitignore' + - '.gitattributes' + + push: + paths-ignore: + - 'docs/**' + - 'README.md' + - 'CHANGELOG.md' + - '.gitignore' + - '.gitattributes' + +name: build-oracle + +jobs: + oracle: + name: Oracle tests. + uses: php-forge/actions/.github/workflows/phpunit-database.yml@main + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + with: + concurrency-group: oracle-${{ github.ref }} + database-env: | + { + "ORACLE_DATABASE": "yiitest", + "ORACLE_PASSWORD": "root" + } + database-health-cmd: "healthcheck.sh" + database-health-retries: 10 + database-image: gvenzl/oracle-xe + database-port: 1521 + database-type: oracle + database-versions: '["23"]' + enable-concurrency: true + extensions: pdo, pdo_oci + os: '["ubuntu-latest"]' + php-version: '["8.4"]' + phpunit-group: oracle diff --git a/tests/TestCase.php b/tests/TestCase.php index 58c9e0e..249b5c5 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -178,10 +178,14 @@ protected function createDatabase(): void $command->dropTable('multiple_tree')->execute(); } + $primaryKey = $this->driverName === 'oci' + ? 'NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY' + : $this->primaryKey()->notNull(); + $command->createTable( 'tree', [ - 'id' => $this->primaryKey()->notNull(), + 'id' => $primaryKey, 'name' => $this->text()->notNull(), 'lft' => $this->integer()->notNull(), 'rgt' => $this->integer()->notNull(), @@ -192,7 +196,7 @@ protected function createDatabase(): void $command->createTable( 'multiple_tree', [ - 'id' => $this->primaryKey()->notNull(), + 'id' => $primaryKey, 'tree' => $this->integer(), 'name' => $this->text()->notNull(), 'lft' => $this->integer()->notNull(), diff --git a/tests/oracle/CacheManagementTest.php b/tests/oracle/CacheManagementTest.php new file mode 100644 index 0000000..da88191 --- /dev/null +++ b/tests/oracle/CacheManagementTest.php @@ -0,0 +1,17 @@ + Date: Sun, 6 Jul 2025 14:55:54 -0400 Subject: [PATCH 02/10] fix: update `Oracle` database image to `gvenzl/oracle-free` for improved compatibility. --- .github/workflows/build-oracle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-oracle.yml b/.github/workflows/build-oracle.yml index ff0cbc4..ce7efb3 100644 --- a/.github/workflows/build-oracle.yml +++ b/.github/workflows/build-oracle.yml @@ -32,7 +32,7 @@ jobs: } database-health-cmd: "healthcheck.sh" database-health-retries: 10 - database-image: gvenzl/oracle-xe + database-image: gvenzl/oracle-free database-port: 1521 database-type: oracle database-versions: '["23"]' From 4084c3e7713f8536a3783c2f8a43c08ff8d952cc Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 6 Jul 2025 14:59:00 -0400 Subject: [PATCH 03/10] fix: update PHPUnit group from `oracle` to `oci` for consistency in testing. --- .github/workflows/build-oracle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-oracle.yml b/.github/workflows/build-oracle.yml index ce7efb3..3b9f1c1 100644 --- a/.github/workflows/build-oracle.yml +++ b/.github/workflows/build-oracle.yml @@ -40,4 +40,4 @@ jobs: extensions: pdo, pdo_oci os: '["ubuntu-latest"]' php-version: '["8.4"]' - phpunit-group: oracle + phpunit-group: oci From 8723e3225faf89b053cce72ea00fc77eb63afcf8 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 6 Jul 2025 15:05:29 -0400 Subject: [PATCH 04/10] fix: update `DSN` in `Oracle` test classes for compatibility with new database configuration. --- tests/oracle/CacheManagementTest.php | 2 +- tests/oracle/ExceptionHandlingTest.php | 2 +- tests/oracle/ExtensibilityTest.php | 2 +- tests/oracle/NodeAppendTest.php | 2 +- tests/oracle/NodeDeleteTest.php | 2 +- tests/oracle/NodeInsertTest.php | 2 +- tests/oracle/NodePrependTest.php | 2 +- tests/oracle/NodeStateTest.php | 2 +- tests/oracle/QueryBehaviorTest.php | 2 +- tests/oracle/TreeTraversalTest.php | 2 +- tests/oracle/ValidationAndStructureTest.php | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/oracle/CacheManagementTest.php b/tests/oracle/CacheManagementTest.php index da88191..96949d7 100644 --- a/tests/oracle/CacheManagementTest.php +++ b/tests/oracle/CacheManagementTest.php @@ -11,7 +11,7 @@ final class CacheManagementTest extends AbstractCacheManagement { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/ExceptionHandlingTest.php b/tests/oracle/ExceptionHandlingTest.php index 392a999..15b29a1 100644 --- a/tests/oracle/ExceptionHandlingTest.php +++ b/tests/oracle/ExceptionHandlingTest.php @@ -11,7 +11,7 @@ final class ExceptionHandlingTest extends AbstractExceptionHandling { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/ExtensibilityTest.php b/tests/oracle/ExtensibilityTest.php index d638bb7..7df7e2f 100644 --- a/tests/oracle/ExtensibilityTest.php +++ b/tests/oracle/ExtensibilityTest.php @@ -11,7 +11,7 @@ final class ExtensibilityTest extends AbstractExtensibility { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/NodeAppendTest.php b/tests/oracle/NodeAppendTest.php index bce5df6..a8c5c0d 100644 --- a/tests/oracle/NodeAppendTest.php +++ b/tests/oracle/NodeAppendTest.php @@ -11,7 +11,7 @@ final class NodeAppendTest extends AbstractNodeAppend { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/NodeDeleteTest.php b/tests/oracle/NodeDeleteTest.php index 7027904..973c548 100644 --- a/tests/oracle/NodeDeleteTest.php +++ b/tests/oracle/NodeDeleteTest.php @@ -11,7 +11,7 @@ final class NodeDeleteTest extends AbstractNodeDelete { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/NodeInsertTest.php b/tests/oracle/NodeInsertTest.php index 7872d98..88b73f8 100644 --- a/tests/oracle/NodeInsertTest.php +++ b/tests/oracle/NodeInsertTest.php @@ -11,7 +11,7 @@ final class NodeInsertTest extends AbstractNodeInsert { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/NodePrependTest.php b/tests/oracle/NodePrependTest.php index 3e6df21..a205529 100644 --- a/tests/oracle/NodePrependTest.php +++ b/tests/oracle/NodePrependTest.php @@ -11,7 +11,7 @@ final class NodePrependTest extends AbstractNodePrepend { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/NodeStateTest.php b/tests/oracle/NodeStateTest.php index b44c49b..70a9dcc 100644 --- a/tests/oracle/NodeStateTest.php +++ b/tests/oracle/NodeStateTest.php @@ -11,7 +11,7 @@ final class NodeStateTest extends AbstractNodeState { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/QueryBehaviorTest.php b/tests/oracle/QueryBehaviorTest.php index ad4c710..048dcb8 100644 --- a/tests/oracle/QueryBehaviorTest.php +++ b/tests/oracle/QueryBehaviorTest.php @@ -11,7 +11,7 @@ final class QueryBehaviorTest extends AbstractQueryBehavior { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/TreeTraversalTest.php b/tests/oracle/TreeTraversalTest.php index f55dd65..0f511c4 100644 --- a/tests/oracle/TreeTraversalTest.php +++ b/tests/oracle/TreeTraversalTest.php @@ -11,7 +11,7 @@ final class TreeTraversalTest extends AbstractTreeTraversal { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } diff --git a/tests/oracle/ValidationAndStructureTest.php b/tests/oracle/ValidationAndStructureTest.php index cc560a3..4afaf84 100644 --- a/tests/oracle/ValidationAndStructureTest.php +++ b/tests/oracle/ValidationAndStructureTest.php @@ -11,7 +11,7 @@ final class ValidationAndStructureTest extends AbstractValidationAndStructure { protected string $driverName = 'oci'; - protected string|null $dsn = 'oci:dbname=localhost/XE;charset=AL32UTF8;'; + protected string|null $dsn = 'oci:dbname=localhost/FREEPDB1;charset=AL32UTF8;'; protected string $password = 'root'; protected string $username = 'system'; } From dca0a39adda6df05b33ff286bdba90bcf8bfc63c Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 6 Jul 2025 15:22:05 -0400 Subject: [PATCH 05/10] fix: enhance XML attribute handling by converting values to strings for compatibility with `Oracle` resource types. --- tests/TestCase.php | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index 249b5c5..e008c00 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -129,16 +129,16 @@ protected function buildFlatXMLDataSet(array $dataSet): string foreach ($dataSet as $item) { $treeElement = $xml->addChild($item['type']); - $treeElement?->addAttribute('id', (string) $item['id']); + $treeElement?->addAttribute('id', $this->convertToString($item['id'])); if ($item['type'] === 'multiple_tree') { - $treeElement?->addAttribute('tree', (string) $item['tree']); + $treeElement?->addAttribute('tree', $this->convertToString($item['tree'])); } - $treeElement?->addAttribute('lft', (string) $item['lft']); - $treeElement?->addAttribute('rgt', (string) $item['rgt']); - $treeElement?->addAttribute('depth', (string) $item['depth']); - $treeElement?->addAttribute('name', $item['name']); + $treeElement?->addAttribute('lft', $this->convertToString($item['lft'])); + $treeElement?->addAttribute('rgt', $this->convertToString($item['rgt'])); + $treeElement?->addAttribute('depth', $this->convertToString($item['depth'])); + $treeElement?->addAttribute('name', $this->convertToString($item['name'])); } $dom = dom_import_simplexml($xml)->ownerDocument; @@ -166,6 +166,36 @@ protected function buildFlatXMLDataSet(array $dataSet): string ); } + /** + * Converts a value to string, handling Oracle resource types correctly. + * + * Oracle database may return numeric values as resource types when using `asArray()` with {@see ActiveRecord}. + * + * This method properly converts those resources to strings for use with {@see SimpleXMLElement::addAttribute()}. + * + * @param int|string|resource|null $value The value to convert to string + * + * @return string The converted string value + */ + protected function convertToString($value): string + { + if (is_resource($value)) { + $content = stream_get_contents($value); + + if (is_string($content)) { + return trim($content); + } + + return ''; + } + + if ($value === null) { + return ''; + } + + return (string) $value; + } + protected function createDatabase(): void { $command = $this->getDb()->createCommand(); From faaeca5200f3579cdfb3ee2d46f1c1ba3218a376 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sun, 6 Jul 2025 19:22:32 +0000 Subject: [PATCH 06/10] Apply fixes from StyleCI --- tests/TestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index e008c00..72f7150 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -173,7 +173,7 @@ protected function buildFlatXMLDataSet(array $dataSet): string * * This method properly converts those resources to strings for use with {@see SimpleXMLElement::addAttribute()}. * - * @param int|string|resource|null $value The value to convert to string + * @param int|resource|string|null $value The value to convert to string * * @return string The converted string value */ From 7093bf612172f2e6a56ff1a1f921b388a7a63941 Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 6 Jul 2025 15:30:14 -0400 Subject: [PATCH 07/10] fix: adjust column type for `name` in `tree` table to support `oci` driver. --- tests/TestCase.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index e008c00..c7b5f96 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -211,12 +211,15 @@ protected function createDatabase(): void $primaryKey = $this->driverName === 'oci' ? 'NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY' : $this->primaryKey()->notNull(); + $name =$this->driverName === 'oci' + ? $this->string()->notNull() + : $this->text()->notNull(); $command->createTable( 'tree', [ 'id' => $primaryKey, - 'name' => $this->text()->notNull(), + 'name' => $name, 'lft' => $this->integer()->notNull(), 'rgt' => $this->integer()->notNull(), 'depth' => $this->integer()->notNull(), @@ -228,7 +231,7 @@ protected function createDatabase(): void [ 'id' => $primaryKey, 'tree' => $this->integer(), - 'name' => $this->text()->notNull(), + 'name' => $name, 'lft' => $this->integer()->notNull(), 'rgt' => $this->integer()->notNull(), 'depth' => $this->integer()->notNull(), From 7868c49c2306f04ab141a8fcd1e2680b2db5e156 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sun, 6 Jul 2025 19:30:50 +0000 Subject: [PATCH 08/10] Apply fixes from StyleCI --- tests/TestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index 80427a3..fadb47b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -211,7 +211,7 @@ protected function createDatabase(): void $primaryKey = $this->driverName === 'oci' ? 'NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY' : $this->primaryKey()->notNull(); - $name =$this->driverName === 'oci' + $name = $this->driverName === 'oci' ? $this->string()->notNull() : $this->text()->notNull(); From 03431291d79d29dbc616ee2b920bda4d7ab5314b Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 6 Jul 2025 15:40:46 -0400 Subject: [PATCH 09/10] fix: replace custom string conversion with direct casting for XML attributes. --- tests/TestCase.php | 42 ++++++------------------------------------ 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index fadb47b..521ee5d 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -129,16 +129,16 @@ protected function buildFlatXMLDataSet(array $dataSet): string foreach ($dataSet as $item) { $treeElement = $xml->addChild($item['type']); - $treeElement?->addAttribute('id', $this->convertToString($item['id'])); + $treeElement?->addAttribute('id', (string) $item['id']); if ($item['type'] === 'multiple_tree') { - $treeElement?->addAttribute('tree', $this->convertToString($item['tree'])); + $treeElement?->addAttribute('tree', (string) $item['tree']); } - $treeElement?->addAttribute('lft', $this->convertToString($item['lft'])); - $treeElement?->addAttribute('rgt', $this->convertToString($item['rgt'])); - $treeElement?->addAttribute('depth', $this->convertToString($item['depth'])); - $treeElement?->addAttribute('name', $this->convertToString($item['name'])); + $treeElement?->addAttribute('lft', (string) $item['lft']); + $treeElement?->addAttribute('rgt', (string) $item['rgt']); + $treeElement?->addAttribute('depth', (string) $item['depth']); + $treeElement?->addAttribute('name', $item['name']); } $dom = dom_import_simplexml($xml)->ownerDocument; @@ -166,36 +166,6 @@ protected function buildFlatXMLDataSet(array $dataSet): string ); } - /** - * Converts a value to string, handling Oracle resource types correctly. - * - * Oracle database may return numeric values as resource types when using `asArray()` with {@see ActiveRecord}. - * - * This method properly converts those resources to strings for use with {@see SimpleXMLElement::addAttribute()}. - * - * @param int|resource|string|null $value The value to convert to string - * - * @return string The converted string value - */ - protected function convertToString($value): string - { - if (is_resource($value)) { - $content = stream_get_contents($value); - - if (is_string($content)) { - return trim($content); - } - - return ''; - } - - if ($value === null) { - return ''; - } - - return (string) $value; - } - protected function createDatabase(): void { $command = $this->getDb()->createCommand(); From 9f2f248f79054f118a896a88a7ef5016a38dd6ea Mon Sep 17 00:00:00 2001 From: Wilmer Arambula Date: Sun, 6 Jul 2025 15:46:43 -0400 Subject: [PATCH 10/10] fix: update database type in `Oracle` workflow from 'oracle' to 'oci' for consistency. --- .github/workflows/build-oracle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-oracle.yml b/.github/workflows/build-oracle.yml index 3b9f1c1..79dd54c 100644 --- a/.github/workflows/build-oracle.yml +++ b/.github/workflows/build-oracle.yml @@ -34,7 +34,7 @@ jobs: database-health-retries: 10 database-image: gvenzl/oracle-free database-port: 1521 - database-type: oracle + database-type: oci database-versions: '["23"]' enable-concurrency: true extensions: pdo, pdo_oci