diff --git a/README.md b/README.md index 880b50a..e894347 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # catalogs-php A PHP framework to talk to Catalogs. Part of the [CloudFest 2024 Hackathon](https://hackathon.cloudfest.com/project/integrating-mariadb-catalogs-with-php-platforms/). +![Build status](https://github.com/MariaDB/catalogs-php/actions/workflows/test.yml/badge.svg?branch=main) + # Installation Include the catalog-php with composer: @@ -15,8 +17,12 @@ Include autoloader in your project. create('wp_1'); -$cat->createAdminUserForCatalog('wp_1', 'admin', 'adminpassword', '%'); +$cat = new CatalogManager('127.0.0.1', 3306, 'root', 'rootpassword'); +$catPort = $cat->create('wp_2'); +$cat->createAdminUserForCatalog('wp_2', 'admin', 'adminpassword', '%'); // Using PDO, Create a DB and user in the collection using the $catPort. // Set DB_NAME with the "name:$catPort" diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 8ed79a5..b58f901 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -14,6 +14,12 @@ + + + + + + diff --git a/src/Catalog.php b/src/CatalogManager.php similarity index 76% rename from src/Catalog.php rename to src/CatalogManager.php index d4f5850..0877943 100644 --- a/src/Catalog.php +++ b/src/CatalogManager.php @@ -9,7 +9,7 @@ * * @package Mariadb\CatalogsPHP */ -class Catalog +class CatalogManager { /** * The connection to the MariaDB server. @@ -18,6 +18,15 @@ class Catalog */ private $connection; + // Prepared statements with the USE CATALOG command are not working as expected. + // This method is used to check the catalog name before using it in a query. + private function checkCatalogName($catalogName): void + { + if (preg_match('/[^a-zA-Z0-9_]/', $catalogName) === 1) { + throw new CatalogManagerException('Invalid catalog name'); + } + } + // This is too low, because this is a beta version we are developing for. public const MINIMAL_MARIA_VERSION = '11.0.2'; @@ -39,7 +48,7 @@ class Catalog * @param \PDO|null $pdo Optional. An existing PDO connection to use. Default is null. * * @throws PDOException If a PDO error occurs during the connection attempt. - * @throws Exception If a general error occurs during instantiation. + * @throws CatalogManagerException If a general error occurs during instantiation. */ public function __construct( protected string $dbHost = 'localhost', @@ -71,7 +80,7 @@ public function __construct( $version = $versionQuery->fetchColumn(); if (version_compare($version, self::MINIMAL_MARIA_VERSION, '<') === true) { - throw new Exception( + throw new CatalogManagerException( 'The MariaDB version is too low. The minimal version is ' . self::MINIMAL_MARIA_VERSION ); } @@ -86,28 +95,29 @@ public function __construct( /** * Create a new catalog * - * @param string $catName The new Catalog name. + * @param string $catalogName The new Catalog name. * * @return int */ - public function create(string $catName): int + public function create(string $catalogName): int { // Check if the Catalog name is valid. - if (in_array($catName, array_keys($this->list())) === true) { - throw new Exception('Catalog name already exists.'); + if (in_array($catalogName, array_keys($this->list())) === true) { + throw new CatalogManagerException('Catalog name already exists.'); } $rootPrivileges = $this->connection->query("SELECT * FROM mysql.global_priv WHERE User='{$this->dbUser}' AND Host='%';"); $scripts = [ - 'src/create_catalog_sql/mysql_system_tables.sql', - 'src/create_catalog_sql/mysql_performance_tables.sql', - 'src/create_catalog_sql/mysql_system_tables_data.sql', - 'src/create_catalog_sql/maria_add_gis_sp.sql', - 'src/create_catalog_sql/mysql_sys_schema.sql', + __DIR__ . '/create_catalog_sql/mysql_system_tables.sql', + __DIR__ . '/create_catalog_sql/mysql_performance_tables.sql', + __DIR__ . '/create_catalog_sql/mysql_system_tables_data.sql', + __DIR__ . '/create_catalog_sql/maria_add_gis_sp.sql', + __DIR__ . '/create_catalog_sql/mysql_sys_schema.sql', ]; - $this->connection->exec('CREATE CATALOG IF NOT EXISTS ' . $catName); - $this->connection->exec('USE CATALOG ' . $catName); + $this->checkCatalogName($catalogName); + $this->connection->exec('CREATE CATALOG IF NOT EXISTS ' . $catalogName); + $this->connection->exec('USE CATALOG ' . $catalogName); $this->connection->exec('CREATE DATABASE IF NOT EXISTS mysql'); $this->connection->exec('USE mysql'); @@ -139,18 +149,18 @@ public function create(string $catName): int } } - return $this->getPort($catName); + return $this->getPort($catalogName); } /** * Get the port of a catalog. * - * @param string $catName The catalog name. + * @param string $catalogName The catalog name. * * @return int */ - public function getPort(string $catName): int + public function getPort(string $catalogName): int { // TODO: wait for the functionality to be implemented in the server. return ($this->dbPort ?? 0); @@ -179,24 +189,25 @@ public function list(): array /** * Drop a catalog. * - * @param string $catName The catalog name. + * @param string $catalogName The catalog name. * * @return void * * @throws PDOException If a PDO error occurs during the catalog drop attempt. - * @throws Exception If a general error occurs during catalog drop. + * @throws CatalogManagerException If a general error occurs during catalog drop. */ - public function drop(string $catName): bool + public function drop(string $catalogName): bool { try { // Enter the catalog. - $this->connection->exec('USE CATALOG ' . $catName); + $this->checkCatalogName($catalogName); + $this->connection->exec('USE CATALOG ' . $catalogName); // Check if there are any tables besides mysql, sys, performance_schema and information_schema. $tables = $this->connection->query('SHOW DATABASES'); foreach ($tables as $table) { if (in_array($table['Database'], ['mysql', 'sys', 'performance_schema', 'information_schema']) === false) { - throw new \Exception('Catalog is not empty'); + throw new CatalogManagerException('Catalog is not empty'); } } @@ -206,9 +217,9 @@ public function drop(string $catName): bool $this->connection->exec('DROP DATABASE IF EXISTS performance_schema'); // Drop the catalog. - $this->connection->exec('DROP CATALOG ' . $catName); + $this->connection->exec('DROP CATALOG ' . $catalogName); } catch (\PDOException $e) { - throw new \Exception('Error dropping catalog: ' . $e->getMessage()); + throw new CatalogManagerException('Error dropping catalog: ' . $e->getMessage()); } return true; @@ -231,7 +242,7 @@ private function alter() /** * Create admin user for a catalog * - * @param string $catalog The catalog name + * @param string $catalogName The catalog name * @param string $userName The user name * @param string $password The user password * @param string $authHost The database host @@ -239,16 +250,17 @@ private function alter() * @return void */ public function createAdminUserForCatalog( - string $catalog, + string $catalogName, string $userName, string $password, string $authHost = 'localhost' ): void { - $this->connection->exec("USE CATALOG {$catalog}"); + $this->checkCatalogName($catalogName); + $this->connection->exec("USE CATALOG {$catalogName}"); $this->connection->exec("USE mysql"); $this->connection = new \PDO( - "mysql:host={$this->dbHost};port={$this->dbPort};dbname={$catalog}.mysql", + "mysql:host={$this->dbHost};port={$this->dbPort};dbname={$catalogName}.mysql", $this->dbUser, $this->dbPass, $this->dbOptions diff --git a/src/Exception.php b/src/CatalogManagerException.php similarity index 96% rename from src/Exception.php rename to src/CatalogManagerException.php index b56f340..4d9a0f2 100644 --- a/src/Exception.php +++ b/src/CatalogManagerException.php @@ -12,7 +12,7 @@ * * @package Mariadb\CatalogsPHP */ -class Exception extends \Exception +class CatalogManagerException extends \Exception { /** * Constructs the Exception. diff --git a/tests/CatalogTest.php b/tests/CatalogTest.php index e86afa9..8633c7e 100644 --- a/tests/CatalogTest.php +++ b/tests/CatalogTest.php @@ -2,23 +2,41 @@ namespace Mariadb\CatalogsPHP\Tests; -use Mariadb\CatalogsPHP\Catalog; +use Mariadb\CatalogsPHP\CatalogManager; use PHPUnit\Framework\TestCase; +/** + * Class PDOStatementMock + * + * A mock for the PDOStatement class + */ class CatalogTest extends TestCase { + /** + * @var CatalogManager $catalog The Catalog instance to test + */ private $catalog; + + /** + * @var \PDO $pdoMock The PDO mock to inject into the Catalog instance + */ private $pdoMock; + /** + * Set up the test + */ protected function setUp(): void { // Create a mock for the PDO class $this->pdoMock = $this->createMock(\PDO::class); // Inject the PDO mock into your Catalog class - $this->catalog = new Catalog('localhost', 3306, 'root', '', null, $this->pdoMock); + $this->catalog = new CatalogManager('localhost', 3306, 'root', '', null, $this->pdoMock); } + /** + * Test the list method + */ public function testList() { // Mock the PDOStatement for the 'SHOW CATALOGS' query @@ -42,12 +60,18 @@ public function testList() ], $catalogs); } + /** + * Test the getPort method + */ public function testGetPort() { $port = $this->catalog->getPort('test'); $this->assertEquals(3306, $port); } + /** + * Test the create method + */ public function testCreate() { // Configure the PDO mock to return the PDOStatement mock for the 'SHOW CATALOGS' query