diff --git a/composer.json b/composer.json index e7ec2bd..b447c20 100644 --- a/composer.json +++ b/composer.json @@ -23,9 +23,11 @@ "email": "jeroen.pfeil@automattic.com" } ], + "minimum-stability": "dev", + "prefer-stable": true, "require": { "php": ">=7.4", - "wp-cli/wp-cli": "^2.5" + "wp-cli/wp-cli": "^2.13" }, "require-dev": { "wp-cli/wp-cli-tests": "^5.0", diff --git a/features/bootstrap/SQLiteFeatureContext.php b/features/bootstrap/SQLiteFeatureContext.php index 9a07975..0d33a0c 100644 --- a/features/bootstrap/SQLiteFeatureContext.php +++ b/features/bootstrap/SQLiteFeatureContext.php @@ -3,10 +3,9 @@ namespace Automattic\WP_CLI\SQLite; use Behat\Behat\Context\Context; -use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Behat\Gherkin\Node\PyStringNode; use WP_CLI\Tests\Context\FeatureContext as WPCLIFeatureContext; -use SQLite3; +use PDO; use Exception; class SQLiteFeatureContext extends WPCLIFeatureContext implements Context { @@ -25,8 +24,9 @@ public function aSqlDumpFileNamedWithContent( $filename, PyStringNode $content ) */ public function theSqliteDatabaseShouldContainATableNamed( $table_name ) { $this->connectToDatabase(); - $result = $this->db->query( "SELECT name FROM sqlite_master WHERE type='table' AND name='" . $this->db->escapeString( $table_name ) . "'" ); - $row = $result->fetchArray(); + $stmt = $this->db->prepare( "SELECT name FROM sqlite_master WHERE type='table' AND name=?" ); + $stmt->execute( [ $table_name ] ); + $row = $stmt->fetch(); if ( ! $row ) { throw new Exception( "Table '$table_name' not found in the database." ); } @@ -38,8 +38,9 @@ public function theSqliteDatabaseShouldContainATableNamed( $table_name ) { */ public function theTableShouldContainARowWithName( $table_name, $name ) { $this->connectToDatabase(); - $result = $this->db->query( "SELECT * FROM $table_name WHERE name='" . $this->db->escapeString( $name ) . "'" ); - $row = $result->fetchArray(); + $stmt = $this->db->prepare( "SELECT * FROM $table_name WHERE name=?" ); + $stmt->execute( [ $name ] ); + $row = $stmt->fetch(); if ( ! $row ) { throw new Exception( "Row with name '$name' not found in table '$table_name'." ); } @@ -51,14 +52,7 @@ public function theTableShouldContainARowWithName( $table_name, $name ) { public function theSqliteDatabaseShouldContainTheImportedData() { $this->connectToDatabase(); $result = $this->db->query( "SELECT name FROM sqlite_master WHERE type='table'" ); - $tables = []; - while ( true ) { - $row = $result->fetchArray(); - if ( false === $row ) { - break; - } - $tables[] = $row['name']; - } + $tables = $result->fetchAll( PDO::FETCH_COLUMN ); if ( empty( $tables ) ) { throw new Exception( 'No tables found in the database after import.' ); } @@ -78,7 +72,8 @@ private function connectToDatabase() { if ( ! $this->db ) { $run_dir = $this->variables['RUN_DIR']; $db_file = $run_dir . '/wp-content/database/.ht.sqlite'; - $this->db = new SQLite3( $db_file ); + $this->db = new PDO( 'sqlite:' . $db_file ); + $this->db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); } } @@ -105,45 +100,43 @@ protected function create_file( $filename, $content ) { file_put_contents( $full_path, $content ); } - - //// /** * @Given /^the SQLite database contains some sample data$/ */ public function theSqliteDatabaseContainsSomeSampleData() { - $this->connectToDatabase(); - $this->db->exec( - " - INSERT OR REPLACE INTO wp_posts (ID, post_title, post_content, post_type, post_status) - VALUES (1, 'Sample Post', 'This is a sample post content.', 'post', 'publish'); - " - ); - - // Insert or update sample data in wp_users - $this->db->exec( - " - INSERT OR REPLACE INTO wp_users (ID, user_login, user_pass, user_nicename, user_email) - VALUES (1, 'testuser', 'password_hash', 'Test User', 'testuser@example.com'); - " - ); - - // Insert or update sample data in wp_options - $this->db->exec( - " - INSERT OR REPLACE INTO wp_options (option_id, option_name, option_value, autoload) - VALUES - (1, 'siteurl', 'http://example.com', 'yes'), - (2, 'blogname', 'Test Blog', 'yes'), - (3, 'blogdescription', 'Just another WordPress site', 'yes'), - (4, 'users_can_register', '0', 'yes'), - (5, 'admin_email', 'admin@example.com', 'yes'), - (6, 'start_of_week', '1', 'yes'), - (7, 'use_balanceTags', '0', 'yes'), - (8, 'use_smilies', '1', 'yes'), - (9, 'require_name_email', '1', 'yes'), - (10, 'comments_notify', '1', 'yes'); - " - ); + $this->connectToDatabase(); + $this->db->exec( + " + INSERT OR REPLACE INTO wp_posts (ID, post_title, post_content, post_type, post_status) + VALUES (1, 'Sample Post', 'This is a sample post content.', 'post', 'publish'); + " + ); + + // Insert or update sample data in wp_users + $this->db->exec( + " + INSERT OR REPLACE INTO wp_users (ID, user_login, user_pass, user_nicename, user_email) + VALUES (1, 'testuser', 'password_hash', 'Test User', 'testuser@example.com'); + " + ); + + // Insert or update sample data in wp_options + $this->db->exec( + " + INSERT OR REPLACE INTO wp_options (option_id, option_name, option_value, autoload) + VALUES + (1, 'siteurl', 'http://example.com', 'yes'), + (2, 'blogname', 'Test Blog', 'yes'), + (3, 'blogdescription', 'Just another WordPress site', 'yes'), + (4, 'users_can_register', '0', 'yes'), + (5, 'admin_email', 'admin@example.com', 'yes'), + (6, 'start_of_week', '1', 'yes'), + (7, 'use_balanceTags', '0', 'yes'), + (8, 'use_smilies', '1', 'yes'), + (9, 'require_name_email', '1', 'yes'), + (10, 'comments_notify', '1', 'yes'); + " + ); } /** diff --git a/src/SQLiteDatabaseIntegrationLoader.php b/src/SQLiteDatabaseIntegrationLoader.php index 30cda4a..24d28ae 100644 --- a/src/SQLiteDatabaseIntegrationLoader.php +++ b/src/SQLiteDatabaseIntegrationLoader.php @@ -76,20 +76,23 @@ public static function load_plugin() { if ( version_compare( $sqlite_plugin_version, '2.1.11', '<' ) ) { WP_CLI::error( 'The SQLite integration plugin must be version 2.1.11 or higher.' ); } - // Load the translator class from the plugin. if ( ! defined( 'SQLITE_DB_DROPIN_VERSION' ) ) { define( 'SQLITE_DB_DROPIN_VERSION', $sqlite_plugin_version ); // phpcs:ignore } - // We also need to selectively load the necessary classes from the plugin. - require_once $plugin_directory . '/php-polyfills.php'; - require_once $plugin_directory . '/constants.php'; - $new_driver_enabled = defined( 'WP_SQLITE_AST_DRIVER' ) && WP_SQLITE_AST_DRIVER; + $old_structure = file_exists( $plugin_directory . '/php-polyfills.php' ); + + if ( $old_structure ) { + require_once $plugin_directory . '/php-polyfills.php'; + } + require_once $plugin_directory . '/constants.php'; if ( $new_driver_enabled && file_exists( $plugin_directory . '/wp-pdo-mysql-on-sqlite.php' ) ) { require_once $plugin_directory . '/wp-pdo-mysql-on-sqlite.php'; + } elseif ( $new_driver_enabled && file_exists( $plugin_directory . '/wp-includes/database/load.php' ) ) { + require_once $plugin_directory . '/wp-includes/database/load.php'; } elseif ( $new_driver_enabled ) { require_once $plugin_directory . '/version.php'; require_once $plugin_directory . '/wp-includes/parser/class-wp-parser-grammar.php'; @@ -108,11 +111,12 @@ public static function load_plugin() { require_once $plugin_directory . '/wp-includes/sqlite-ast/class-wp-sqlite-information-schema-exception.php'; require_once $plugin_directory . '/wp-includes/sqlite-ast/class-wp-sqlite-information-schema-reconstructor.php'; } else { - require_once $plugin_directory . '/wp-includes/sqlite/class-wp-sqlite-lexer.php'; - require_once $plugin_directory . '/wp-includes/sqlite/class-wp-sqlite-query-rewriter.php'; - require_once $plugin_directory . '/wp-includes/sqlite/class-wp-sqlite-translator.php'; - require_once $plugin_directory . '/wp-includes/sqlite/class-wp-sqlite-token.php'; - require_once $plugin_directory . '/wp-includes/sqlite/class-wp-sqlite-pdo-user-defined-functions.php'; + $sqlite = $plugin_directory . '/wp-includes/sqlite'; + require_once "$sqlite/class-wp-sqlite-lexer.php"; + require_once "$sqlite/class-wp-sqlite-query-rewriter.php"; + require_once "$sqlite/class-wp-sqlite-translator.php"; + require_once "$sqlite/class-wp-sqlite-token.php"; + require_once "$sqlite/class-wp-sqlite-pdo-user-defined-functions.php"; } } }