diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea62a0635..51fca5c22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: composer: name: Install PHP dependencies runs-on: ubuntu-latest - container: joomlaprojects/docker-images:php8.1 + container: joomlaprojects/docker-images:php8.3 steps: - uses: actions/checkout@v4 - uses: actions/cache@v4 @@ -32,7 +32,7 @@ jobs: code-style-php: name: Check PHP code style runs-on: ubuntu-latest - container: joomlaprojects/docker-images:php8.1 + container: joomlaprojects/docker-images:php8.3 needs: [composer] steps: - uses: actions/checkout@v4 @@ -50,7 +50,6 @@ jobs: runs-on: ubuntu-latest container: joomlaprojects/docker-images:php8.4 needs: [code-style-php] - continue-on-error: true steps: - uses: actions/checkout@v4 - uses: actions/cache/restore@v4 @@ -68,7 +67,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Run Unit tests @@ -84,7 +83,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3'] + php_version: ['8.3', '8.4'] db_engine: ['mysql', 'mysqli'] db_version: ['5.7', '8.0'] steps: @@ -110,7 +109,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Run Unit tests @@ -134,7 +133,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3'] + php_version: ['8.3', '8.4'] db_version: ['10', '11'] steps: - uses: actions/checkout@v4 @@ -158,7 +157,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Run Unit tests @@ -190,7 +189,7 @@ jobs: needs: [code-style-php] strategy: matrix: - php_version: ['8.1', '8.2', '8.3'] + php_version: ['8.3', '8.4'] steps: - uses: actions/checkout@v4 - name: Setup PHP diff --git a/README.md b/README.md index 443aef3cc..d255045f2 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ function search($title) In the first case, the title variable is simply escaped and quoted. Any quote characters in the title string will be prepended with a backslash and the whole string will be wrapped in quotes. -In the second case, the example shows how to treat a search string that will be used in a `LIKE` clause. In this case, the title variable is manually escaped using `escape` with a second argument of `true`. This will force other special characters to be escaped (otherwise you could set youself up for serious performance problems if the user includes too many wildcards). Then, the result is passed to the `quote` method but escaping is turned off (because it has already been done manually). +In the second case, the example shows how to treat a search string that will be used in a `LIKE` clause. In this case, the title variable is manually escaped using `escape` with a second argument of `true`. This will force other special characters to be escaped (otherwise you could set yourself up for serious performance problems if the user includes too many wildcards). Then, the result is passed to the `quote` method but escaping is turned off (because it has already been done manually). In the third case, the title variable is an array so the whole array can be passed to the `quote` method (this saves using a closure and a ) @@ -102,7 +102,7 @@ The `Database\DatabaseIterator` class allows iteration over database results ```php $db = DatabaseDriver::getInstance($options); $iterator = $db->setQuery( - $db->getQuery(true)->select('*')->from('#__content') + $db->createQuery()->select('*')->from('#__content') )->getIterator(); foreach ($iterator as $row) @@ -118,7 +118,7 @@ $count = count($iterator); ``` ## Logging -`Database\DatabaseDriver` implements the `Psr\Log\LoggerAwareInterface` so is ready for intergrating with a logging package that supports that standard. +`Database\DatabaseDriver` implements the `Psr\Log\LoggerAwareInterface` so is ready for integrating with a logging package that supports that standard. Drivers log all errors with a log level of `LogLevel::ERROR`. @@ -173,12 +173,12 @@ This is the log file: ## Installation via Composer -Add `"joomla/database": "~3.0"` to the require block in your composer.json and then run `composer install`. +Add `"joomla/database": "~4.0"` to the require block in your composer.json and then run `composer install`. ```json { "require": { - "joomla/database": "~3.0" + "joomla/database": "~4.0" } } ``` @@ -186,11 +186,11 @@ Add `"joomla/database": "~3.0"` to the require block in your composer.json and t Alternatively, you can simply run the following from the command line: ```sh -composer require joomla/database "~3.0" +composer require joomla/database "~4.0" ``` If you want to include the test sources, use ```sh -composer require --prefer-source joomla/database "~3.0" +composer require --prefer-source joomla/database "~4.0" ``` diff --git a/SECURITY.md b/SECURITY.md index ed9f30a8f..0ea4e4f4e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,8 @@ These versions are currently being supported with security updates: | Version | Supported | -| ------- | ------------------ | +|---------| ------------------ | +| 4.x.x | :white_check_mark: | | 3.x.x | :white_check_mark: | | 2.0.x | :white_check_mark: | | 1.8.x | :x: | diff --git a/Tests/AbstractDatabaseDriverTestCase.php b/Tests/AbstractDatabaseDriverTestCase.php index 2d7ea2b11..b4377cf7a 100644 --- a/Tests/AbstractDatabaseDriverTestCase.php +++ b/Tests/AbstractDatabaseDriverTestCase.php @@ -13,6 +13,7 @@ use Joomla\Database\ParameterType; use Joomla\Database\QueryInterface; use Joomla\Test\DatabaseTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Base test class for Joomla\Database\DatabaseDriver @@ -72,13 +73,15 @@ public function testIsConnectionEncryptionSupported() /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** @@ -86,9 +89,8 @@ public function dataDropTable() * * @param string $table The name of the database table to drop. * @param boolean $alreadyExists Flag indicating the table should exist before the DROP TABLE query. - * - * @dataProvider dataDropTable */ + #[DataProvider('dataDropTable')] public function testDropTable(string $table, bool $alreadyExists) { $this->assertSame( @@ -110,9 +112,9 @@ public function testDropTable(string $table, bool $alreadyExists) /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - abstract public function dataEscape(): \Generator; + abstract public static function dataEscape(): array; /** * @testdox Text can be escaped @@ -120,9 +122,8 @@ abstract public function dataEscape(): \Generator; * @param string $text The string to be escaped. * @param boolean $extra Optional parameter to provide extra escaping. * @param string $expected The expected result. - * - * @dataProvider dataEscape */ + #[DataProvider('dataEscape')] public function testEscape($text, $extra, $expected) { $this->assertSame( @@ -240,9 +241,9 @@ public function testGetIterator() /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - abstract public function dataGetTableColumns(): \Generator; + abstract public static function dataGetTableColumns(): array; /** * @testdox Information about the columns of a database table is returned @@ -250,9 +251,8 @@ abstract public function dataGetTableColumns(): \Generator; * @param string $table The name of the database table. * @param boolean $typeOnly True (default) to only return field types. * @param array $expected Expected result. - * - * @dataProvider dataGetTableColumns */ + #[DataProvider('dataGetTableColumns')] public function testGetTableColumns(string $table, bool $typeOnly, array $expected) { $this->assertEquals( @@ -596,18 +596,17 @@ public function testLockAndUnlockTable() /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - abstract public function dataQuoteBinary(): \Generator; + abstract public static function dataQuoteBinary(): array; /** * @testdox A binary value is quoted properly * * @param string $data The binary quoted input string. * @param string $expected The expected result. - * - * @dataProvider dataQuoteBinary */ + #[DataProvider('dataQuoteBinary')] public function testQuoteBinary($data, $expected) { $this->assertSame($expected, static::$connection->quoteBinary($data)); @@ -616,9 +615,9 @@ public function testQuoteBinary($data, $expected) /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - abstract public function dataQuoteName(): \Generator; + abstract public static function dataQuoteName(): array; /** * @testdox A value is name quoted properly @@ -626,9 +625,8 @@ abstract public function dataQuoteName(): \Generator; * @param array|string $name The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes. * @param array|string $as The AS query part associated to $name. * @param array|string $expected The expected result. - * - * @dataProvider dataQuoteName */ + #[DataProvider('dataQuoteName')] public function testQuoteName($name, $as, $expected) { $this->assertSame( diff --git a/Tests/DatabaseExporterTest.php b/Tests/DatabaseExporterTest.php index 3d11e5e31..e2bb22a9f 100644 --- a/Tests/DatabaseExporterTest.php +++ b/Tests/DatabaseExporterTest.php @@ -8,8 +8,12 @@ namespace Joomla\Database\Tests; use Joomla\Database\DatabaseExporter; +use Joomla\Database\DatabaseImporter; use Joomla\Database\DatabaseInterface; +use Joomla\Database\Tests\Stubs\TestDatabaseExporter; +use Joomla\Database\Tests\Stubs\TestDatabaseImporter; use Joomla\Test\TestHelper; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -18,21 +22,39 @@ */ class DatabaseExporterTest extends TestCase { + /** + * Importer object + * + * @var DatabaseExporter + */ + private $exporter; + + /** + * Sets up the fixture. + * + * This method is called before a test is executed. + * + * @return void + */ + protected function setUp(): void + { + parent::setUp(); + + $this->exporter = new TestDatabaseExporter(); + } + /** * @testdox The exporter is correctly configured when instantiated */ public function testInstantiation() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - $expected = (object) [ 'withStructure' => true, 'withData' => false, ]; - $this->assertEquals($expected, TestHelper::getValue($exporter, 'options')); - $this->assertSame('xml', TestHelper::getValue($exporter, 'asFormat')); + $this->assertEquals($expected, TestHelper::getValue($this->exporter, 'options')); + $this->assertSame('xml', TestHelper::getValue($this->exporter, 'asFormat')); } /** @@ -40,34 +62,33 @@ public function testInstantiation() */ public function testAsXml() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - - $this->assertSame($exporter, $exporter->asXml(), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->asXml(), 'The exporter supports method chaining'); - $this->assertSame('xml', TestHelper::getValue($exporter, 'asFormat')); + $this->assertSame('xml', TestHelper::getValue($this->exporter, 'asFormat')); } /** * Data provider for from test cases * - * @return \Generator + * @return array */ - public function dataFrom(): \Generator + public static function dataFrom(): array { - yield 'single table' => [ - '#__dbtest', - false, - ]; - - yield 'multiple tables' => [ - ['#__content', '#__dbtest'], - false, - ]; - - yield 'incorrect table data type' => [ - new \stdClass(), - true, + return [ + 'single table' => [ + '#__dbtest', + false, + ], + + 'multiple tables' => [ + ['#__content', '#__dbtest'], + false, + ], + + 'incorrect table data type' => [ + new \stdClass(), + true, + ], ]; } @@ -76,21 +97,17 @@ public function dataFrom(): \Generator * * @param string[]|string $from The name of a single table, or an array of the table names to export. * @param boolean $shouldRaiseException Flag indicating the exporter should raise an exception for an unsupported data type - * - * @dataProvider dataFrom */ + #[DataProvider('dataFrom')] public function testFrom($from, bool $shouldRaiseException) { if ($shouldRaiseException) { $this->expectException(\InvalidArgumentException::class); } - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - - $this->assertSame($exporter, $exporter->from($from), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->from($from), 'The exporter supports method chaining'); - $this->assertSame((array) $from, TestHelper::getValue($exporter, 'from')); + $this->assertSame((array) $from, TestHelper::getValue($this->exporter, 'from')); } /** @@ -98,13 +115,10 @@ public function testFrom($from, bool $shouldRaiseException) */ public function testSetDbo() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - /** @var DatabaseInterface|MockObject $db */ $db = $this->createMock(DatabaseInterface::class); - $this->assertSame($exporter, $exporter->setDbo($db), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->setDbo($db), 'The exporter supports method chaining'); } /** @@ -112,12 +126,9 @@ public function testSetDbo() */ public function testWithStructure() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); + $this->assertSame($this->exporter, $this->exporter->withStructure(false), 'The exporter supports method chaining'); - $this->assertSame($exporter, $exporter->withStructure(false), 'The exporter supports method chaining'); - - $options = TestHelper::getValue($exporter, 'options'); + $options = TestHelper::getValue($this->exporter, 'options'); $this->assertFalse($options->withStructure); } @@ -127,12 +138,9 @@ public function testWithStructure() */ public function testWithData() { - /** @var DatabaseExporter|MockObject $exporter */ - $exporter = $this->getMockForAbstractClass(DatabaseExporter::class); - - $this->assertSame($exporter, $exporter->withData(true), 'The exporter supports method chaining'); + $this->assertSame($this->exporter, $this->exporter->withData(true), 'The exporter supports method chaining'); - $options = TestHelper::getValue($exporter, 'options'); + $options = TestHelper::getValue($this->exporter, 'options'); $this->assertTrue($options->withData); } diff --git a/Tests/DatabaseFactoryTest.php b/Tests/DatabaseFactoryTest.php index 17433bef1..4fbfd7148 100644 --- a/Tests/DatabaseFactoryTest.php +++ b/Tests/DatabaseFactoryTest.php @@ -18,6 +18,7 @@ use Joomla\Database\QueryInterface; use Joomla\Database\StatementInterface; use Joomla\Test\TestHelper; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -49,18 +50,20 @@ protected function setUp(): void /** * Data provider for driver test cases * - * @return \Generator + * @return array */ - public function dataGetDriver(): \Generator + public static function dataGetDriver(): array { - yield 'supported driver' => [ - 'mysqli', - false, - ]; + return [ + 'supported driver' => [ + 'mysqli', + false, + ], - yield 'unsupported exporter' => [ - 'mariadb', - true, + 'unsupported exporter' => [ + 'mariadb', + true, + ], ]; } @@ -69,9 +72,8 @@ public function dataGetDriver(): \Generator * * @param string $adapter The type of adapter to create * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter - * - * @dataProvider dataGetDriver */ + #[DataProvider('dataGetDriver')] public function testGetDriver(string $adapter, bool $shouldRaiseException) { if ($shouldRaiseException) { @@ -87,26 +89,28 @@ public function testGetDriver(string $adapter, bool $shouldRaiseException) /** * Data provider for exporter test cases * - * @return \Generator + * @return array */ - public function dataGetExporter(): \Generator + public static function dataGetExporter(): array { - yield 'exporter without database driver' => [ - 'mysqli', - false, - null, - ]; + return [ + 'exporter without database driver' => [ + 'mysqli', + false, + false, + ], - yield 'exporter with database driver' => [ - 'mysqli', - false, - $this->createMock(MysqliDriver::class), - ]; + 'exporter with database driver' => [ + 'mysqli', + false, + true, + ], - yield 'unsupported exporter' => [ - 'mariadb', - true, - null, + 'unsupported exporter' => [ + 'mariadb', + true, + false, + ], ]; } @@ -116,15 +120,20 @@ public function dataGetExporter(): \Generator * @param string $adapter The type of adapter to create * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter * @param DatabaseDriver|null $databaseDriver The optional database driver to be injected into the exporter - * - * @dataProvider dataGetExporter */ - public function testGetExporter(string $adapter, bool $shouldRaiseException, ?DatabaseDriver $databaseDriver) + #[DataProvider('dataGetExporter')] + public function testGetExporter(string $adapter, bool $shouldRaiseException, bool $createDb) { if ($shouldRaiseException) { $this->expectException(UnsupportedAdapterException::class); } + $databaseDriver = null; + + if ($createDb) { + $databaseDriver = $this->createMock(MysqliDriver::class); + } + $exporter = $this->factory->getExporter($adapter, $databaseDriver); $this->assertInstanceOf( @@ -143,44 +152,51 @@ public function testGetExporter(string $adapter, bool $shouldRaiseException, ?Da /** * Data provider for importer test cases * - * @return \Generator + * @return array */ - public function dataGetImporter(): \Generator + public static function dataGetImporter(): array { - yield 'importer without database driver' => [ - 'mysqli', - false, - null, - ]; + return [ + 'importer without database driver' => [ + 'mysqli', + false, + false, + ], - yield 'importer with database driver' => [ - 'mysqli', - false, - $this->createMock(MysqliDriver::class), - ]; + 'importer with database driver' => [ + 'mysqli', + false, + true, + ], - yield 'unsupported importer' => [ - 'mariadb', - true, - null, + 'unsupported importer' => [ + 'mariadb', + true, + false, + ], ]; } /** * @testdox The factory builds a database importer correctly * - * @param string $adapter The type of adapter to create - * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter - * @param DatabaseDriver|null $databaseDriver The optional database driver to be injected into the importer - * - * @dataProvider dataGetImporter + * @param string $adapter The type of adapter to create + * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter + * @param boolean $createDb The optional database driver to be injected into the importer */ - public function testGetImporter(string $adapter, bool $shouldRaiseException, ?DatabaseDriver $databaseDriver) + #[DataProvider('dataGetImporter')] + public function testGetImporter(string $adapter, bool $shouldRaiseException, bool $createDb) { if ($shouldRaiseException) { $this->expectException(UnsupportedAdapterException::class); } + $databaseDriver = null; + + if ($createDb) { + $databaseDriver = $this->createMock(MysqliDriver::class); + } + $importer = $this->factory->getImporter($adapter, $databaseDriver); $this->assertInstanceOf( @@ -199,26 +215,33 @@ public function testGetImporter(string $adapter, bool $shouldRaiseException, ?Da /** * Data provider for iterator test cases * - * @return \Generator + * @return array */ - public function dataGetIterator(): \Generator + public static function dataGetIterator(): array { - yield 'driver without custom iterator' => [ - 'mysqli', - $this->createMock(StatementInterface::class), + return [ + 'driver without custom iterator' => [ + 'mysqli', + true, + ], ]; } /** * @testdox The factory builds a database iterator correctly * - * @param string $adapter The type of adapter to create - * @param StatementInterface $statement Statement holding the result set to be iterated. - * - * @dataProvider dataGetIterator + * @param string $adapter The type of adapter to create + * @param bool $createStatement Statement holding the result set to be iterated. */ - public function testGetIterator(string $adapter, StatementInterface $statement) + #[DataProvider('dataGetIterator')] + public function testGetIterator(string $adapter, bool $createStatement) { + $statement = null; + + if ($createStatement) { + $statement = $this->createMock(StatementInterface::class); + } + $this->assertInstanceOf( DatabaseIterator::class, $this->factory->getIterator($adapter, $statement) @@ -228,38 +251,45 @@ public function testGetIterator(string $adapter, StatementInterface $statement) /** * Data provider for query test cases * - * @return \Generator + * @return array */ - public function dataGetQuery(): \Generator + public static function dataGetQuery(): array { - yield 'supported query' => [ - 'mysqli', - false, - $this->createMock(MysqliDriver::class), - ]; + return [ + 'supported query' => [ + 'mysqli', + false, + true, + ], - yield 'unsupported query' => [ - 'mariadb', - true, - null, + 'unsupported query' => [ + 'mariadb', + true, + false, + ], ]; } /** * @testdox The factory builds a database query object correctly * - * @param string $adapter The type of adapter to create - * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter - * @param DatabaseDriver|null $databaseDriver The optional database driver to be injected into the importer - * - * @dataProvider dataGetQuery + * @param string $adapter The type of adapter to create + * @param boolean $shouldRaiseException Flag indicating the factory should raise an exception for an unsupported adapter + * @param boolean $createDb The optional database driver to be injected into the importer */ - public function testGetQuery(string $adapter, bool $shouldRaiseException, ?DatabaseDriver $databaseDriver) + #[DataProvider('dataGetQuery')] + public function testGetQuery(string $adapter, bool $shouldRaiseException, bool $createDb) { if ($shouldRaiseException) { $this->expectException(UnsupportedAdapterException::class); } + $databaseDriver = null; + + if ($createDb) { + $databaseDriver = $this->createMock(MysqliDriver::class); + } + $this->assertInstanceOf( QueryInterface::class, $this->factory->getQuery($adapter, $databaseDriver) diff --git a/Tests/DatabaseImporterTest.php b/Tests/DatabaseImporterTest.php index 8a6a4ef4d..c3e369163 100644 --- a/Tests/DatabaseImporterTest.php +++ b/Tests/DatabaseImporterTest.php @@ -9,6 +9,8 @@ use Joomla\Database\DatabaseImporter; use Joomla\Database\DatabaseInterface; +use Joomla\Database\Tests\Stubs\TestDatabaseImporter; +use Joomla\Database\Tests\Stubs\TestDatabaseQuery; use Joomla\Test\TestHelper; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -18,20 +20,38 @@ */ class DatabaseImporterTest extends TestCase { + /** + * Importer object + * + * @var DatabaseImporter + */ + private $importer; + + /** + * Sets up the fixture. + * + * This method is called before a test is executed. + * + * @return void + */ + protected function setUp(): void + { + parent::setUp(); + + $this->importer = new TestDatabaseImporter(); + } + /** * @testdox The importer is correctly configured when instantiated */ public function testInstantiation() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); - $expected = (object) [ 'withStructure' => true, ]; - $this->assertEquals($expected, TestHelper::getValue($importer, 'options')); - $this->assertSame('xml', TestHelper::getValue($importer, 'asFormat')); + $this->assertEquals($expected, TestHelper::getValue($this->importer, 'options')); + $this->assertSame('xml', TestHelper::getValue($this->importer, 'asFormat')); } /** @@ -39,12 +59,9 @@ public function testInstantiation() */ public function testAsXml() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); + $this->assertSame($this->importer, $this->importer->asXml(), 'The importer supports method chaining'); - $this->assertSame($importer, $importer->asXml(), 'The importer supports method chaining'); - - $this->assertSame('xml', TestHelper::getValue($importer, 'asFormat')); + $this->assertSame('xml', TestHelper::getValue($this->importer, 'asFormat')); } /** @@ -52,13 +69,10 @@ public function testAsXml() */ public function testSetDbo() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); - /** @var DatabaseInterface|MockObject $db */ $db = $this->createMock(DatabaseInterface::class); - $this->assertSame($importer, $importer->setDbo($db), 'The importer supports method chaining'); + $this->assertSame($this->importer, $this->importer->setDbo($db), 'The importer supports method chaining'); } /** @@ -66,12 +80,9 @@ public function testSetDbo() */ public function testWithStructure() { - /** @var DatabaseImporter|MockObject $importer */ - $importer = $this->getMockForAbstractClass(DatabaseImporter::class); - - $this->assertSame($importer, $importer->withStructure(false), 'The importer supports method chaining'); + $this->assertSame($this->importer, $this->importer->withStructure(false), 'The importer supports method chaining'); - $options = TestHelper::getValue($importer, 'options'); + $options = TestHelper::getValue($this->importer, 'options'); $this->assertFalse($options->withStructure); } diff --git a/Tests/DatabaseQueryTest.php b/Tests/DatabaseQueryTest.php index f225e1ad3..e29402af2 100644 --- a/Tests/DatabaseQueryTest.php +++ b/Tests/DatabaseQueryTest.php @@ -11,6 +11,8 @@ use Joomla\Database\Exception\QueryTypeAlreadyDefinedException; use Joomla\Database\Exception\UnknownTypeException; use Joomla\Database\ParameterType; +use Joomla\Database\Tests\Stubs\TestDatabaseQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -45,10 +47,7 @@ protected function setUp(): void parent::setUp(); $this->db = $this->createMock(DatabaseInterface::class); - $this->query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [$this->db] - ); + $this->query = new TestDatabaseQuery($this->db); } /** @@ -77,14 +76,6 @@ public function testCallChangeQueryType() ->call('foo'); } - /** - * @testdox A string is cast as a character string for the driver - */ - public function testCastAsChar() - { - $this->assertSame('foo', $this->query->castAsChar('foo')); - } - /** * @testdox A string is cast as a character string for the driver */ @@ -113,12 +104,14 @@ public function testCastAsWithUnknownType() /** * Data provider for character length test cases * - * @return \Generator + * @return array */ - public function dataCharLength(): \Generator + public static function dataCharLength(): array { - yield 'field without comparison' => ['a.title', null, null, 'CHAR_LENGTH(a.title)']; - yield 'field with comparison' => ['a.title', '!=', '0', 'CHAR_LENGTH(a.title) != 0']; + return [ + 'field without comparison' => ['a.title', null, null, 'CHAR_LENGTH(a.title)'], + 'field with comparison' => ['a.title', '!=', '0', 'CHAR_LENGTH(a.title) != 0'], + ]; } /** @@ -128,9 +121,8 @@ public function dataCharLength(): \Generator * @param string|null $operator Comparison operator between charLength integer value and $condition * @param string|null $condition Integer value to compare charLength with. * @param string $expected The expected query string. - * - * @dataProvider dataCharLength */ + #[DataProvider('dataCharLength')] public function testCharLength(string $field, ?string $operator, ?string $condition, string $expected) { $this->assertSame( @@ -156,12 +148,14 @@ public function testColumns() /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'CONCATENATE(foo || bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "CONCATENATE(foo || ' and ' || bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'CONCATENATE(foo || bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "CONCATENATE(foo || ' and ' || bar)"], + ]; } /** @@ -170,9 +164,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) @@ -201,12 +194,14 @@ public function testCurrentTimestamp() /** * Data provider for dateAdd test cases * - * @return \Generator + * @return array */ - public function dataDateAdd(): \Generator + public static function dataDateAdd(): array { - yield 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL 1 DAY)"]; - yield 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL -1 DAY)"]; + return [ + 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL 1 DAY)"], + 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "DATE_ADD('2019-10-13', INTERVAL -1 DAY)"], + ]; } /** @@ -216,9 +211,8 @@ public function dataDateAdd(): \Generator * @param string $interval The string representation of the appropriate number of units * @param string $datePart The part of the date to perform the addition on * @param string $expected The expected query string. - * - * @dataProvider dataDateAdd */ + #[DataProvider('dataDateAdd')] public function testDateAdd(string $date, string $interval, string $datePart, string $expected) { $this->assertSame( @@ -525,12 +519,14 @@ public function testLength() /** * Data provider for null date test cases * - * @return \Generator + * @return array */ - public function dataNullDate(): \Generator + public static function dataNullDate(): array { - yield 'null date with quote' => [true, "'0000-00-00 00:00:00'"]; - yield 'null date without quote' => [false, '0000-00-00 00:00:00']; + return [ + 'null date with quote' => [true, "'0000-00-00 00:00:00'"], + 'null date without quote' => [false, '0000-00-00 00:00:00'], + ]; } /** @@ -538,9 +534,8 @@ public function dataNullDate(): \Generator * * @param boolean $quoted Optionally wraps the null date in database quotes (true by default). * @param string $expected The expected query string. - * - * @dataProvider dataNullDate */ + #[DataProvider('dataNullDate')] public function testNullDate(bool $quoted, string $expected) { $this->db->expects($this->once()) @@ -566,10 +561,7 @@ public function testNullDateException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->nullDate(); } @@ -627,10 +619,7 @@ public function testIsNullDatetimeException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->isNullDatetime('a.created'); } @@ -673,10 +662,7 @@ public function testQuoteException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->quote('foo'); } @@ -705,10 +691,7 @@ public function testQuoteNameException() { $this->expectException(\RuntimeException::class); - $query = $this->getMockForAbstractClass( - DatabaseQuery::class, - [] - ); + $query = new TestDatabaseQuery(); $query->quoteName('foo'); } @@ -930,28 +913,30 @@ public function testAndWhere() /** * Data provider for bind test cases * - * @return \Generator - */ - public function dataBind(): \Generator - { - yield 'string field' => ['foo', 'bar', ParameterType::STRING, [ - 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'numeric field' => ['foo', 42, ParameterType::INTEGER, [ - 'foo' => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'numeric key' => [1, 'bar', ParameterType::STRING, [ - 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'array of data' => [[1, 'foo'], [42, 'bar'], [ParameterType::INTEGER, ParameterType::STRING], [ - 1 => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], - 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; - yield 'key array, single data value' => [[1, 2, 3], 'bar', ParameterType::STRING, [ - 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - 2 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - 3 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], - ]]; + * @return array + */ + public static function dataBind(): array + { + return [ + 'string field' => ['foo', 'bar', ParameterType::STRING, [ + 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + 'numeric field' => ['foo', 42, ParameterType::INTEGER, [ + 'foo' => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], + ]], + 'numeric key' => [1, 'bar', ParameterType::STRING, [ + 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + 'array of data' => [[1, 'foo'], [42, 'bar'], [ParameterType::INTEGER, ParameterType::STRING], [ + 1 => (object) ['value' => 42, 'dataType' => 'int', 'length' => 0, 'driverOptions' => []], + 'foo' => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + 'key array, single data value' => [[1, 2, 3], 'bar', ParameterType::STRING, [ + 1 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + 2 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + 3 => (object) ['value' => 'bar', 'dataType' => 'string', 'length' => 0, 'driverOptions' => []], + ]], + ]; } /** @@ -965,9 +950,8 @@ public function dataBind(): \Generator * @param array|string $dataType Constant corresponding to a SQL datatype. It can be an array, in this case it * has to be same length of $key * @param array $expected The expected structure of `$bounded` - * - * @dataProvider dataBind */ + #[DataProvider('dataBind')] public function testBind($key, $value, $dataType, $expected) { $this->assertSame($this->query, $this->query->bind($key, $value, $dataType), 'The query builder supports method chaining'); diff --git a/Tests/Monitor/LoggingMonitorTest.php b/Tests/Monitor/LoggingMonitorTest.php index 074fc52e5..5465e31a6 100644 --- a/Tests/Monitor/LoggingMonitorTest.php +++ b/Tests/Monitor/LoggingMonitorTest.php @@ -8,7 +8,7 @@ use Joomla\Database\Monitor\LoggingMonitor; use PHPUnit\Framework\TestCase; -use Psr\Log\Test\TestLogger; +use ColinODell\PsrTestLogger\TestLogger; /** * Test class for Joomla\Database\Monitor\LoggingMonitor diff --git a/Tests/Mysql/MysqlDriverTest.php b/Tests/Mysql/MysqlDriverTest.php index 47d68214d..feae93579 100644 --- a/Tests/Mysql/MysqlDriverTest.php +++ b/Tests/Mysql/MysqlDriverTest.php @@ -14,6 +14,7 @@ use Joomla\Database\Mysql\MysqlQuery; use Joomla\Database\ParameterType; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Mysql\MysqlDriver @@ -91,9 +92,9 @@ protected function tearDown(): void /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { // For unknown reasons, the connection gets lost on Travis. re-establish, if that happens if (static::$connection === null) { @@ -103,76 +104,78 @@ public function dataGetTableColumns(): \Generator $isMySQL8 = !static::$connection->isMariaDb() && version_compare(static::$connection->getVersion(), '8.0', '>='); $useDisplayWidth = static::$connection->isMariaDb() || version_compare(static::$connection->getVersion(), '8.0.17', '<'); - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'int unsigned', - 'title' => 'varchar', - 'start_date' => 'datetime', - 'description' => 'text', - 'data' => 'blob', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'int unsigned', + 'title' => 'varchar', + 'start_date' => 'datetime', + 'description' => 'text', + 'data' => 'blob', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', - 'Collation' => $isMySQL8 ? null : '', - 'Null' => 'NO', - 'Key' => 'PRI', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => 'auto_increment', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'varchar(50)', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'datetime', - 'Collation' => '', - 'Null' => 'NO', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'text', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'blob', - 'Collation' => '', - 'Null' => 'YES', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', + 'Collation' => $isMySQL8 ? null : '', + 'Null' => 'NO', + 'Key' => 'PRI', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => 'auto_increment', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'varchar(50)', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'datetime', + 'Collation' => '', + 'Null' => 'NO', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'text', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'blob', + 'Collation' => '', + 'Null' => 'YES', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], ], ], ]; @@ -181,50 +184,58 @@ public function dataGetTableColumns(): \Generator /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\\\'%_abc123']; - yield ["'%_abc123", true, '\\\'\\%\_abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\\\'%_abc123'], + ["'%_abc123", true, '\\\'\\%\_abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "X'" . bin2hex('DATA') . "'"]; - yield ["\x00\x01\x02\xff", "X'000102ff'"]; - yield ["\x01\x01\x02\xff", "X'010102ff'"]; + return [ + ['DATA', "X'" . bin2hex('DATA') . "'"], + ["\x00\x01\x02\xff", "X'000102ff'"], + ["\x01\x01\x02\xff", "X'010102ff'"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '`protected``title`']; - yield ['protected"title', null, '`protected"title`']; - yield ['protected]title', null, '`protected]title`']; + return [ + ['protected`title', null, '`protected``title`'], + ['protected"title', null, '`protected"title`'], + ['protected]title', null, '`protected]title`'], + ]; } /* @@ -381,13 +392,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback(): array { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -395,9 +408,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Mysql/MysqlExporterTest.php b/Tests/Mysql/MysqlExporterTest.php index 01484de0e..f7c4488fe 100644 --- a/Tests/Mysql/MysqlExporterTest.php +++ b/Tests/Mysql/MysqlExporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysql\MysqlDriver; use Joomla\Database\Mysql\MysqlExporter; use Joomla\Database\Mysql\MysqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -43,7 +44,7 @@ protected function setUp(): void ->willReturn('jos_'); $this->db->expects($this->any()) - ->method('getQuery') + ->method('createQuery') ->willReturnCallback(function () { return new MysqlQuery($this->db); }); @@ -120,11 +121,12 @@ function ($name, $as = null) { /** * Data provider for string casting test cases * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield 'without structure or data' => [ + return [ + 'without structure or data' => [ false, false, << XML , - ]; + ], - yield 'with only structure' => [ + 'with only structure' => [ true, false, << XML , - ]; + ], - yield 'with only data' => [ + 'with only data' => [ false, true, << XML , - ]; + ], - yield 'with structure and data' => [ + 'with structure and data' => [ true, true, << XML , + ], ]; } @@ -209,9 +212,8 @@ public function dataCastingToString(): \Generator * @param boolean $withStructure True to export the structure, false to not. * @param boolean $withData True to export the data, false to not. * @param string $expectedXml Expected XML string. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString(bool $withStructure, bool $withData, string $expectedXml) { $exporter = new MysqlExporter(); @@ -244,45 +246,46 @@ public function testCastingToString(bool $withStructure, bool $withData, string /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqlDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqlDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The exporter checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the exporter. - * @param string[]|string|null $from Database tables to export from. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the exporter. + * @param string[]|string|null $from Database tables to export from. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -292,10 +295,11 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $exporter = new MysqlExporter(); if ($db) { - $exporter->setDbo($db); + $exporter->setDbo($this->createMock($db)); } if ($from) { + $exporter->from($from); } diff --git a/Tests/Mysql/MysqlImporterTest.php b/Tests/Mysql/MysqlImporterTest.php index 1b6cdf58e..512d44393 100644 --- a/Tests/Mysql/MysqlImporterTest.php +++ b/Tests/Mysql/MysqlImporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysql\MysqlDriver; use Joomla\Database\Mysql\MysqlImporter; use Joomla\Database\Mysql\MysqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -69,7 +70,7 @@ protected function setUp(): void ->willReturn('jos_'); $this->db->expects($this->any()) - ->method('getQuery') + ->method('createQuery') ->willReturnCallback(function () { return new MysqlQuery($this->db); }); @@ -205,9 +206,9 @@ protected function tearDown(): void /** * Data provider for import test cases * - * @return \Generator + * @return array */ - public function dataImport(): \Generator + public static function dataImport(): array { $idField = ''; $titleField = ''; @@ -216,87 +217,89 @@ public function dataImport(): \Generator $idKey = ''; $titleKey = ''; - yield 'no changes in existing structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), - [], - [], - ]; + return [ + 'no changes in existing structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), + [], + [], + ], - yield 'inserts row into database' => [ - true, - true, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), - [], - [ - 'jos_dbtest' => [ - (object) [ - 'id' => '1', - 'title' => 'Testing', + 'inserts row into database' => [ + true, + true, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), + [], + [ + 'jos_dbtest' => [ + (object) [ + 'id' => '1', + 'title' => 'Testing', + ], ], ], ], - ]; - yield 'adds alias column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + 'adds alias column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + ], + [], ], - [], - ]; - yield 'adds key for the title column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), - [ - 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + 'adds key for the title column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), + [ + 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + ], + [], ], - [], - ]; - yield 'removes the title column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $idKey . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + 'removes the title column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $idKey . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + ], + [], ], - [], - ]; - yield 'removes the primary key based on the id column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + 'removes the primary key based on the id column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + ], + [], ], - [], - ]; - yield 'adds a new database table' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), - [ - "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + 'adds a new database table' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), + [ + "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + ], + [], ], - [], - ]; - yield 'changes the field type of the id field' => [ - true, - false, - new \SimpleXMLElement('' . $titleField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + 'changes the field type of the id field' => [ + true, + false, + new \SimpleXMLElement('' . $titleField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + ], + [], ], - [], ]; } @@ -308,9 +311,8 @@ public function dataImport(): \Generator * @param \SimpleXMLElement $from XML document to import. * @param string[] $expectedQueries The expected database queries to perform. * @param string[] $expectedInsertObjects The expected objects to be given to the database's insertObject method. - * - * @dataProvider dataImport */ + #[DataProvider('dataImport')] public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLElement $from, array $expectedQueries, array $expectedInsertObjects) { $importer = new MysqlImporter(); @@ -332,45 +334,46 @@ public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLEle /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqlDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqlDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The importer checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the importer. - * @param string[]|string|null $from Database structure to import. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the importer. + * @param string[]|string|null $from Database structure to import. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -380,7 +383,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $importer = new MysqlImporter(); if ($db) { - $importer->setDbo($db); + $importer->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Mysql/MysqlPreparedStatementTest.php b/Tests/Mysql/MysqlPreparedStatementTest.php index 6e177f905..f450db223 100644 --- a/Tests/Mysql/MysqlPreparedStatementTest.php +++ b/Tests/Mysql/MysqlPreparedStatementTest.php @@ -72,7 +72,7 @@ protected function tearDown(): void public function testPreparedStatementWithDuplicateKey() { $dummyValue = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ @@ -93,7 +93,7 @@ public function testPreparedStatementWithSingleKey() { $dummyValue = 'test'; $dummyValue2 = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ diff --git a/Tests/Mysql/MysqlQueryTest.php b/Tests/Mysql/MysqlQueryTest.php index f8e6e4d0f..a9d96c621 100644 --- a/Tests/Mysql/MysqlQueryTest.php +++ b/Tests/Mysql/MysqlQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Mysql\MysqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -48,12 +49,14 @@ protected function setUp(): void /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"], + ]; } /** @@ -62,9 +65,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) diff --git a/Tests/Mysqli/MysqliDriverTest.php b/Tests/Mysqli/MysqliDriverTest.php index e23422398..59d5d33da 100644 --- a/Tests/Mysqli/MysqliDriverTest.php +++ b/Tests/Mysqli/MysqliDriverTest.php @@ -15,6 +15,7 @@ use Joomla\Database\Mysqli\MysqliQuery; use Joomla\Database\ParameterType; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Mysqli\MysqliDriver @@ -95,22 +96,24 @@ protected function tearDown(): void /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\\\'%_abc123']; - yield ["'%_abc123", true, '\\\'\\%\_abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\\\'%_abc123'], + ["'%_abc123", true, '\\\'\\%\_abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { // For unknown reasons, the connection gets lost on Travis. re-establish, if that happens if (static::$connection === null) { @@ -120,76 +123,78 @@ public function dataGetTableColumns(): \Generator $isMySQL8 = !static::$connection->isMariaDb() && version_compare(static::$connection->getVersion(), '8.0', '>='); $useDisplayWidth = static::$connection->isMariaDb() || version_compare(static::$connection->getVersion(), '8.0.17', '<'); - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'int unsigned', - 'title' => 'varchar', - 'start_date' => 'datetime', - 'description' => 'text', - 'data' => 'blob', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'int unsigned', + 'title' => 'varchar', + 'start_date' => 'datetime', + 'description' => 'text', + 'data' => 'blob', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', - 'Collation' => $isMySQL8 ? null : '', - 'Null' => 'NO', - 'Key' => 'PRI', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => 'auto_increment', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'varchar(50)', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'datetime', - 'Collation' => '', - 'Null' => 'NO', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'text', - 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', - 'Null' => 'NO', - 'Key' => '', - 'Default' => $isMySQL8 ? null : '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'blob', - 'Collation' => '', - 'Null' => 'YES', - 'Key' => '', - 'Default' => '', - 'Extra' => '', - 'Privileges' => 'select,insert,update,references', - 'Comment' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => $useDisplayWidth ? 'int(10) unsigned' : 'int unsigned', + 'Collation' => $isMySQL8 ? null : '', + 'Null' => 'NO', + 'Key' => 'PRI', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => 'auto_increment', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'varchar(50)', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'datetime', + 'Collation' => '', + 'Null' => 'NO', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'text', + 'Collation' => $isMySQL8 ? 'utf8mb3_general_ci' : 'utf8_general_ci', + 'Null' => 'NO', + 'Key' => '', + 'Default' => $isMySQL8 ? null : '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'blob', + 'Collation' => '', + 'Null' => 'YES', + 'Key' => '', + 'Default' => '', + 'Extra' => '', + 'Privileges' => 'select,insert,update,references', + 'Comment' => '', + ], ], ], ]; @@ -198,37 +203,43 @@ public function dataGetTableColumns(): \Generator /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "X'" . bin2hex('DATA') . "'"]; - yield ["\x00\x01\x02\xff", "X'000102ff'"]; - yield ["\x01\x01\x02\xff", "X'010102ff'"]; + return [ + ['DATA', "X'" . bin2hex('DATA') . "'"], + ["\x00\x01\x02\xff", "X'000102ff'"], + ["\x01\x01\x02\xff", "X'010102ff'"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '`protected``title`']; - yield ['protected"title', null, '`protected"title`']; - yield ['protected]title', null, '`protected]title`']; + return [ + ['protected`title', null, '`protected``title`'], + ['protected"title', null, '`protected"title`'], + ['protected]title', null, '`protected]title`'], + ]; } /* @@ -389,13 +400,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback(): array { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -403,9 +416,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Mysqli/MysqliExporterTest.php b/Tests/Mysqli/MysqliExporterTest.php index 4e96342a3..9059f3fd5 100644 --- a/Tests/Mysqli/MysqliExporterTest.php +++ b/Tests/Mysqli/MysqliExporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysqli\MysqliDriver; use Joomla\Database\Mysqli\MysqliExporter; use Joomla\Database\Mysqli\MysqliQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -43,7 +44,7 @@ protected function setUp(): void ->willReturn('jos_'); $this->db->expects($this->any()) - ->method('getQuery') + ->method('createQuery') ->willReturnCallback(function () { return new MysqliQuery($this->db); }); @@ -120,11 +121,12 @@ function ($name, $as = null) { /** * Data provider for string casting test cases * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield 'without structure or data' => [ + return [ + 'without structure or data' => [ false, false, << XML , - ]; + ], - yield 'with only structure' => [ + 'with only structure' => [ true, false, << XML , - ]; + ], - yield 'with only data' => [ + 'with only data' => [ false, true, << XML , - ]; + ], - yield 'with structure and data' => [ + 'with structure and data' => [ true, true, << XML , + ], ]; } @@ -209,9 +212,8 @@ public function dataCastingToString(): \Generator * @param boolean $withStructure True to export the structure, false to not. * @param boolean $withData True to export the data, false to not. * @param string $expectedXml Expected XML string. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString(bool $withStructure, bool $withData, string $expectedXml) { $exporter = new MysqliExporter(); @@ -244,45 +246,46 @@ public function testCastingToString(bool $withStructure, bool $withData, string /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqliDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqliDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqliDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqliDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The exporter checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the exporter. - * @param string[]|string|null $from Database tables to export from. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the exporter. + * @param string[]|string|null $from Database tables to export from. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -292,7 +295,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $exporter = new MysqliExporter(); if ($db) { - $exporter->setDbo($db); + $exporter->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Mysqli/MysqliImporterTest.php b/Tests/Mysqli/MysqliImporterTest.php index a17638821..b60f457dc 100644 --- a/Tests/Mysqli/MysqliImporterTest.php +++ b/Tests/Mysqli/MysqliImporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Mysqli\MysqliDriver; use Joomla\Database\Mysqli\MysqliImporter; use Joomla\Database\Mysqli\MysqliQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -69,7 +70,7 @@ protected function setUp(): void ->willReturn('jos_'); $this->db->expects($this->any()) - ->method('getQuery') + ->method('createQuery') ->willReturnCallback(function () { return new MysqliQuery($this->db); }); @@ -205,9 +206,9 @@ protected function tearDown(): void /** * Data provider for import test cases * - * @return \Generator + * @return array */ - public function dataImport(): \Generator + public static function dataImport(): array { $idField = ''; $titleField = ''; @@ -216,87 +217,89 @@ public function dataImport(): \Generator $idKey = ''; $titleKey = ''; - yield 'no changes in existing structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), - [], - [], - ]; + return [ + 'no changes in existing structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ''), + [], + [], + ], - yield 'inserts row into database' => [ - true, - true, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), - [], - [ - 'jos_dbtest' => [ - (object) [ - 'id' => '1', - 'title' => 'Testing', + 'inserts row into database' => [ + true, + true, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . ' 1Testing'), + [], + [ + 'jos_dbtest' => [ + (object) [ + 'id' => '1', + 'title' => 'Testing', + ], ], ], ], - ]; - yield 'adds alias column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + 'adds alias column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $aliasField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` ADD COLUMN `alias` varchar(255) NOT NULL DEFAULT ''", + ], + [], ], - [], - ]; - yield 'adds key for the title column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), - [ - 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + 'adds key for the title column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . $titleKey . ''), + [ + 'ALTER TABLE `jos_dbtest` ADD UNIQUE KEY `idx_title` (`title`)', + ], + [], ], - [], - ]; - yield 'removes the title column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $idKey . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + 'removes the title column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $idKey . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP COLUMN `title`', + ], + [], ], - [], - ]; - yield 'removes the primary key based on the id column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . ''), - [ - 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + 'removes the primary key based on the id column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . ''), + [ + 'ALTER TABLE `jos_dbtest` DROP PRIMARY KEY', + ], + [], ], - [], - ]; - yield 'adds a new database table' => [ - true, - false, - new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), - [ - "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + 'adds a new database table' => [ + true, + false, + new \SimpleXMLElement('' . $idField . $titleField . $idKey . '' . $idField . $titleField . $idKey . ''), + [ + "CREATE TABLE `#__newtest` (`id` int(11) unsigned NOT NULL DEFAULT '' AUTO_INCREMENT, `title` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`))", + ], + [], ], - [], - ]; - yield 'changes the field type of the id field' => [ - true, - false, - new \SimpleXMLElement('' . $titleField . $idKey . ''), - [ - "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + 'changes the field type of the id field' => [ + true, + false, + new \SimpleXMLElement('' . $titleField . $idKey . ''), + [ + "ALTER TABLE `jos_dbtest` CHANGE COLUMN `id` `id` bigint() unsigned NOT NULL DEFAULT '' AUTO_INCREMENT", + ], + [], ], - [], ]; } @@ -308,9 +311,8 @@ public function dataImport(): \Generator * @param \SimpleXMLElement $from XML document to import. * @param string[] $expectedQueries The expected database queries to perform. * @param string[] $expectedInsertObjects The expected objects to be given to the database's insertObject method. - * - * @dataProvider dataImport */ + #[DataProvider('dataImport')] public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLElement $from, array $expectedQueries, array $expectedInsertObjects) { $importer = new MysqliImporter(); @@ -332,45 +334,46 @@ public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLEle /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(MysqliDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + MysqliDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(MysqliDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + MysqliDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The importer checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the importer. - * @param string[]|string|null $from Database structure to import. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the importer. + * @param string[]|string|null $from Database structure to import. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -380,7 +383,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $importer = new MysqliImporter(); if ($db) { - $importer->setDbo($db); + $importer->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Mysqli/MysqliQueryTest.php b/Tests/Mysqli/MysqliQueryTest.php index d14e795c2..6b5893fe2 100644 --- a/Tests/Mysqli/MysqliQueryTest.php +++ b/Tests/Mysqli/MysqliQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Mysqli\MysqliQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -48,12 +49,14 @@ protected function setUp(): void /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'CONCAT(foo,bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "CONCAT_WS(' and ', foo, bar)"], + ]; } /** @@ -62,9 +65,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) diff --git a/Tests/Pgsql/PgsqlDriverTest.php b/Tests/Pgsql/PgsqlDriverTest.php index 93748813a..ee297a713 100644 --- a/Tests/Pgsql/PgsqlDriverTest.php +++ b/Tests/Pgsql/PgsqlDriverTest.php @@ -12,6 +12,7 @@ use Joomla\Database\Pgsql\PgsqlImporter; use Joomla\Database\Pgsql\PgsqlQuery; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Pgsql\PgsqlDriver @@ -54,75 +55,77 @@ protected function tearDown(): void /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'integer', - 'title' => 'character varying', - 'start_date' => 'timestamp without time zone', - 'description' => 'text', - 'data' => 'bytea', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'integer', + 'title' => 'character varying', + 'start_date' => 'timestamp without time zone', + 'description' => 'text', + 'data' => 'bytea', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'column_name' => 'id', - 'Field' => 'id', - 'type' => 'integer', - 'Type' => 'integer', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => 'nextval(\'dbtest_id_seq\'::regclass)', - 'comments' => '', - ], - 'title' => (object) [ - 'column_name' => 'title', - 'Field' => 'title', - 'type' => 'character varying(50)', - 'Type' => 'character varying(50)', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => null, - 'comments' => '', - ], - 'start_date' => (object) [ - 'column_name' => 'start_date', - 'Field' => 'start_date', - 'type' => 'timestamp without time zone', - 'Type' => 'timestamp without time zone', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => null, - 'comments' => '', - ], - 'description' => (object) [ - 'column_name' => 'description', - 'Field' => 'description', - 'type' => 'text', - 'Type' => 'text', - 'null' => 'NO', - 'Null' => 'NO', - 'Default' => null, - 'comments' => '', - ], - 'data' => (object) [ - 'column_name' => 'data', - 'Field' => 'data', - 'type' => 'bytea', - 'Type' => 'bytea', - 'null' => 'YES', - 'Null' => 'YES', - 'Default' => null, - 'comments' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'column_name' => 'id', + 'Field' => 'id', + 'type' => 'integer', + 'Type' => 'integer', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => 'nextval(\'dbtest_id_seq\'::regclass)', + 'comments' => '', + ], + 'title' => (object) [ + 'column_name' => 'title', + 'Field' => 'title', + 'type' => 'character varying(50)', + 'Type' => 'character varying(50)', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => null, + 'comments' => '', + ], + 'start_date' => (object) [ + 'column_name' => 'start_date', + 'Field' => 'start_date', + 'type' => 'timestamp without time zone', + 'Type' => 'timestamp without time zone', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => null, + 'comments' => '', + ], + 'description' => (object) [ + 'column_name' => 'description', + 'Field' => 'description', + 'type' => 'text', + 'Type' => 'text', + 'null' => 'NO', + 'Null' => 'NO', + 'Default' => null, + 'comments' => '', + ], + 'data' => (object) [ + 'column_name' => 'data', + 'Field' => 'data', + 'type' => 'bytea', + 'Type' => 'bytea', + 'null' => 'YES', + 'Null' => 'YES', + 'Default' => null, + 'comments' => '', + ], ], ], ]; @@ -131,50 +134,58 @@ public function dataGetTableColumns(): \Generator /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "decode('44415441', 'hex')"]; - yield ["\x00\x01\x02\xff", "decode('000102ff', 'hex')"]; - yield ["\x01\x01\x02\xff", "decode('010102ff', 'hex')"]; + return [ + ['DATA', "decode('44415441', 'hex')"], + ["\x00\x01\x02\xff", "decode('000102ff', 'hex')"], + ["\x01\x01\x02\xff", "decode('010102ff', 'hex')"], + ]; } /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database does not exist before query' => ['#__foo', false]; + return [ + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\'\'%_abc123']; - yield ["'%_abc123", true, '\'\'%_abc123']; - yield ["\'%_abc123", false, '\\\\\'\'%_abc123']; - yield ["\'%_abc123", true, '\\\\\'\'%_abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\'\'%_abc123'], + ["'%_abc123", true, '\'\'%_abc123'], + ["\'%_abc123", false, '\\\\\'\'%_abc123'], + ["\'%_abc123", true, '\\\\\'\'%_abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '"protected`title"']; - yield ['protected"title', null, '"protected""title"']; - yield ['protected]title', null, '"protected]title"']; + return [ + ['protected`title', null, '"protected`title"'], + ['protected"title', null, '"protected""title"'], + ['protected]title', null, '"protected]title"'], + ]; } /* @@ -452,13 +463,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback(): array { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -466,9 +479,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Pgsql/PgsqlExporterTest.php b/Tests/Pgsql/PgsqlExporterTest.php index 7d92d52c4..468b72691 100644 --- a/Tests/Pgsql/PgsqlExporterTest.php +++ b/Tests/Pgsql/PgsqlExporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Pgsql\PgsqlDriver; use Joomla\Database\Pgsql\PgsqlExporter; use Joomla\Database\Pgsql\PgsqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -43,7 +44,7 @@ protected function setUp(): void ->willReturn('jos_'); $this->db->expects($this->any()) - ->method('getQuery') + ->method('createQuery') ->willReturnCallback(function () { return new PgsqlQuery($this->db); }); @@ -142,11 +143,12 @@ function ($name, $as = null) { /** * Data provider for string casting test cases * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield 'without structure or data' => [ + return [ + 'without structure or data' => [ false, false, << XML , - ]; + ], - yield 'with only structure' => [ + 'with only structure' => [ true, false, << XML , - ]; + ], - yield 'with only data' => [ + 'with only data' => [ false, true, << XML , - ]; + ], - yield 'with structure and data' => [ + 'with structure and data' => [ true, true, << XML , + ], ]; } @@ -237,9 +240,8 @@ public function dataCastingToString(): \Generator * @param boolean $withStructure True to export the structure, false to not. * @param boolean $withData True to export the data, false to not. * @param string $expectedXml Expected XML string. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString(bool $withStructure, bool $withData, string $expectedXml) { $exporter = new PgsqlExporter(); @@ -272,45 +274,46 @@ public function testCastingToString(bool $withStructure, bool $withData, string /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(PgsqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + PgsqlDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - '#__dbtest', - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + '#__dbtest', + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(PgsqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + PgsqlDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The exporter checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the exporter. - * @param string[]|string|null $from Database tables to export from. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the exporter. + * @param string[]|string|null $from Database tables to export from. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -320,7 +323,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $exporter = new PgsqlExporter(); if ($db) { - $exporter->setDbo($db); + $exporter->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Pgsql/PgsqlImporterTest.php b/Tests/Pgsql/PgsqlImporterTest.php index d33a63e1c..b25ba792e 100644 --- a/Tests/Pgsql/PgsqlImporterTest.php +++ b/Tests/Pgsql/PgsqlImporterTest.php @@ -10,6 +10,7 @@ use Joomla\Database\Pgsql\PgsqlDriver; use Joomla\Database\Pgsql\PgsqlImporter; use Joomla\Database\Pgsql\PgsqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -69,7 +70,7 @@ protected function setUp(): void ->willReturn('jos_'); $this->db->expects($this->any()) - ->method('getQuery') + ->method('createQuery') ->willReturnCallback(function () { return new PgsqlQuery($this->db); }); @@ -211,9 +212,9 @@ protected function tearDown(): void /** * Data provider for import test cases * - * @return \Generator + * @return array */ - public function dataImport(): \Generator + public static function dataImport(): array { $idSequence = ''; @@ -224,93 +225,95 @@ public function dataImport(): \Generator $idKey = ''; $titleKey = ''; - yield 'no changes in existing structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ''), - [], - [], - ]; + return [ + 'no changes in existing structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ''), + [], + [], + ], - yield 'inserts row into database' => [ - true, - true, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ' 1Testing'), - [], - [ - 'jos_dbtest' => [ - (object) [ - 'id' => '1', - 'title' => 'Testing', + 'inserts row into database' => [ + true, + true, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . ' 1Testing'), + [], + [ + 'jos_dbtest' => [ + (object) [ + 'id' => '1', + 'title' => 'Testing', + ], ], ], ], - ]; - yield 'adds alias column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $aliasField . $idKey . ''), - [ - "ALTER TABLE \"jos_dbtest\" ADD COLUMN \"alias\" character varying(255) NOT NULL DEFAULT 'test'", + 'adds alias column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $aliasField . $idKey . ''), + [ + "ALTER TABLE \"jos_dbtest\" ADD COLUMN \"alias\" character varying(255) NOT NULL DEFAULT 'test'", + ], + [], ], - [], - ]; - yield 'adds key for the title column to the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . $titleKey . ''), - [ - 'CREATE INDEX jos_dbtest_idx_name ON jos_dbtest USING btree (name)', + 'adds key for the title column to the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . $titleKey . ''), + [ + 'CREATE INDEX jos_dbtest_idx_name ON jos_dbtest USING btree (name)', + ], + [], ], - [], - ]; - yield 'removes the title column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $idKey . ''), - [ - 'ALTER TABLE "jos_dbtest" DROP COLUMN "title"', + 'removes the title column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $idKey . ''), + [ + 'ALTER TABLE "jos_dbtest" DROP COLUMN "title"', + ], + [], ], - [], - ]; - yield 'removes the primary key based on the id column from the structure' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . ''), - [ - 'ALTER TABLE ONLY "jos_dbtest" DROP CONSTRAINT "jos_dbtest_pkey"', + 'removes the primary key based on the id column from the structure' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . ''), + [ + 'ALTER TABLE ONLY "jos_dbtest" DROP CONSTRAINT "jos_dbtest_pkey"', + ], + [], ], - [], - ]; - yield 'adds a new database table' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . '' . $titleField . ''), - [ - 'CREATE TABLE "jos_newtest" ("id" SERIAL, "title" character varying(50) NOT NULL DEFAULT \'NULL\')', - 'CREATE SEQUENCE IF NOT EXISTS jos_newtest_id_seq INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 NO CYCLE OWNED BY "public.jos_newtest.id"', - "SELECT setval('jos_newtest_id_seq', , FALSE)", - 'ALTER TABLE jos_newtest ADD PRIMARY KEY (id)', + 'adds a new database table' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . $idField . $titleField . $idKey . '' . $titleField . ''), + [ + 'CREATE TABLE "jos_newtest" ("id" SERIAL, "title" character varying(50) NOT NULL DEFAULT \'NULL\')', + 'CREATE SEQUENCE IF NOT EXISTS jos_newtest_id_seq INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 NO CYCLE OWNED BY "public.jos_newtest.id"', + "SELECT setval('jos_newtest_id_seq', , FALSE)", + 'ALTER TABLE jos_newtest ADD PRIMARY KEY (id)', + ], + [], ], - [], - ]; - yield 'changes the field type of the id field' => [ - true, - false, - new \SimpleXMLElement('' . $idSequence . '' . $titleField . $idKey . ''), - [ - 'ALTER TABLE "jos_dbtest" ALTER COLUMN "id" TYPE bigint, + 'changes the field type of the id field' => [ + true, + false, + new \SimpleXMLElement('' . $idSequence . '' . $titleField . $idKey . ''), + [ + 'ALTER TABLE "jos_dbtest" ALTER COLUMN "id" TYPE bigint, ALTER COLUMN "id" SET NOT NULL, ALTER COLUMN "id" SET DEFAULT \'nextval(\'jos_dbtest_id_seq\'::regclass)\'; ALTER SEQUENCE "jos_dbtest_id_seq" OWNED BY "jos_dbtest.id"', + ], + [], ], - [], ]; } @@ -322,9 +325,8 @@ public function dataImport(): \Generator * @param \SimpleXMLElement $from XML document to import. * @param string[] $expectedQueries The expected database queries to perform. * @param string[] $expectedInsertObjects The expected objects to be given to the database's insertObject method. - * - * @dataProvider dataImport */ + #[DataProvider('dataImport')] public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLElement $from, array $expectedQueries, array $expectedInsertObjects) { $importer = new PgsqlImporter(); @@ -346,45 +348,46 @@ public function testImport(bool $mergeStructure, bool $importData, \SimpleXMLEle /** * Data provider for check test cases * - * @return \Generator + * @return array */ - public function dataCheck(): \Generator + public static function dataCheck(): array { - yield 'passes checks' => [ - $this->createMock(PgsqlDriver::class), - '#__dbtest', - null, - ]; + return [ + 'passes checks' => [ + PgsqlDriver::class, + '#__dbtest', + null, + ], - yield 'fails checks with incorrect database driver subclass' => [ - $this->createMock(DatabaseInterface::class), - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with incorrect database driver subclass' => [ + DatabaseInterface::class, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no database driver' => [ - null, - new \SimpleXMLElement(''), - 'Database connection wrong type.', - ]; + 'fails checks with no database driver' => [ + null, + new \SimpleXMLElement(''), + 'Database connection wrong type.', + ], - yield 'fails checks with no tables' => [ - $this->createMock(PgsqlDriver::class), - null, - 'ERROR: No Tables Specified', + 'fails checks with no tables' => [ + PgsqlDriver::class, + null, + 'ERROR: No Tables Specified', + ], ]; } /** * @testdox The importer checks for errors * - * @param DatabaseInterface|null $db Database driver to set in the importer. - * @param string[]|string|null $from Database structure to import. - * @param string|null $exceptionMessage If an Exception should be thrown, the expected message - * - * @dataProvider dataCheck + * @param string|null $db Database driver to set in the importer. + * @param string[]|string|null $from Database structure to import. + * @param string|null $exceptionMessage If an Exception should be thrown, the expected message */ - public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessage) + #[DataProvider('dataCheck')] + public function testCheck(?string $db, $from, ?string $exceptionMessage) { if ($exceptionMessage) { $this->expectException(\RuntimeException::class); @@ -394,7 +397,7 @@ public function testCheck(?DatabaseInterface $db, $from, ?string $exceptionMessa $importer = new PgsqlImporter(); if ($db) { - $importer->setDbo($db); + $importer->setDbo($this->createMock($db)); } if ($from) { diff --git a/Tests/Pgsql/PgsqlPreparedStatementTest.php b/Tests/Pgsql/PgsqlPreparedStatementTest.php index 17dd43e92..41b4fe18d 100644 --- a/Tests/Pgsql/PgsqlPreparedStatementTest.php +++ b/Tests/Pgsql/PgsqlPreparedStatementTest.php @@ -75,7 +75,7 @@ protected function tearDown(): void public function testPreparedStatementWithDuplicateKey() { $dummyValue = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ @@ -96,7 +96,7 @@ public function testPreparedStatementWithSingleKey() { $dummyValue = 'test'; $dummyValue2 = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ diff --git a/Tests/Pgsql/PgsqlQueryTest.php b/Tests/Pgsql/PgsqlQueryTest.php index 7db376f26..b04f63a6b 100644 --- a/Tests/Pgsql/PgsqlQueryTest.php +++ b/Tests/Pgsql/PgsqlQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Pgsql\PgsqlQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -45,14 +46,6 @@ protected function setUp(): void $this->query = new PgsqlQuery($this->db); } - /** - * @testdox A string is cast as a character string for the driver - */ - public function testCastAsChar() - { - $this->assertSame('foo::text', $this->query->castAsChar('foo')); - } - /** * @testdox A string is cast as a character string for the driver */ @@ -86,12 +79,14 @@ public function testCastAsWithIntegerType() /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'foo || bar']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'foo || bar'], + 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"], + ]; } /** @@ -100,9 +95,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) @@ -225,12 +219,14 @@ public function testSecond() /** * Data provider for dateAdd test cases * - * @return \Generator + * @return array */ - public function dataDateAdd(): \Generator + public static function dataDateAdd(): array { - yield 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "timestamp '2019-10-13' + interval '1 DAY'"]; - yield 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "timestamp '2019-10-13' - interval '1 DAY'"]; + return [ + 'date with positive interval' => ["'2019-10-13'", '1', 'DAY', "timestamp '2019-10-13' + interval '1 DAY'"], + 'date with negative interval' => ["'2019-10-13'", '-1', 'DAY', "timestamp '2019-10-13' - interval '1 DAY'"], + ]; } /** @@ -240,9 +236,8 @@ public function dataDateAdd(): \Generator * @param string $interval The string representation of the appropriate number of units * @param string $datePart The part of the date to perform the addition on * @param string $expected The expected query string. - * - * @dataProvider dataDateAdd */ + #[DataProvider('dataDateAdd')] public function testDateAdd(string $date, string $interval, string $datePart, string $expected) { $this->assertSame( diff --git a/Tests/Query/QueryElementTest.php b/Tests/Query/QueryElementTest.php index 0b37877d7..7fa6eccfb 100644 --- a/Tests/Query/QueryElementTest.php +++ b/Tests/Query/QueryElementTest.php @@ -7,6 +7,7 @@ namespace Joomla\Database\Tests\Query; use Joomla\Database\Query\QueryElement; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -24,33 +25,35 @@ class QueryElementTest extends TestCase * glue => glue * - array $expected values in same array format * - * @return \Generator + * @return array */ - public function dataInstantiation(): \Generator + public static function dataInstantiation(): array { - yield 'array-element' => [ - [ - 'name' => 'FROM', - 'elements' => ['field1', 'field2'], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['field1', 'field2'], - 'glue' => ',', + return [ + 'array-element' => [ + [ + 'name' => 'FROM', + 'elements' => ['field1', 'field2'], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['field1', 'field2'], + 'glue' => ',', + ], ], - ]; - yield 'non-array-element' => [ - [ - 'name' => 'TABLE', - 'elements' => 'my_table_name', - 'glue' => ',', - ], - [ - 'name' => 'TABLE', - 'elements' => ['my_table_name'], - 'glue' => ',', + 'non-array-element' => [ + [ + 'name' => 'TABLE', + 'elements' => 'my_table_name', + 'glue' => ',', + ], + [ + 'name' => 'TABLE', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], ], ]; } @@ -60,9 +63,8 @@ public function dataInstantiation(): \Generator * * @param array $element values for base element * @param array $expected values for expected fields - * - * @dataProvider dataInstantiation */ + #[DataProvider('dataInstantiation')] public function testInstantiation(array $element, array $expected) { $baseElement = new QueryElement($element['name'], $element['elements'], $element['glue']); @@ -92,36 +94,38 @@ public function testInstantiation(array $element, array $expected) * - string $glue the element glue * - string $expected expected result * - * @return \Generator + * @return array */ - public function dataCastingToString(): \Generator + public static function dataCastingToString(): array { - yield [ - 'FROM', - 'table1', - ',', - PHP_EOL . 'FROM table1', - ]; + return [ + [ + 'FROM', + 'table1', + ',', + PHP_EOL . 'FROM table1', + ], - yield [ - 'SELECT', - ['column1', 'column2'], - ',', - PHP_EOL . 'SELECT column1,column2', - ]; + [ + 'SELECT', + ['column1', 'column2'], + ',', + PHP_EOL . 'SELECT column1,column2', + ], - yield [ - '()', - ['column1', 'column2'], - ',', - PHP_EOL . '(column1,column2)', - ]; + [ + '()', + ['column1', 'column2'], + ',', + PHP_EOL . '(column1,column2)', + ], - yield [ - 'CONCAT()', - ['column1', 'column2'], - ',', - PHP_EOL . 'CONCAT(column1,column2)', + [ + 'CONCAT()', + ['column1', 'column2'], + ',', + PHP_EOL . 'CONCAT(column1,column2)', + ], ]; } @@ -132,9 +136,8 @@ public function dataCastingToString(): \Generator * @param mixed $elements String or array. * @param string $glue The glue for elements. * @param string $expected The expected value. - * - * @dataProvider dataCastingToString */ + #[DataProvider('dataCastingToString')] public function testCastingToString($name, $elements, $glue, $expected) { $this->assertThat( @@ -155,46 +158,48 @@ public function testCastingToString($name, $elements, $glue, $expected) * - array $expected array of elements that should be the value of the elements attribute after the merge * - string $string value of __toString() for element after append * - * @return \Generator + * @return array */ - public function dataAppend(): \Generator + public static function dataAppend(): array { - yield 'array-element' => [ - [ - 'name' => 'SELECT', - 'elements' => [], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', + return [ + 'array-element' => [ + [ + 'name' => 'SELECT', + 'elements' => [], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', ], - PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', - ]; - yield 'non-array-element' => [ - [ - 'name' => 'SELECT', - 'elements' => [], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', - ], - [ - 'name' => 'FROM', - 'elements' => ['my_table_name'], - 'glue' => ',', + 'non-array-element' => [ + [ + 'name' => 'SELECT', + 'elements' => [], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + [ + 'name' => 'FROM', + 'elements' => ['my_table_name'], + 'glue' => ',', + ], + PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', ], - PHP_EOL . 'SELECT ' . PHP_EOL . 'FROM my_table_name', ]; } @@ -205,9 +210,8 @@ public function dataAppend(): \Generator * @param array $append append element values * @param array $expected expected element values for elements field after append * @param string $string expected value of toString (not used in this test) - * - * @dataProvider dataAppend */ + #[DataProvider('dataAppend')] public function testAppend($element, $append, $expected, $string) { $baseElement = new QueryElement($element['name'], $element['elements'], $element['glue']); diff --git a/Tests/Sqlite/SqliteDriverTest.php b/Tests/Sqlite/SqliteDriverTest.php index 940198c5e..3d1ec2fc7 100644 --- a/Tests/Sqlite/SqliteDriverTest.php +++ b/Tests/Sqlite/SqliteDriverTest.php @@ -13,6 +13,7 @@ use Joomla\Database\Sqlite\SqliteDriver; use Joomla\Database\Sqlite\SqliteQuery; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Sqlite\SqliteDriver @@ -88,73 +89,77 @@ function (string $table): bool { /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, "''%_abc123"]; - yield ["'%_abc123", true, "''%_abc123"]; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, "''%_abc123"], + ["'%_abc123", true, "''%_abc123"], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for fetching table column test cases * - * @return \Generator - */ - public function dataGetTableColumns(): \Generator - { - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'INTEGER', - 'title' => 'TEXT', - 'start_date' => 'TEXT', - 'description' => 'TEXT', - 'data' => 'BLOB', + * @return array + */ + public static function dataGetTableColumns(): array + { + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'INTEGER', + 'title' => 'TEXT', + 'start_date' => 'TEXT', + 'description' => 'TEXT', + 'data' => 'BLOB', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => 'INTEGER', - 'Null' => 'YES', - 'Default' => null, - 'Key' => 'PRI', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'TEXT', - 'Null' => 'NO', - 'Default' => '\'\'', - 'Key' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'TEXT', - 'Null' => 'NO', - 'Default' => '\'\'', - 'Key' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'TEXT', - 'Null' => 'NO', - 'Default' => '\'\'', - 'Key' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'BLOB', - 'Null' => 'YES', - 'Default' => null, - 'Key' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => 'INTEGER', + 'Null' => 'YES', + 'Default' => null, + 'Key' => 'PRI', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'TEXT', + 'Null' => 'NO', + 'Default' => '\'\'', + 'Key' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'TEXT', + 'Null' => 'NO', + 'Default' => '\'\'', + 'Key' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'TEXT', + 'Null' => 'NO', + 'Default' => '\'\'', + 'Key' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'BLOB', + 'Null' => 'YES', + 'Default' => null, + 'Key' => '', + ], ], ], ]; @@ -163,37 +168,43 @@ public function dataGetTableColumns(): \Generator /** * Data provider for table dropping test cases * - * @return \Generator + * @return array */ - public function dataDropTable() + public static function dataDropTable(): array { - yield 'database exists before query' => ['#__dbtest', true]; + return [ + 'database exists before query' => ['#__dbtest', true], - yield 'database does not exist before query' => ['#__foo', false]; + 'database does not exist before query' => ['#__foo', false], + ]; } /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "X'" . bin2hex('DATA') . "'"]; - yield ["\x00\x01\x02\xff", "X'000102ff'"]; - yield ["\x01\x01\x02\xff", "X'010102ff'"]; + return [ + ['DATA', "X'" . bin2hex('DATA') . "'"], + ["\x00\x01\x02\xff", "X'000102ff'"], + ["\x01\x01\x02\xff", "X'010102ff'"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '`protected``title`']; - yield ['protected"title', null, '`protected"title`']; - yield ['protected]title', null, '`protected]title`']; + return [ + ['protected`title', null, '`protected``title`'], + ['protected"title', null, '`protected"title`'], + ['protected]title', null, '`protected]title`'], + ]; } /* @@ -412,13 +423,15 @@ public function testTransactionCommit() /** * Data provider for transaction rollback test cases * - * @return \Generator + * @return array */ - public function dataTransactionRollback() + public static function dataTransactionRollback() { - yield 'rollback without savepoint' => [null, 0]; + return [ + 'rollback without savepoint' => [null, 0], - yield 'rollback with savepoint' => ['transactionSavepoint', 1]; + 'rollback with savepoint' => ['transactionSavepoint', 1], + ]; } /** @@ -426,9 +439,8 @@ public function dataTransactionRollback() * * @param string|null $toSavepoint Savepoint name to rollback transaction to * @param integer $tupleCount Number of tuples found after insertion and rollback - * - * @dataProvider dataTransactionRollback */ + #[DataProvider('dataTransactionRollback')] public function testTransactionRollback(?string $toSavepoint, int $tupleCount) { $this->loadExampleData(); diff --git a/Tests/Sqlite/SqlitePreparedStatementTest.php b/Tests/Sqlite/SqlitePreparedStatementTest.php index e3ffd2a82..3ddb258cf 100644 --- a/Tests/Sqlite/SqlitePreparedStatementTest.php +++ b/Tests/Sqlite/SqlitePreparedStatementTest.php @@ -82,7 +82,7 @@ function (string $table): bool { public function testPreparedStatementWithDuplicateKey() { $dummyValue = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ @@ -103,7 +103,7 @@ public function testPreparedStatementWithSingleKey() { $dummyValue = 'test'; $dummyValue2 = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ diff --git a/Tests/Sqlite/SqliteQueryTest.php b/Tests/Sqlite/SqliteQueryTest.php index fdb910c43..5a444d40c 100644 --- a/Tests/Sqlite/SqliteQueryTest.php +++ b/Tests/Sqlite/SqliteQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Sqlite\SqliteQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -48,12 +49,14 @@ protected function setUp(): void /** * Data provider for character length test cases * - * @return \Generator + * @return array */ - public function dataCharLength(): \Generator + public static function dataCharLength(): array { - yield 'field without comparison' => ['a.title', null, null, 'length(a.title)']; - yield 'field with comparison' => ['a.title', '!=', '0', 'length(a.title) != 0']; + return [ + 'field without comparison' => ['a.title', null, null, 'length(a.title)'], + 'field with comparison' => ['a.title', '!=', '0', 'length(a.title) != 0'], + ]; } /** @@ -63,9 +66,8 @@ public function dataCharLength(): \Generator * @param string|null $operator Comparison operator between charLength integer value and $condition * @param string|null $condition Integer value to compare charLength with. * @param string $expected The expected query string. - * - * @dataProvider dataCharLength */ + #[DataProvider('dataCharLength')] public function testCharLength(string $field, ?string $operator, ?string $condition, string $expected) { $this->assertSame( @@ -77,12 +79,14 @@ public function testCharLength(string $field, ?string $operator, ?string $condit /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, 'foo || bar']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"]; + return [ + 'values without separator' => [['foo', 'bar'], null, 'foo || bar'], + 'values with separator' => [['foo', 'bar'], ' and ', "foo || ' and ' || bar"], + ]; } /** @@ -91,9 +95,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) diff --git a/Tests/Sqlsrv/SqlsrvDriverTest.php b/Tests/Sqlsrv/SqlsrvDriverTest.php index 9f8d96071..19bda8fc7 100644 --- a/Tests/Sqlsrv/SqlsrvDriverTest.php +++ b/Tests/Sqlsrv/SqlsrvDriverTest.php @@ -12,6 +12,7 @@ use Joomla\Database\Sqlsrv\SqlsrvDriver; use Joomla\Database\Sqlsrv\SqlsrvQuery; use Joomla\Database\Tests\AbstractDatabaseDriverTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * Test class for Joomla\Database\Sqlsrv\SqlsrvDriver. @@ -121,68 +122,72 @@ protected function loadExampleData(): void /** * Data provider for escaping test cases * - * @return \Generator + * @return array */ - public function dataEscape(): \Generator + public static function dataEscape(): array { - yield ["'%_abc123", false, '\'\'%_abc123']; - yield ["'%_abc123", true, '\'\'[%][_]abc123']; - yield [3, false, 3]; - yield [3.14, false, '3.14']; + return [ + ["'%_abc123", false, '\'\'%_abc123'], + ["'%_abc123", true, '\'\'[%][_]abc123'], + [3, false, 3], + [3.14, false, '3.14'], + ]; } /** * Data provider for fetching table column test cases * - * @return \Generator + * @return array */ - public function dataGetTableColumns(): \Generator + public static function dataGetTableColumns(): array { - yield 'only column types' => [ - '#__dbtest', - true, - [ - 'id' => 'int', - 'title' => 'nvarchar', - 'start_date' => 'datetime', - 'description' => 'nvarchar', - 'data' => 'nvarchar', + return [ + 'only column types' => [ + '#__dbtest', + true, + [ + 'id' => 'int', + 'title' => 'nvarchar', + 'start_date' => 'datetime', + 'description' => 'nvarchar', + 'data' => 'nvarchar', + ], ], - ]; - yield 'full column information' => [ - '#__dbtest', - false, - [ - 'id' => (object) [ - 'Field' => 'id', - 'Type' => 'int', - 'Null' => 'NO', - 'Default' => '', - ], - 'title' => (object) [ - 'Field' => 'title', - 'Type' => 'nvarchar', - 'Null' => 'NO', - 'Default' => '', - ], - 'start_date' => (object) [ - 'Field' => 'start_date', - 'Type' => 'datetime', - 'Null' => 'NO', - 'Default' => '', - ], - 'description' => (object) [ - 'Field' => 'description', - 'Type' => 'nvarchar', - 'Null' => 'NO', - 'Default' => '', - ], - 'data' => (object) [ - 'Field' => 'data', - 'Type' => 'nvarchar', - 'Null' => 'YES', - 'Default' => '', + 'full column information' => [ + '#__dbtest', + false, + [ + 'id' => (object) [ + 'Field' => 'id', + 'Type' => 'int', + 'Null' => 'NO', + 'Default' => '', + ], + 'title' => (object) [ + 'Field' => 'title', + 'Type' => 'nvarchar', + 'Null' => 'NO', + 'Default' => '', + ], + 'start_date' => (object) [ + 'Field' => 'start_date', + 'Type' => 'datetime', + 'Null' => 'NO', + 'Default' => '', + ], + 'description' => (object) [ + 'Field' => 'description', + 'Type' => 'nvarchar', + 'Null' => 'NO', + 'Default' => '', + ], + 'data' => (object) [ + 'Field' => 'data', + 'Type' => 'nvarchar', + 'Null' => 'YES', + 'Default' => '', + ], ], ], ]; @@ -191,25 +196,29 @@ public function dataGetTableColumns(): \Generator /** * Data provider for binary quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteBinary(): \Generator + public static function dataQuoteBinary(): array { - yield ['DATA', "0x" . bin2hex('DATA')]; - yield ["\x00\x01\x02\xff", "0x000102ff"]; - yield ["\x01\x01\x02\xff", "0x010102ff"]; + return [ + ['DATA', "0x" . bin2hex('DATA')], + ["\x00\x01\x02\xff", "0x000102ff"], + ["\x01\x01\x02\xff", "0x010102ff"], + ]; } /** * Data provider for name quoting test cases * - * @return \Generator + * @return array */ - public function dataQuoteName(): \Generator + public static function dataQuoteName(): array { - yield ['protected`title', null, '[protected`title]']; - yield ['protected"title', null, '[protected"title]']; - yield ['protected]title', null, '[protected]]title]']; + return [ + ['protected`title', null, '[protected`title]'], + ['protected"title', null, '[protected"title]'], + ['protected]title', null, '[protected]]title]'], + ]; } /* @@ -469,9 +478,8 @@ public function testGetTableCreate() * @param string $table The name of the database table. * @param boolean $typeOnly True (default) to only return field types. * @param array $expected Expected result. - * - * @dataProvider dataGetTableColumns */ + #[DataProvider('dataGetTableColumns')] public function testGetTableColumns(string $table, bool $typeOnly, array $expected) { $this->assertEquals( diff --git a/Tests/Sqlsrv/SqlsrvPreparedStatementTest.php b/Tests/Sqlsrv/SqlsrvPreparedStatementTest.php index 8625fdf77..f21e4b1fc 100644 --- a/Tests/Sqlsrv/SqlsrvPreparedStatementTest.php +++ b/Tests/Sqlsrv/SqlsrvPreparedStatementTest.php @@ -133,7 +133,7 @@ public function testPrepareParameterKeyMappingWithSingleKey() public function testPreparedStatementWithDuplicateKey() { $dummyValue = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ @@ -154,7 +154,7 @@ public function testPreparedStatementWithSingleKey() { $dummyValue = 'test'; $dummyValue2 = 'test'; - $query = static::$connection->getQuery(true); + $query = static::$connection->createQuery(); $query->select('*') ->from($query->quoteName('dbtest')) ->where([ diff --git a/Tests/Sqlsrv/SqlsrvQueryTest.php b/Tests/Sqlsrv/SqlsrvQueryTest.php index 39b0d034d..cddd42838 100644 --- a/Tests/Sqlsrv/SqlsrvQueryTest.php +++ b/Tests/Sqlsrv/SqlsrvQueryTest.php @@ -8,6 +8,7 @@ use Joomla\Database\DatabaseInterface; use Joomla\Database\Sqlsrv\SqlsrvQuery; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -45,14 +46,6 @@ protected function setUp(): void $this->query = new SqlsrvQuery($this->db); } - /** - * @testdox A string is cast as a character string for the driver - */ - public function testCastAsChar() - { - $this->assertSame('CAST(foo as NVARCHAR(10))', $this->query->castAsChar('foo')); - } - /** * @testdox A string is cast as a character string for the driver */ @@ -86,12 +79,14 @@ public function testCastAsWithIntegerType() /** * Data provider for character length test cases * - * @return \Generator + * @return array */ - public function dataCharLength(): \Generator + public static function dataCharLength(): array { - yield 'field without comparison' => ['a.title', null, null, 'DATALENGTH(a.title)']; - yield 'field with comparison' => ['a.title', '!=', '0', 'DATALENGTH(a.title) != 0']; + return [ + 'field without comparison' => ['a.title', null, null, 'DATALENGTH(a.title)'], + 'field with comparison' => ['a.title', '!=', '0', 'DATALENGTH(a.title) != 0'], + ]; } /** @@ -101,9 +96,8 @@ public function dataCharLength(): \Generator * @param string|null $operator Comparison operator between charLength integer value and $condition * @param string|null $condition Integer value to compare charLength with. * @param string $expected The expected query string. - * - * @dataProvider dataCharLength */ + #[DataProvider('dataCharLength')] public function testCharLength(string $field, ?string $operator, ?string $condition, string $expected) { $this->assertSame( @@ -115,12 +109,14 @@ public function testCharLength(string $field, ?string $operator, ?string $condit /** * Data provider for concatenate test cases * - * @return \Generator + * @return array */ - public function dataConcatenate(): \Generator + public static function dataConcatenate(): array { - yield 'values without separator' => [['foo', 'bar'], null, '(foo+bar)']; - yield 'values with separator' => [['foo', 'bar'], ' and ', "(foo+' and '+bar)"]; + return [ + 'values without separator' => [['foo', 'bar'], null, '(foo+bar)'], + 'values with separator' => [['foo', 'bar'], ' and ', "(foo+' and '+bar)"], + ]; } /** @@ -129,9 +125,8 @@ public function dataConcatenate(): \Generator * @param string[] $values An array of values to concatenate. * @param string|null $separator As separator to place between each value. * @param string $expected The expected query string. - * - * @dataProvider dataConcatenate */ + #[DataProvider('dataConcatenate')] public function testConcatenate(array $values, ?string $separator, string $expected) { $this->db->expects($this->any()) diff --git a/Tests/Stubs/TestDatabaseExporter.php b/Tests/Stubs/TestDatabaseExporter.php new file mode 100644 index 000000000..c121d4d0f --- /dev/null +++ b/Tests/Stubs/TestDatabaseExporter.php @@ -0,0 +1,28 @@ +castAs('CHAR', $value)` instead. diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 78c2cd66a..362465074 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,593 +1,577 @@ parameters: ignoreErrors: - - message: "#^Variable \\$filenames might not be defined\\.$#" + message: '#^Trait Joomla\\Database\\DatabaseAwareTrait is used zero times and is not analysed\.$#' + identifier: trait.unused count: 1 - path: src/Command/ExportCommand.php + path: src/DatabaseAwareTrait.php - - message: "#^Variable \\$zipFilesArray might not be defined\\.$#" + message: '#^Access to an undefined property Joomla\\Database\\QueryInterface\:\:\$limit\.$#' + identifier: property.notFound count: 1 - path: src/Command/ExportCommand.php + path: src/DatabaseDriver.php + + - + message: '#^Access to an undefined property Joomla\\Database\\QueryInterface\:\:\$offset\.$#' + identifier: property.notFound + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Call to function is_array\(\) with array will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: src/DatabaseDriver.php - - message: "#^Access to an undefined property Joomla\\\\Database\\\\QueryInterface\\:\\:\\$limit\\.$#" + message: '#^Call to function is_object\(\) with array will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/DatabaseDriver.php - - message: "#^Access to an undefined property Joomla\\\\Database\\\\QueryInterface\\:\\:\\$offset\\.$#" + message: '#^Call to function is_string\(\) with non\-falsy\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/DatabaseDriver.php - - message: "#^Call to function is_object\\(\\) with array will always evaluate to false\\.$#" + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/DatabaseDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 11 path: src/DatabaseDriver.php - - message: "#^Method Joomla\\\\Database\\\\DatabaseDriver\\:\\:getQuery\\(\\) should return Joomla\\\\Database\\\\DatabaseQuery but returns Joomla\\\\Database\\\\QueryInterface\\.$#" + message: '#^Instanceof between Joomla\\Database\\QueryInterface and Joomla\\Database\\QueryInterface will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue count: 1 path: src/DatabaseDriver.php - - message: "#^Parameter \\#1 \\$class of function class_exists expects string, Joomla\\\\Database\\\\DatabaseDriver given\\.$#" + message: '#^Method Joomla\\Database\\DatabaseDriver\:\:getQuery\(\) should return Joomla\\Database\\DatabaseQuery but returns Joomla\\Database\\QueryInterface\.$#' + identifier: return.type count: 1 path: src/DatabaseDriver.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\, array\\, array\\|string\\> given\\.$#" + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type count: 1 path: src/DatabaseDriver.php - - message: "#^Property Joomla\\\\Database\\\\DatabaseDriver\\:\\:\\$connection \\(resource\\) does not accept null\\.$#" + message: '#^Property Joomla\\Database\\DatabaseDriver\:\:\$connection \(resource\) does not accept null\.$#' + identifier: assign.propertyType count: 2 path: src/DatabaseDriver.php - - message: "#^Property Joomla\\\\Database\\\\DatabaseDriver\\:\\:\\$statement \\(Joomla\\\\Database\\\\StatementInterface\\) does not accept null\\.$#" + message: '#^Property Joomla\\Database\\DatabaseDriver\:\:\$statement \(Joomla\\Database\\StatementInterface\) does not accept null\.$#' + identifier: assign.propertyType count: 1 path: src/DatabaseDriver.php - - message: "#^Strict comparison using \\=\\=\\= between 'resource'\\|'resource \\(closed\\)' and 'object' will always evaluate to false\\.$#" + message: '#^Result of \|\| is always false\.$#' + identifier: booleanOr.alwaysFalse count: 1 path: src/DatabaseDriver.php - - message: "#^Strict comparison using \\=\\=\\= between stdClass and null will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between ''resource''\|''resource \(closed\)'' and ''object'' will always evaluate to false\.$#' + identifier: identical.alwaysFalse count: 1 path: src/DatabaseDriver.php - - message: "#^Strict comparison using \\=\\=\\= between string and null will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between stdClass and null will always evaluate to false\.$#' + identifier: identical.alwaysFalse count: 1 path: src/DatabaseDriver.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Strict comparison using \=\=\= between string and null will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: src/DatabaseDriver.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 2 path: src/DatabaseDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 5 path: src/DatabaseIterator.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 2 path: src/DatabaseIterator.php - - message: "#^Argument of an invalid type Joomla\\\\Database\\\\DatabaseQuery supplied for foreach, only iterables are supported\\.$#" + message: '#^Argument of an invalid type \$this\(Joomla\\Database\\DatabaseQuery\) supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable count: 1 path: src/DatabaseQuery.php - - message: "#^If condition is always true\\.$#" - count: 9 + message: '#^Instanceof between Joomla\\Database\\DatabaseInterface and Joomla\\Database\\DatabaseInterface will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue + count: 6 path: src/DatabaseQuery.php - - message: "#^Instanceof between string and \\$this\\(Joomla\\\\Database\\\\DatabaseQuery\\) will always evaluate to false\\.$#" + message: '#^Instanceof between string and \$this\(Joomla\\Database\\DatabaseQuery\) will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse count: 1 path: src/DatabaseQuery.php - - message: "#^Left side of \\|\\| is always true\\.$#" + message: '#^Parameter \#2 \$elements of class Joomla\\Database\\Query\\QueryElement constructor expects array\\|string, null given\.$#' + identifier: argument.type count: 1 path: src/DatabaseQuery.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\|null, string given\\.$#" + message: '#^Return type \(string\) of method Joomla\\Database\\DatabaseQuery\:\:length\(\) should be compatible with return type \(int\) of method Joomla\\Database\\QueryInterface\:\:length\(\)$#' + identifier: method.childReturnType count: 1 path: src/DatabaseQuery.php - - message: "#^Parameter \\#2 \\$elements of class Joomla\\\\Database\\\\Query\\\\QueryElement constructor expects array\\\\|string, null given\\.$#" + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static count: 1 path: src/DatabaseQuery.php - - message: "#^Property Joomla\\\\Database\\\\DatabaseQuery\\:\\:\\$querySet has unknown class Joomla\\\\Database\\\\Query\\\\DatabaseQuery as its type\\.$#" + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 - path: src/DatabaseQuery.php - - - - message: "#^Return type \\(string\\) of method Joomla\\\\Database\\\\DatabaseQuery\\:\\:length\\(\\) should be compatible with return type \\(int\\) of method Joomla\\\\Database\\\\QueryInterface\\:\\:length\\(\\)$#" - count: 1 - path: src/DatabaseQuery.php + path: src/Mysql/MysqlDriver.php - - message: "#^Unsafe usage of new static\\(\\)\\.$#" + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 - path: src/DatabaseQuery.php + path: src/Mysql/MysqlDriver.php - - message: "#^Call to function is_float\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_string\(\) with non\-falsy\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/Mysql/MysqlDriver.php - - message: "#^Call to function is_int\\(\\) with string will always evaluate to false\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 1 path: src/Mysql/MysqlDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type count: 1 path: src/Mysql/MysqlDriver.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\, array\\, array\\|string\\> given\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 1 path: src/Mysql/MysqlDriver.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Call to function is_callable\(\) with array\{mysqli, ''close''\} will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 - path: src/Mysql/MysqlDriver.php + path: src/Mysqli/MysqliDriver.php - - message: "#^Call to an undefined method Joomla\\\\Database\\\\DatabaseInterface\\:\\:isMariaDb\\(\\)\\.$#" + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 - path: src/Mysql/MysqlQuery.php + path: src/Mysqli/MysqliDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 - path: src/Mysql/MysqlQuery.php + path: src/Mysqli/MysqliDriver.php - - message: "#^Call to function is_float\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_object\(\) with mysqli will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/Mysqli/MysqliDriver.php - - message: "#^Call to function is_int\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_string\(\) with non\-falsy\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/Mysqli/MysqliDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 1 path: src/Mysqli/MysqliDriver.php - - message: "#^Method Joomla\\\\Database\\\\Mysqli\\\\MysqliDriver\\:\\:serverClaimsUtf8mb4Support\\(\\) is unused\\.$#" + message: '#^Method Joomla\\Database\\Mysqli\\MysqliDriver\:\:serverClaimsUtf8mb4Support\(\) is unused\.$#' + identifier: method.unused count: 1 path: src/Mysqli/MysqliDriver.php - - message: "#^PHPDoc type mysqli of property Joomla\\\\Database\\\\Mysqli\\\\MysqliDriver\\:\\:\\$connection is not covariant with PHPDoc type resource of overridden property Joomla\\\\Database\\\\DatabaseDriver\\:\\:\\$connection\\.$#" + message: '#^PHPDoc type mysqli of property Joomla\\Database\\Mysqli\\MysqliDriver\:\:\$connection is not covariant with PHPDoc type resource of overridden property Joomla\\Database\\DatabaseDriver\:\:\$connection\.$#' + identifier: property.phpDocType count: 1 path: src/Mysqli/MysqliDriver.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\, array\\, array\\|string\\> given\\.$#" + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type count: 1 path: src/Mysqli/MysqliDriver.php - - message: "#^Property Joomla\\\\Database\\\\Mysqli\\\\MysqliDriver\\:\\:\\$connection \\(mysqli\\) does not accept null\\.$#" + message: '#^Property Joomla\\Database\\Mysqli\\MysqliDriver\:\:\$connection \(mysqli\) does not accept null\.$#' + identifier: assign.propertyType count: 1 path: src/Mysqli/MysqliDriver.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 2 path: src/Mysqli/MysqliDriver.php - - message: "#^Call to an undefined method Joomla\\\\Database\\\\DatabaseInterface\\:\\:isMariaDb\\(\\)\\.$#" + message: '#^PHPDoc type array of property Joomla\\Database\\Mysqli\\MysqliQuery\:\:\$nullDatetimeList is not covariant with PHPDoc type array\ of overridden property Joomla\\Database\\DatabaseQuery\:\:\$nullDatetimeList\.$#' + identifier: property.phpDocType count: 1 path: src/Mysqli/MysqliQuery.php - - message: "#^If condition is always true\\.$#" - count: 1 - path: src/Mysqli/MysqliQuery.php - - - - message: "#^PHPDoc type array of property Joomla\\\\Database\\\\Mysqli\\\\MysqliQuery\\:\\:\\$nullDatetimeList is not covariant with PHPDoc type array\\ of overridden property Joomla\\\\Database\\\\DatabaseQuery\\:\\:\\$nullDatetimeList\\.$#" - count: 1 - path: src/Mysqli/MysqliQuery.php - - - - message: "#^PHPDoc tag @param for parameter \\$dataType with type int is incompatible with native type string\\.$#" + message: '#^PHPDoc tag @param for parameter \$dataType with type int is incompatible with native type string\.$#' + identifier: parameter.phpDocType count: 1 path: src/Mysqli/MysqliStatement.php - - message: "#^Parameter \\#4 \\$previous of class Joomla\\\\Database\\\\Exception\\\\ExecutionFailureException constructor expects Exception\\|null, Throwable given\\.$#" + message: '#^Parameter \#4 \$previous of class Joomla\\Database\\Exception\\ExecutionFailureException constructor expects Exception\|null, Throwable given\.$#' + identifier: argument.type count: 1 path: src/Mysqli/MysqliStatement.php - - message: "#^Return type \\(int\\) of method Joomla\\\\Database\\\\Mysqli\\\\MysqliStatement\\:\\:errorCode\\(\\) should be compatible with return type \\(string\\) of method Joomla\\\\Database\\\\StatementInterface\\:\\:errorCode\\(\\)$#" + message: '#^Return type \(int\) of method Joomla\\Database\\Mysqli\\MysqliStatement\:\:errorCode\(\) should be compatible with return type \(string\) of method Joomla\\Database\\StatementInterface\:\:errorCode\(\)$#' + identifier: method.childReturnType count: 1 path: src/Mysqli/MysqliStatement.php - - message: "#^Return type \\(string\\) of method Joomla\\\\Database\\\\Mysqli\\\\MysqliStatement\\:\\:errorInfo\\(\\) should be compatible with return type \\(array\\) of method Joomla\\\\Database\\\\StatementInterface\\:\\:errorInfo\\(\\)$#" + message: '#^Return type \(string\) of method Joomla\\Database\\Mysqli\\MysqliStatement\:\:errorInfo\(\) should be compatible with return type \(array\) of method Joomla\\Database\\StatementInterface\:\:errorInfo\(\)$#' + identifier: method.childReturnType count: 1 path: src/Mysqli/MysqliStatement.php - - message: "#^Strict comparison using \\=\\=\\= between array\\|bool and null will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between array\|bool and null will always evaluate to false\.$#' + identifier: identical.alwaysFalse count: 1 path: src/Mysqli/MysqliStatement.php - - message: "#^Call to function is_float\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/Pdo/PdoDriver.php - - message: "#^Call to function is_int\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/Pdo/PdoDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 4 path: src/Pdo/PdoDriver.php - - message: "#^PHPDoc type PDO of property Joomla\\\\Database\\\\Pdo\\\\PdoDriver\\:\\:\\$connection is not covariant with PHPDoc type resource of overridden property Joomla\\\\Database\\\\DatabaseDriver\\:\\:\\$connection\\.$#" + message: '#^PHPDoc type PDO of property Joomla\\Database\\Pdo\\PdoDriver\:\:\$connection is not covariant with PHPDoc type resource of overridden property Joomla\\Database\\DatabaseDriver\:\:\$connection\.$#' + identifier: property.phpDocType count: 1 path: src/Pdo/PdoDriver.php - - message: "#^Property Joomla\\\\Database\\\\Pdo\\\\PdoDriver\\:\\:\\$connection \\(PDO\\) does not accept null\\.$#" + message: '#^Property Joomla\\Database\\Pdo\\PdoDriver\:\:\$connection \(PDO\) does not accept null\.$#' + identifier: assign.propertyType count: 1 path: src/Pdo/PdoDriver.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 1 path: src/Pdo/PdoDriver.php - - message: "#^PHPDoc type array of property Joomla\\\\Database\\\\Pdo\\\\PdoQuery\\:\\:\\$nullDatetimeList is not covariant with PHPDoc type array\\ of overridden property Joomla\\\\Database\\\\DatabaseQuery\\:\\:\\$nullDatetimeList\\.$#" + message: '#^PHPDoc type array of property Joomla\\Database\\Pdo\\PdoQuery\:\:\$nullDatetimeList is not covariant with PHPDoc type array\ of overridden property Joomla\\Database\\DatabaseQuery\:\:\$nullDatetimeList\.$#' + identifier: property.phpDocType count: 1 path: src/Pdo/PdoQuery.php - - message: "#^Call to an undefined method Joomla\\\\Database\\\\QueryInterface\\:\\:leftJoin\\(\\)\\.$#" - count: 1 - path: src/Pgsql/PgsqlDriver.php - - - - message: "#^Call to an undefined method Joomla\\\\Database\\\\QueryInterface\\:\\:returning\\(\\)\\.$#" - count: 1 - path: src/Pgsql/PgsqlDriver.php - - - - message: "#^Call to function is_object\\(\\) with array will always evaluate to false\\.$#" + message: '#^Call to function is_object\(\) with array will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/Pgsql/PgsqlDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 1 path: src/Pgsql/PgsqlDriver.php - - message: "#^Strict comparison using \\=\\=\\= between string and 0 will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between string and 0 will always evaluate to false\.$#' + identifier: identical.alwaysFalse count: 1 path: src/Pgsql/PgsqlDriver.php - - message: "#^Strict comparison using \\=\\=\\= between string and 1 will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between string and 1 will always evaluate to false\.$#' + identifier: identical.alwaysFalse count: 1 path: src/Pgsql/PgsqlDriver.php - - message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between string and false will always evaluate to false\.$#' + identifier: identical.alwaysFalse count: 1 path: src/Pgsql/PgsqlDriver.php - - message: "#^Strict comparison using \\=\\=\\= between string and true will always evaluate to false\\.$#" + message: '#^Strict comparison using \=\=\= between string and true will always evaluate to false\.$#' + identifier: identical.alwaysFalse count: 1 path: src/Pgsql/PgsqlDriver.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 1 path: src/Pgsql/PgsqlDriver.php - - message: "#^Call to an undefined method Joomla\\\\Database\\\\DatabaseInterface\\:\\:getNamesKey\\(\\)\\.$#" - count: 1 - path: src/Pgsql/PgsqlExporter.php - - - - message: "#^Call to an undefined method Joomla\\\\Database\\\\DatabaseInterface\\:\\:getSequenceIsCalled\\(\\)\\.$#" - count: 1 - path: src/Pgsql/PgsqlExporter.php - - - - message: "#^Call to an undefined method Joomla\\\\Database\\\\DatabaseInterface\\:\\:getSequenceLastValue\\(\\)\\.$#" - count: 1 - path: src/Pgsql/PgsqlExporter.php - - - - message: "#^Call to an undefined method Joomla\\\\Database\\\\DatabaseInterface\\:\\:getTableSequences\\(\\)\\.$#" + message: '#^Instanceof between Joomla\\Database\\Pgsql\\PgsqlDriver and Joomla\\Database\\Pgsql\\PgsqlDriver will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue count: 1 path: src/Pgsql/PgsqlExporter.php - - message: "#^Call to an undefined method Joomla\\\\Database\\\\DatabaseInterface\\:\\:getTableSequences\\(\\)\\.$#" + message: '#^Cannot access property \$Index on array\.$#' + identifier: property.nonObject count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Cannot access property \\$Index on array\\.$#" + message: '#^Cannot access property \$Key_name on array\.$#' + identifier: property.nonObject count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Cannot access property \\$Key_name on array\\.$#" + message: '#^Instanceof between Joomla\\Database\\Pgsql\\PgsqlDriver and Joomla\\Database\\Pgsql\\PgsqlDriver will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Instanceof between array and SimpleXMLElement will always evaluate to false\\.$#" + message: '#^Instanceof between array and SimpleXMLElement will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Method Joomla\\\\Database\\\\Pgsql\\\\PgsqlImporter\\:\\:getChangeSequenceSql\\(\\) invoked with 2 parameters, 1 required\\.$#" + message: '#^Method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getChangeSequenceSql\(\) invoked with 2 parameters, 1 required\.$#' + identifier: arguments.count count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Method Joomla\\\\Database\\\\Pgsql\\\\PgsqlImporter\\:\\:getSetvalSequenceSql\\(\\) invoked with 2 parameters, 1 required\\.$#" + message: '#^Method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getSetvalSequenceSql\(\) invoked with 2 parameters, 1 required\.$#' + identifier: arguments.count count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Parameter \\#1 \\$field of method Joomla\\\\Database\\\\Pgsql\\\\PgsqlImporter\\:\\:getChangeSequenceSql\\(\\) expects SimpleXMLElement, \\(int\\|string\\) given\\.$#" + message: '#^Parameter \#1 \$field of method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getChangeSequenceSql\(\) expects SimpleXMLElement, \(int\|string\) given\.$#' + identifier: argument.type count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Parameter \\#1 \\$field of method Joomla\\\\Database\\\\Pgsql\\\\PgsqlImporter\\:\\:getSetvalSequenceSql\\(\\) expects SimpleXMLElement, \\(int\\|string\\) given\\.$#" + message: '#^Parameter \#1 \$field of method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getSetvalSequenceSql\(\) expects SimpleXMLElement, \(int\|string\) given\.$#' + identifier: argument.type count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^Parameter \\#2 \\$key of method Joomla\\\\Database\\\\Pgsql\\\\PgsqlImporter\\:\\:getAddUniqueSql\\(\\) expects array, SimpleXMLElement given\\.$#" + message: '#^Parameter \#2 \$key of method Joomla\\Database\\Pgsql\\PgsqlImporter\:\:getAddUniqueSql\(\) expects array, SimpleXMLElement given\.$#' + identifier: argument.type count: 1 path: src/Pgsql/PgsqlImporter.php - - message: "#^If condition is always true\\.$#" - count: 12 - path: src/Pgsql/PgsqlQuery.php - - - - message: "#^Instanceof between string and \\$this\\(Joomla\\\\Database\\\\Pgsql\\\\PgsqlQuery\\) will always evaluate to false\\.$#" + message: '#^Instanceof between string and \$this\(Joomla\\Database\\Pgsql\\PgsqlQuery\) will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse count: 1 path: src/Pgsql/PgsqlQuery.php - - message: "#^Parameter \\#2 \\$elements of class Joomla\\\\Database\\\\Query\\\\QueryElement constructor expects array\\\\|string, int given\\.$#" + message: '#^Parameter \#2 \$elements of class Joomla\\Database\\Query\\QueryElement constructor expects array\\|string, int given\.$#' + identifier: argument.type count: 2 path: src/Pgsql/PgsqlQuery.php - - message: "#^Parameter \\#2 \\$elements of class Joomla\\\\Database\\\\Query\\\\QueryElement constructor expects array\\\\|string, null given\\.$#" + message: '#^Parameter \#2 \$elements of class Joomla\\Database\\Query\\QueryElement constructor expects array\\|string, null given\.$#' + identifier: argument.type count: 1 path: src/Pgsql/PgsqlQuery.php - - message: "#^Ternary operator condition is always true\\.$#" + message: '#^Property Joomla\\Database\\DatabaseQuery\:\:\$limit \(int\|null\) does not accept Joomla\\Database\\Query\\QueryElement\.$#' + identifier: assign.propertyType count: 1 path: src/Pgsql/PgsqlQuery.php - - message: """ - #^Fetching class constant class of deprecated interface Joomla\\\\Database\\\\Query\\\\LimitableInterface\\: - 3\\.0 Capabilities will be required in Joomla\\\\Database\\\\QueryInterface$# - """ + message: '#^Property Joomla\\Database\\DatabaseQuery\:\:\$offset \(int\|null\) does not accept Joomla\\Database\\Query\\QueryElement\.$#' + identifier: assign.propertyType count: 1 - path: src/Query/LimitableInterface.php - - - - message: """ - #^Fetching class constant class of deprecated interface Joomla\\\\Database\\\\Query\\\\PreparableInterface\\: - 3\\.0 Capabilities will be required in Joomla\\\\Database\\\\QueryInterface$# - """ - count: 1 - path: src/Query/PreparableInterface.php + path: src/Pgsql/PgsqlQuery.php - - message: "#^Argument of an invalid type Joomla\\\\Database\\\\Query\\\\QueryElement supplied for foreach, only iterables are supported\\.$#" + message: '#^Argument of an invalid type \$this\(Joomla\\Database\\Query\\QueryElement\) supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable count: 1 path: src/Query/QueryElement.php - - message: """ - #^Interface Joomla\\\\Database\\\\QueryInterface extends deprecated interface Joomla\\\\Database\\\\Query\\\\LimitableInterface\\: - 3\\.0 Capabilities will be required in Joomla\\\\Database\\\\QueryInterface$# - """ - count: 1 - path: src/QueryInterface.php - - - - message: """ - #^Interface Joomla\\\\Database\\\\QueryInterface extends deprecated interface Joomla\\\\Database\\\\Query\\\\PreparableInterface\\: - 3\\.0 Capabilities will be required in Joomla\\\\Database\\\\QueryInterface$# - """ - count: 1 - path: src/QueryInterface.php - - - - message: "#^Call to function is_float\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/Sqlite/SqliteDriver.php - - message: "#^Call to function is_int\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/Sqlite/SqliteDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 1 path: src/Sqlite/SqliteDriver.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 1 path: src/Sqlite/SqliteDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^Unsafe usage of new static\(\)\.$#' + identifier: new.static count: 1 path: src/Sqlite/SqliteQuery.php - - message: "#^Left side of \\|\\| is always true\\.$#" - count: 1 - path: src/Sqlite/SqliteQuery.php - - - - message: "#^Result of \\|\\| is always true\\.$#" - count: 1 - path: src/Sqlite/SqliteQuery.php - - - - message: "#^Unsafe usage of new static\\(\\)\\.$#" - count: 1 - path: src/Sqlite/SqliteQuery.php - - - - message: "#^Call to function is_float\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_float\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/Sqlsrv/SqlsrvDriver.php - - message: "#^Call to function is_int\\(\\) with string will always evaluate to false\\.$#" + message: '#^Call to function is_int\(\) with string will always evaluate to false\.$#' + identifier: function.impossibleType count: 1 path: src/Sqlsrv/SqlsrvDriver.php - - message: "#^If condition is always true\\.$#" + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue count: 4 path: src/Sqlsrv/SqlsrvDriver.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\, array\\, array\\|string\\> given\\.$#" - count: 1 + message: '#^Parameter \#2 \$array of function implode expects array\, list\ given\.$#' + identifier: argument.type + count: 2 path: src/Sqlsrv/SqlsrvDriver.php - - message: "#^Parameter \\#3 \\$params of function sqlsrv_query expects array, null given\\.$#" + message: '#^Parameter \#3 \$params of function sqlsrv_query expects array, null given\.$#' + identifier: argument.type count: 1 path: src/Sqlsrv/SqlsrvDriver.php - - message: "#^Property Joomla\\\\Database\\\\DatabaseDriver\\:\\:\\$connection \\(resource\\) does not accept null\\.$#" + message: '#^Property Joomla\\Database\\DatabaseDriver\:\:\$connection \(resource\) does not accept null\.$#' + identifier: assign.propertyType count: 1 path: src/Sqlsrv/SqlsrvDriver.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 1 path: src/Sqlsrv/SqlsrvDriver.php - - message: "#^Comparison operation \"\\>\" between 0 and 1 is always false\\.$#" + message: '#^Comparison operation "\>" between 0 and 1 is always false\.$#' + identifier: greater.alwaysFalse count: 1 path: src/Sqlsrv/SqlsrvQuery.php - - message: "#^If condition is always true\\.$#" - count: 14 - path: src/Sqlsrv/SqlsrvQuery.php - - - - message: "#^Left side of \\|\\| is always true\\.$#" - count: 1 - path: src/Sqlsrv/SqlsrvQuery.php - - - - message: "#^Offset int\\<1, max\\> on array\\<0, mixed\\> in isset\\(\\) does not exist\\.$#" + message: '#^Instanceof between Joomla\\Database\\DatabaseInterface and Joomla\\Database\\DatabaseInterface will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue count: 1 path: src/Sqlsrv/SqlsrvQuery.php - - message: "#^PHPDoc type array of property Joomla\\\\Database\\\\Sqlsrv\\\\SqlsrvQuery\\:\\:\\$nullDatetimeList is not covariant with PHPDoc type array\\ of overridden property Joomla\\\\Database\\\\DatabaseQuery\\:\\:\\$nullDatetimeList\\.$#" + message: '#^Offset int\<1, max\> on list in isset\(\) does not exist\.$#' + identifier: isset.offset count: 1 path: src/Sqlsrv/SqlsrvQuery.php - - message: "#^Parameter \\#2 \\$array of function implode expects array\\, array\\ given\\.$#" + message: '#^PHPDoc type array of property Joomla\\Database\\Sqlsrv\\SqlsrvQuery\:\:\$nullDatetimeList is not covariant with PHPDoc type array\ of overridden property Joomla\\Database\\DatabaseQuery\:\:\$nullDatetimeList\.$#' + identifier: property.phpDocType count: 1 path: src/Sqlsrv/SqlsrvQuery.php - - message: "#^Result of \\|\\| is always true\\.$#" + message: '#^Return type \(string\) of method Joomla\\Database\\Sqlsrv\\SqlsrvQuery\:\:length\(\) should be compatible with return type \(int\) of method Joomla\\Database\\QueryInterface\:\:length\(\)$#' + identifier: method.childReturnType count: 1 path: src/Sqlsrv/SqlsrvQuery.php - - - - message: "#^Return type \\(string\\) of method Joomla\\\\Database\\\\Sqlsrv\\\\SqlsrvQuery\\:\\:length\\(\\) should be compatible with return type \\(int\\) of method Joomla\\\\Database\\\\QueryInterface\\:\\:length\\(\\)$#" - count: 1 - path: src/Sqlsrv/SqlsrvQuery.php - - - - message: "#^Method Joomla\\\\Database\\\\Sqlsrv\\\\SqlsrvStatement\\:\\:errorCode\\(\\) should return string but returns false\\.$#" - count: 1 - path: src/Sqlsrv/SqlsrvStatement.php - - - - message: "#^Negated boolean expression is always false\\.$#" - count: 1 - path: src/Sqlsrv/SqlsrvStatement.php - - - - message: "#^Parameter \\#2 \\$className of function sqlsrv_fetch_object expects string, int given\\.$#" - count: 1 - path: src/Sqlsrv/SqlsrvStatement.php - - - - message: "#^Property Joomla\\\\Database\\\\Sqlsrv\\\\SqlsrvStatement\\:\\:\\$defaultObjectClass \\(int\\) does not accept default value of type string\\.$#" - count: 1 - path: src/Sqlsrv/SqlsrvStatement.php - - - - message: "#^Property Joomla\\\\Database\\\\Sqlsrv\\\\SqlsrvStatement\\:\\:\\$statement \\(resource\\) does not accept null\\.$#" - count: 1 - path: src/Sqlsrv/SqlsrvStatement.php diff --git a/src/Command/ExportCommand.php b/src/Command/ExportCommand.php index ab4d172f0..b3a9c0097 100644 --- a/src/Command/ExportCommand.php +++ b/src/Command/ExportCommand.php @@ -95,7 +95,6 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in $tableName = $input->getOption('table'); $zip = $input->getOption('zip'); - $zipFile = $folderPath . '/data_exported_' . date("Y-m-d\TH-i-s") . '.zip'; $tables = $this->db->getTableList(); $prefix = $this->db->getPrefix(); @@ -109,20 +108,15 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in $tables = [$tableName]; } - if ($zip) { - if (!class_exists(Archive::class)) { - $symfonyStyle->error('The "joomla/archive" Composer package is not installed, cannot create ZIP files.'); - - return 1; - } - - /** @var Zip $zipArchive */ - $zipArchive = (new Archive())->getAdapter('zip'); + if ($zip && !class_exists(Archive::class)) { + $symfonyStyle->error('The "joomla/archive" Composer package is not installed, cannot create ZIP files.'); - $filenames = []; - $zipFilesArray = []; + return 1; } + $filenames = []; + $zipFilesArray = []; + foreach ($tables as $table) { // If an empty prefix is in use then we will dump all tables, otherwise the prefix must match if (strlen($prefix) === 0 || strpos(substr($table, 0, strlen($prefix)), $prefix) !== false) { @@ -139,16 +133,18 @@ protected function doExecute(InputInterface $input, OutputInterface $output): in File::write($filename, $data); - if ($zip) { - $zipFilesArray[] = ['name' => $table . '.xml', 'data' => $data]; - $filenames[] = $filename; - } + $zipFilesArray[] = ['name' => $table . '.xml', 'data' => $data]; + $filenames[] = $filename; $symfonyStyle->text(sprintf('Exported data for %s in %d seconds', $table, round(microtime(true) - $taskTime, 3))); } } if ($zip) { + /** @var Zip $zipArchive */ + $zipArchive = (new Archive())->getAdapter('zip'); + + $zipFile = $folderPath . '/data_exported_' . date("Y-m-d\TH-i-s") . '.zip'; $zipArchive->create($zipFile, $zipFilesArray); foreach ($filenames as $fname) { File::delete($fname); diff --git a/src/DatabaseDriver.php b/src/DatabaseDriver.php index 9f943ef60..81885d022 100644 --- a/src/DatabaseDriver.php +++ b/src/DatabaseDriver.php @@ -250,7 +250,6 @@ public static function getConnectors() $baseName = $file->getBasename(); // Derive the class name from the type. - /** @var DatabaseDriver $class */ $class = __NAMESPACE__ . '\\' . ucfirst(strtolower($baseName)) . '\\' . ucfirst(strtolower($baseName)) . 'Driver'; // If the class doesn't exist, or if it's not supported on this system, move on to the next type. @@ -501,15 +500,14 @@ public function __destruct() * * @param string $dbName The database name that will be altered * - * @return boolean|resource + * @return boolean * * @since 2.0.0 - * @throws \RuntimeException */ public function alterDbCharacterSet($dbName) { - if ($dbName === null) { - throw new \RuntimeException('Database name must not be null.'); + if ($dbName === null || !is_string($dbName) || $dbName === '') { + throw new \RuntimeException('Database name must not be null and a non empty string.'); } $this->setQuery($this->getAlterDbCharacterSet($dbName)); @@ -523,7 +521,7 @@ public function alterDbCharacterSet($dbName) * @param \stdClass $options Object used to pass user and database name to database driver. This object must have "db_name" and "db_user" set. * @param boolean $utf True if the database supports the UTF-8 character set. * - * @return boolean|resource + * @return boolean * * @since 2.0.0 * @throws \RuntimeException @@ -979,7 +977,7 @@ public function getImporter() * Get the current query object or a new DatabaseQuery object. * * @param boolean $new False to return the current query object, True to return a new DatabaseQuery object. - * The $new parameter is deprecated in 2.2 and will be removed in 4.0, use createQuery() instead. + * The $new parameter is deprecated in 2.2 and will be removed in 5.0, use createQuery() instead. * * @return DatabaseQuery * @@ -991,7 +989,7 @@ public function getQuery($new = false) trigger_deprecation( 'joomla/database', '2.2.0', - 'The parameter $new is deprecated and will be removed in 4.0, use %s::createQuery() instead.', + 'The parameter $new is deprecated and will be removed in 5.0, use %s::createQuery() instead.', self::class ); @@ -1579,31 +1577,6 @@ protected function quoteNameString($name, $asSinglePart = false) return $q[0] . str_replace('.', "$q[1].$q[0]", $name) . $q[1]; } - /** - * Quote strings coming from quoteName call. - * - * @param array $strArr Array of strings coming from quoteName dot-explosion. - * - * @return string Dot-imploded string of quoted parts. - * - * @since 1.0 - * @deprecated 2.0 Use quoteNameString instead - */ - protected function quoteNameStr($strArr) - { - $parts = []; - - foreach ($strArr as $part) { - if ($part === null) { - continue; - } - - $parts[] = $this->quoteNameString($part, true); - } - - return implode('.', $parts); - } - /** * This function replaces a string identifier with the configured table prefix. * @@ -1743,7 +1716,7 @@ public function setQuery($query, $offset = 0, $limit = 0) if (\is_string($query)) { // Allows taking advantage of bound variables in a direct query: - $query = $this->getQuery(true)->setQuery($query); + $query = $this->createQuery()->setQuery($query); } elseif (!($query instanceof QueryInterface)) { throw new \InvalidArgumentException( sprintf( diff --git a/src/DatabaseExporter.php b/src/DatabaseExporter.php index fd26d110f..dffedf18b 100644 --- a/src/DatabaseExporter.php +++ b/src/DatabaseExporter.php @@ -269,7 +269,7 @@ protected function buildXmlData() } $this->db->setQuery( - $this->db->getQuery(true) + $this->db->createQuery() ->select($this->db->quoteName(array_keys($fields))) ->from($this->db->quoteName($table)) ); diff --git a/src/DatabaseInterface.php b/src/DatabaseInterface.php index 508b9b954..5f3e41c95 100644 --- a/src/DatabaseInterface.php +++ b/src/DatabaseInterface.php @@ -48,6 +48,15 @@ public function connected(); */ public function createDatabase($options, $utf = true); + /** + * Create a new DatabaseQuery object. + * + * @return QueryInterface + * + * @since 4.0.0 + */ + public function createQuery(): QueryInterface; + /** * Replace special placeholder representing binary field with the original string. * @@ -232,9 +241,10 @@ public function getPrefix(); public function getNumRows(); /** - * Get the current query object or a new QueryInterface object. + * Get the current query object. (Deprecated: Or a new QueryInterface object). * - * @param boolean $new False to return the current query object, True to return a new QueryInterface object. + * @param boolean $new False to return the current query object, True to return a new DatabaseQuery object. + * The $new parameter is deprecated in 2.2 and will be removed in 5.0, use createQuery() instead. * * @return QueryInterface * @@ -460,7 +470,7 @@ public function lockTable($tableName); * @param array|string $text A string or an array of strings to quote. * @param boolean $escape True (default) to escape the string, false to leave it unchanged. * - * @return string + * @return array|string The quoted input string. * * @since 2.0.0 */ diff --git a/src/DatabaseQuery.php b/src/DatabaseQuery.php index b288c4df9..6abc16f8b 100644 --- a/src/DatabaseQuery.php +++ b/src/DatabaseQuery.php @@ -20,26 +20,26 @@ * @property-read array $bounded Holds key / value pair of bound objects. * @property-read array $parameterMapping Mapping array for parameter types. * @property-read DatabaseInterface $db The database driver. - * @property-read string $sql The SQL query (if a direct query string was provided). + * @property-read string|null $sql The SQL query (if a direct query string was provided). * @property-read string $type The query type. * @property-read string|null $alias The query alias. * @property-read Query\QueryElement $element The query element for a generic query (type = null). - * @property-read Query\QueryElement $select The select element. - * @property-read Query\QueryElement $delete The delete element. - * @property-read Query\QueryElement $update The update element. - * @property-read Query\QueryElement $insert The insert element. - * @property-read Query\QueryElement $from The from element. + * @property-read Query\QueryElement|null $select The select element. + * @property-read Query\QueryElement|null $delete The delete element. + * @property-read Query\QueryElement|null $update The update element. + * @property-read Query\QueryElement|null $insert The insert element. + * @property-read Query\QueryElement|null $from The from element. * @property-read Query\QueryElement[]|null $join The join elements. - * @property-read Query\QueryElement $set The set element. - * @property-read Query\QueryElement $where The where element. - * @property-read Query\QueryElement $group The group element. - * @property-read Query\QueryElement $having The having element. - * @property-read Query\QueryElement $columns The column list for an INSERT statement. - * @property-read Query\QueryElement $values The values list for an INSERT statement. - * @property-read Query\QueryElement $order The order element. - * @property-read boolean $autoIncrementField The auto increment insert field element. - * @property-read Query\QueryElement $call The call element. - * @property-read Query\QueryElement $exec The exec element. + * @property-read Query\QueryElement|null $set The set element. + * @property-read Query\QueryElement|null $where The where element. + * @property-read Query\QueryElement|null $group The group element. + * @property-read Query\QueryElement|null $having The having element. + * @property-read Query\QueryElement|null $columns The column list for an INSERT statement. + * @property-read Query\QueryElement|null $values The values list for an INSERT statement. + * @property-read Query\QueryElement|null $order The order element. + * @property-read boolean|null $autoIncrementField The auto increment insert field element. + * @property-read Query\QueryElement|null $call The call element. + * @property-read Query\QueryElement|null $exec The exec element. * @property-read Query\QueryElement[]|null $merge The list of query elements. * @property-read DatabaseQuery|null $querySet The query object. * @property-read array|null $selectRowNumber Details of window function. @@ -83,7 +83,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The SQL query (if a direct query string was provided). * - * @var string + * @var ?string * @since 1.0 */ protected $sql; @@ -115,7 +115,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The select element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $select; @@ -123,7 +123,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The delete element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $delete; @@ -131,7 +131,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The update element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $update; @@ -139,7 +139,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The insert element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $insert; @@ -147,7 +147,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The from element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $from; @@ -155,7 +155,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The join elements. * - * @var Query\QueryElement[] + * @var ?Query\QueryElement[] * @since 1.0 */ protected $join; @@ -163,7 +163,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The set element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $set; @@ -171,7 +171,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The where element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $where; @@ -179,7 +179,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The group by element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $group; @@ -187,7 +187,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The having element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $having; @@ -195,7 +195,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The column list for an INSERT statement. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $columns; @@ -203,7 +203,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The values list for an INSERT statement. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $values; @@ -211,7 +211,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The order element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $order; @@ -219,7 +219,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The auto increment insert field element. * - * @var boolean + * @var ?boolean * @since 1.0 */ protected $autoIncrementField = false; @@ -227,7 +227,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The call element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $call; @@ -235,7 +235,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The exec element. * - * @var Query\QueryElement + * @var ?Query\QueryElement * @since 1.0 */ protected $exec; @@ -243,7 +243,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The list of query elements, which may include UNION, UNION ALL, EXCEPT and INTERSECT. * - * @var Query\QueryElement[] + * @var ?Query\QueryElement[] * @since 2.0.0 */ protected $merge; @@ -251,7 +251,7 @@ abstract class DatabaseQuery implements QueryInterface /** * The query object. * - * @var Query\DatabaseQuery + * @var ?DatabaseQuery * @since 2.0.0 */ protected $querySet; @@ -558,26 +558,6 @@ public function castAs(string $type, string $value, ?string $length = null) } } - /** - * Casts a value to a char. - * - * Ensure that the value is properly quoted before passing to the method. - * - * Usage: - * $query->select($query->castAsChar('a')); - * - * @param string $value The value to cast as a char. - * - * @return string SQL statement to cast the value as a char type. - * - * @since 1.0 - * @deprecated 3.0 Use $query->castAs('CHAR', $value) - */ - public function castAsChar($value) - { - return $this->castAs('CHAR', $value); - } - /** * Gets the number of characters in a string. * @@ -1486,7 +1466,7 @@ public function q($text, $escape = true) * @param array|string $text A string or an array of strings to quote. * @param boolean $escape True (default) to escape the string, false to leave it unchanged. * - * @return string The quoted input string. + * @return array|string The quoted input string. * * @since 1.0 * @throws \RuntimeException if the internal db property is not a valid object. diff --git a/src/Pgsql/PgsqlDriver.php b/src/Pgsql/PgsqlDriver.php index 86ee08725..16c93d12e 100644 --- a/src/Pgsql/PgsqlDriver.php +++ b/src/Pgsql/PgsqlDriver.php @@ -767,6 +767,7 @@ public function insertObject($table, &$object, $key = null) } // Create the base insert statement. + /** @var PgsqlQuery $query */ $query = $this->createQuery(); $query->insert($this->quoteName($table)) diff --git a/src/Pgsql/PgsqlExporter.php b/src/Pgsql/PgsqlExporter.php index 08d7d2a3d..124081f63 100644 --- a/src/Pgsql/PgsqlExporter.php +++ b/src/Pgsql/PgsqlExporter.php @@ -18,6 +18,14 @@ */ class PgsqlExporter extends DatabaseExporter { + /** + * The database connector to use for exporting structure and/or data. + * + * @var PgsqlDriver + * @since 1.0 + */ + protected $db; + /** * Builds the XML data for the tables to export. * @@ -126,7 +134,7 @@ protected function buildXmlData() } } - $query = $this->db->getQuery(true); + $query = $this->db->createQuery(); $query->select($query->quoteName(array_keys($fields))) ->from($query->quoteName($table)); $this->db->setQuery($query); diff --git a/src/Pgsql/PgsqlImporter.php b/src/Pgsql/PgsqlImporter.php index 1bc7d85f6..207c25d77 100644 --- a/src/Pgsql/PgsqlImporter.php +++ b/src/Pgsql/PgsqlImporter.php @@ -18,6 +18,14 @@ */ class PgsqlImporter extends DatabaseImporter { + /** + * The database connector to use for exporting structure and/or data. + * + * @var PgsqlDriver + * @since 1.0 + */ + protected $db; + /** * Checks if all data and options are in order prior to exporting. * diff --git a/src/Query/LimitableInterface.php b/src/Query/LimitableInterface.php deleted file mode 100644 index 2932b31ea..000000000 --- a/src/Query/LimitableInterface.php +++ /dev/null @@ -1,61 +0,0 @@ -setLimit(100, 0); (retrieve 100 rows, starting at first record) - * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record) - * - * @param integer $limit The limit for the result set - * @param integer $offset The offset for the result set - * - * @return $this - * - * @since 1.0 - */ - public function setLimit($limit = 0, $offset = 0); -} diff --git a/src/Query/MysqlQueryBuilder.php b/src/Query/MysqlQueryBuilder.php index a23f6f805..7ac3139b6 100644 --- a/src/Query/MysqlQueryBuilder.php +++ b/src/Query/MysqlQueryBuilder.php @@ -9,6 +9,8 @@ namespace Joomla\Database\Query; +use Joomla\Database\Mysql\MysqlDriver; + /** * Trait for MySQL Query Building. * @@ -136,7 +138,7 @@ public function groupConcat($expression, $separator = ',') * @param array|string $text A string or an array of strings to quote. * @param boolean $escape True (default) to escape the string, false to leave it unchanged. * - * @return string The quoted input string. + * @return array|string The quoted input string. * * @since 2.0.0 * @throws \RuntimeException if the internal db property is not a valid object. @@ -217,8 +219,11 @@ public function findInSet($value, $set) */ public function selectRowNumber($orderBy, $orderColumnAlias) { + /** @var MysqlDriver $db */ + $db = $this->db; + // Use parent method with ROW_NUMBER() window function on MariaDB >= 10.2.0 and MySQL >= 8.0.0. - if (version_compare($this->db->getVersion(), $this->db->isMariaDb() ? '10.2.0' : '8.0.0', '>=')) { + if (version_compare($db->getVersion(), $db->isMariaDb() ? '10.2.0' : '8.0.0', '>=')) { return parent::selectRowNumber($orderBy, $orderColumnAlias); } diff --git a/src/Query/PostgresqlQueryBuilder.php b/src/Query/PostgresqlQueryBuilder.php index d54464e5c..a520fc5ed 100644 --- a/src/Query/PostgresqlQueryBuilder.php +++ b/src/Query/PostgresqlQueryBuilder.php @@ -19,7 +19,7 @@ trait PostgresqlQueryBuilder /** * The FOR UPDATE element used in "FOR UPDATE" lock * - * @var QueryElement + * @var ?QueryElement * @since 2.0.0 */ protected $forUpdate; @@ -27,7 +27,7 @@ trait PostgresqlQueryBuilder /** * The FOR SHARE element used in "FOR SHARE" lock * - * @var QueryElement + * @var ?QueryElement * @since 2.0.0 */ protected $forShare; @@ -35,7 +35,7 @@ trait PostgresqlQueryBuilder /** * The NOWAIT element used in "FOR SHARE" and "FOR UPDATE" lock * - * @var QueryElement + * @var ?QueryElement * @since 2.0.0 */ protected $noWait; @@ -59,7 +59,7 @@ trait PostgresqlQueryBuilder /** * The RETURNING element of INSERT INTO * - * @var QueryElement + * @var ?QueryElement * @since 2.0.0 */ protected $returning; diff --git a/src/Query/PreparableInterface.php b/src/Query/PreparableInterface.php deleted file mode 100644 index 125d4325c..000000000 --- a/src/Query/PreparableInterface.php +++ /dev/null @@ -1,75 +0,0 @@ -innerJoin('b', 'b.id = a.id')->innerJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function innerJoin($table, $condition = null); + + /** + * Add an OUTER JOIN clause to the query. + * + * Usage: + * $query->outerJoin('b', 'b.id = a.id')->leftJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function outerJoin($table, $condition = null); + + /** + * Add a LEFT JOIN clause to the query. + * + * Usage: + * $query->leftJoin('b', 'b.id = a.id')->leftJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function leftJoin($table, $condition = null); + + /** + * Add a RIGHT JOIN clause to the query. + * + * Usage: + * $query->rightJoin('b', 'b.id = a.id')->rightJoin('c', 'c.id = b.id'); + * + * @param string $table The name of table. + * @param string $condition The join condition. + * + * @return $this + * + * @since 4.0 + */ + public function rightJoin($table, $condition = null); + /** * Get the length of a string in bytes. * @@ -537,6 +595,21 @@ public function selectRowNumber($orderBy, $orderColumnAlias); */ public function set($conditions, $glue = ','); + /** + * Allows a direct query to be provided to the database driver's setQuery() method, but still allow queries + * to have bounded variables. + * + * Usage: + * $query->setQuery('select * from #__users'); + * + * @param DatabaseQuery|string $sql A SQL query string or DatabaseQuery object + * + * @return $this + * + * @since 4.0 + */ + public function setQuery($sql); + /** * Add a table name to the UPDATE clause of the query. * @@ -722,4 +795,75 @@ public function querySet($query); * @since 2.0.0 */ public function toQuerySet(); + + /** + * Method to add a variable to an internal array that will be bound to a prepared SQL statement before query execution. + * + * @param array|string|integer $key The key that will be used in your SQL query to reference the value. Usually of + * the form ':key', but can also be an integer. + * @param mixed $value The value that will be bound. It can be an array, in this case it has to be + * same length of $key; The value is passed by reference to support output + * parameters such as those possible with stored procedures. + * @param array|string $dataType Constant corresponding to a SQL datatype. It can be an array, in this case it + * has to be same length of $key + * @param integer $length The length of the variable. Usually required for OUTPUT parameters. + * @param array $driverOptions Optional driver options to be used. + * + * @return $this + * + * @since 4.0 + */ + public function bind($key, &$value, $dataType = ParameterType::STRING, $length = 0, $driverOptions = []); + + /** + * Method to unbind a bound variable. + * + * @param array|string|integer $key The key or array of keys to unbind. + * + * @return $this + * + * @since 4.0.0 + */ + public function unbind($key); + + /** + * Retrieves the bound parameters array when key is null and returns it by reference. If a key is provided then that item is returned. + * + * @param mixed $key The bounded variable key to retrieve. + * + * @return mixed + * + * @since 4.0 + */ + public function &getBounded($key = null); + + /** + * Method to modify a query already in string format with the needed additions to make the query limited to a particular number of + * results, or start at a particular offset. + * + * @param string $query The query in string format + * @param integer $limit The limit for the result set + * @param integer $offset The offset for the result set + * + * @return string + * + * @since 4.0 + */ + public function processLimit($query, $limit, $offset = 0); + + /** + * Sets the offset and limit for the result set, if the database driver supports it. + * + * Usage: + * $query->setLimit(100, 0); (retrieve 100 rows, starting at first record) + * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record) + * + * @param integer $limit The limit for the result set + * @param integer $offset The offset for the result set + * + * @return $this + * + * @since 4.0 + */ + public function setLimit($limit = 0, $offset = 0); } diff --git a/src/Sqlsrv/SqlsrvDriver.php b/src/Sqlsrv/SqlsrvDriver.php index d8b88cb80..e2a430c71 100644 --- a/src/Sqlsrv/SqlsrvDriver.php +++ b/src/Sqlsrv/SqlsrvDriver.php @@ -249,7 +249,7 @@ public function escape($text, $extra = false) * @param mixed $text A string or an array of strings to quote. * @param boolean $escape True (default) to escape the string, false to leave it unchanged. * - * @return string The quoted input string. + * @return array|string The quoted input string. * * @since 1.6.0 */ @@ -338,7 +338,6 @@ public function getCollation() * @return string|boolean The collation in use by the database connection (string) or boolean false if not supported. * * @since 1.6.0 - * @throws \RuntimeException */ public function getConnectionCollation() { @@ -352,7 +351,6 @@ public function getConnectionCollation() * @return string The database encryption details. * * @since 2.0.0 - * @throws \RuntimeException */ public function getConnectionEncryption(): string { diff --git a/src/Sqlsrv/SqlsrvQuery.php b/src/Sqlsrv/SqlsrvQuery.php index 66937c41c..76905340d 100644 --- a/src/Sqlsrv/SqlsrvQuery.php +++ b/src/Sqlsrv/SqlsrvQuery.php @@ -712,7 +712,7 @@ protected function fixGroupColumns($selectColumns) $alias = end($table); $table = $table[0]; - // Chek if exists a wildcard with current alias table? + // Check if exists a wildcard with current alias table? if (\in_array($alias, $wildcardTables, true)) { if (!isset($cacheCols[$table])) { $cacheCols[$table] = $this->db->getTableColumns($table); @@ -744,7 +744,7 @@ protected function fixGroupColumns($selectColumns) $table = $matches[1]; $alias = $matches[2] ?? $table; - // Chek if exists a wildcard with current alias table? + // Check if exists a wildcard with current alias table? if (\in_array($alias, $wildcardTables, true)) { if (!isset($cacheCols[$table])) { $cacheCols[$table] = $this->db->getTableColumns($table); diff --git a/src/Sqlsrv/SqlsrvStatement.php b/src/Sqlsrv/SqlsrvStatement.php index e93599fe5..096c7d422 100644 --- a/src/Sqlsrv/SqlsrvStatement.php +++ b/src/Sqlsrv/SqlsrvStatement.php @@ -44,7 +44,7 @@ class SqlsrvStatement implements StatementInterface /** * The default class to use for building object result sets. * - * @var integer + * @var string * @since 2.0.0 */ protected $defaultObjectClass = \stdClass::class; @@ -80,7 +80,7 @@ class SqlsrvStatement implements StatementInterface /** * The prepared statement. * - * @var resource + * @var ?resource * @since 2.0.0 */ protected $statement; @@ -352,7 +352,7 @@ public function errorCode() return $errors[0]['code']; } - return false; + return ''; } /**