diff --git a/.gitattributes b/.gitattributes index 7d92ee940d..f7fa86e5fc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,7 +7,6 @@ /gulp-tasks export-ignore /lang export-ignore /tests export-ignore -/vendor/ export-ignore /node_modules export-ignore /.babelrc export-ignore diff --git a/.github/workflows/build-and-tag.yml b/.github/workflows/build-and-tag.yml index 397993c837..2587b42195 100644 --- a/.github/workflows/build-and-tag.yml +++ b/.github/workflows/build-and-tag.yml @@ -12,6 +12,15 @@ jobs: - name: Checkout code uses: actions/checkout@v3 + - name: Set PHP version + uses: shivammathur/setup-php@v2 + with: + php-version: '7.0' # Minimum required version + coverage: none + + - name: composer install + run: composer install --no-dev -o + - name: install node v18 uses: actions/setup-node@v3 with: diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index af19ac02e1..b55e3b21f1 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -1,6 +1,8 @@ name: E2E Test env: + COMPOSER_VERSION: "2" + COMPOSER_CACHE: "${{ github.workspace }}/.composer-cache" NODE_VERSION: "18" NODE_CACHE: "${{ github.workspace }}/node_modules_cache" @@ -37,6 +39,24 @@ jobs: restore-keys: | npm-${{ env.NODE_VERSION }}- + - name: Prepare composer cache + uses: actions/cache@v3 + with: + path: ${{ env.COMPOSER_CACHE }} + key: composer-${{ env.COMPOSER_VERSION }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + composer-${{ env.COMPOSER_VERSION }}- + + - name: Set PHP version + uses: shivammathur/setup-php@v2 + with: + php-version: '7.0' + tools: cs2pr + coverage: none + + - name: composer install + run: composer install --no-dev -o + - name: "Install node v${{ env.NODE_VERSION }}" uses: actions/setup-node@v3 with: @@ -101,6 +121,24 @@ jobs: restore-keys: | npm-${{ env.NODE_VERSION }}- + - name: Prepare composer cache + uses: actions/cache@v3 + with: + path: ${{ env.COMPOSER_CACHE }} + key: composer-${{ env.COMPOSER_VERSION }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + composer-${{ env.COMPOSER_VERSION }}- + + - name: Set PHP version + uses: shivammathur/setup-php@v2 + with: + php-version: '7.0' + tools: cs2pr + coverage: none + + - name: composer install + run: composer install --no-dev -o + - name: "Install node v${{ env.NODE_VERSION }}" uses: actions/setup-node@v3 with: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 53291a1062..085a10d7ad 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -73,12 +73,12 @@ jobs: - name: Set PHP version uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.2' tools: cs2pr coverage: none - name: composer install - run: composer install + run: composer install --ignore-platform-reqs - name: PHPCS check run: './vendor/bin/phpcs . -q --report=checkstyle --runtime-set testVersion 7.0- | cs2pr' diff --git a/.github/workflows/test-build-with-vendor.yml b/.github/workflows/test-build-with-vendor.yml new file mode 100644 index 0000000000..25de677234 --- /dev/null +++ b/.github/workflows/test-build-with-vendor.yml @@ -0,0 +1,49 @@ +name: Build with vendor (test) + +on: + pull_request: + branches: + - develop + - '[0-9].[0-9x]*' # Version branches: 4.x.x, 4.1.x, 5.x + +jobs: + wordpress: + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set PHP version + uses: shivammathur/setup-php@v2 + with: + php-version: '7.0' # Minimum required version + coverage: none + + - name: composer install + run: composer install --no-dev -o + + - name: install node v18 + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Build + run: | + npm ci + npm run build + + - name: Setup + run: 'echo "VERSION=$(grep -Po ''\"version\": \"[0-9\\.]+\"'' package.json | grep -Po ''[0-9\\.]+'')" >> $GITHUB_ENV' + + - name: Zip + run: npm run build:zip + + - name: Make artifacts available + uses: actions/upload-artifact@v3 + with: + name: cypress-artifact + retention-days: 2 + path: | + ${{ github.workspace }}/elasticpress.zip + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6bee75316f..0cbbc6c33f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -55,11 +55,11 @@ jobs: - name: Set PHP version uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.2' coverage: none - name: Install dependencies - run: composer install + run: composer install --ignore-platform-reqs - name: Setup WP Tests run: | @@ -108,11 +108,11 @@ jobs: - name: Set PHP version uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: '8.2' coverage: none - name: Install dependencies - run: composer install + run: composer install --ignore-platform-reqs - name: Setup WP Tests run: | diff --git a/bin/build-zip.sh b/bin/build-zip.sh index fe30ddb247..3e81e8f417 100755 --- a/bin/build-zip.sh +++ b/bin/build-zip.sh @@ -6,4 +6,4 @@ npm run build rm ./elasticpress.zip git archive --output=elasticpress.zip HEAD -zip -ur elasticpress.zip dist +zip -ur elasticpress.zip dist vendor diff --git a/composer.json b/composer.json index fa7c47e825..001ba211fe 100644 --- a/composer.json +++ b/composer.json @@ -29,12 +29,12 @@ ], "require": { "php": ">=7.0", - "composer/installers": "^1.0 || ^2.0" + "composer/installers": "^1.0 || ^2.0", + "psr/container": "^1.0 || ^2.0" }, "require-dev": { "10up/phpcs-composer": "dev-master", "wpackagist-plugin/woocommerce":"*", - "phpunit/phpunit": "^9.5", "phpcompatibility/phpcompatibility-wp": "*", "yoast/phpunit-polyfills": "^1.0" }, @@ -54,6 +54,9 @@ "allow-plugins": { "composer/installers": true, "dealerdirect/phpcodesniffer-composer-installer": true + }, + "platform": { + "php": "7.0" } } } diff --git a/composer.lock b/composer.lock index 369da8a481..f93b16c0e8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,41 +4,43 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ff870c75078541fd7f71487b281ddd46", + "content-hash": "93f6532f7aa0270c6df2f16091b31b4f", "packages": [ { "name": "composer/installers", - "version": "v2.2.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35" + "reference": "d20a64ed3c94748397ff5973488761b22f6d3f19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/c29dc4b93137acb82734f672c37e029dfbd95b35", - "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35", + "url": "https://api.github.com/repos/composer/installers/zipball/d20a64ed3c94748397ff5973488761b22f6d3f19", + "reference": "d20a64ed3c94748397ff5973488761b22f6d3f19", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": "^7.2 || ^8.0" + "composer-plugin-api": "^1.0 || ^2.0" + }, + "replace": { + "roundcube/plugin-installer": "*", + "shama/baton": "*" }, "require-dev": { "composer/composer": "1.6.* || ^2.0", "composer/semver": "^1 || ^3", "phpstan/phpstan": "^0.12.55", "phpstan/phpstan-phpunit": "^0.12.16", - "symfony/phpunit-bridge": "^5.3", - "symfony/process": "^5" + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^2.3" }, "type": "composer-plugin", "extra": { "class": "Composer\\Installers\\Plugin", "branch-alias": { - "dev-main": "2.x-dev" - }, - "plugin-modifies-install-path": true + "dev-main": "1.x-dev" + } }, "autoload": { "psr-4": { @@ -59,6 +61,7 @@ "description": "A multi-framework Composer library installer", "homepage": "https://composer.github.io/installers/", "keywords": [ + "Craft", "Dolibarr", "Eliasis", "Hurad", @@ -79,6 +82,7 @@ "Whmcs", "WolfCMS", "agl", + "aimeos", "annotatecms", "attogram", "bitrix", @@ -97,6 +101,7 @@ "grav", "installer", "itop", + "joomla", "known", "kohana", "laravel", @@ -105,7 +110,6 @@ "magento", "majima", "mako", - "matomo", "mediawiki", "miaoxing", "modulework", @@ -125,7 +129,9 @@ "silverstripe", "sydes", "sylius", + "symfony", "tastyigniter", + "typo3", "wordpress", "yawik", "zend", @@ -133,7 +139,7 @@ ], "support": { "issues": "https://github.com/composer/installers/issues", - "source": "https://github.com/composer/installers/tree/v2.2.0" + "source": "https://github.com/composer/installers/tree/v1.12.0" }, "funding": [ { @@ -149,7 +155,60 @@ "type": "tidelift" } ], - "time": "2022-08-20T06:45:11+00:00" + "time": "2021-09-13T08:19:44+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" + }, + "time": "2017-02-14T16:28:37+00:00" } ], "packages-dev": [ @@ -321,30 +380,30 @@ }, { "name": "doctrine/instantiator", - "version": "1.5.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^11", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { @@ -371,7 +430,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -387,7 +446,7 @@ "type": "tidelift" } ], - "time": "2022-12-30T00:15:36+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "myclabs/deep-copy", @@ -450,16 +509,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.5", + "version": "v4.16.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -500,9 +559,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, - "time": "2023-05-19T20:20:00+00:00" + "time": "2023-06-25T14:52:30+00:00" }, { "name": "phar-io/manifest", @@ -791,16 +850,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.26", + "version": "9.2.27", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", "shasum": "" }, "require": { @@ -856,7 +915,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" }, "funding": [ { @@ -864,7 +924,7 @@ "type": "github" } ], - "time": "2023-03-06T12:58:08+00:00" + "time": "2023-07-26T13:44:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1109,16 +1169,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.8", + "version": "9.6.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", - "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", "shasum": "" }, "require": { @@ -1192,7 +1252,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" }, "funding": [ { @@ -1208,7 +1268,7 @@ "type": "tidelift" } ], - "time": "2023-05-11T05:14:45+00:00" + "time": "2023-07-10T04:04:23+00:00" }, { "name": "sebastian/cli-parser", @@ -2391,15 +2451,15 @@ }, { "name": "wpackagist-plugin/woocommerce", - "version": "7.7.2", + "version": "7.9.0", "source": { "type": "svn", "url": "https://plugins.svn.wordpress.org/woocommerce/", - "reference": "tags/7.7.2" + "reference": "tags/7.9.0" }, "dist": { "type": "zip", - "url": "https://downloads.wordpress.org/plugin/woocommerce.7.7.2.zip" + "url": "https://downloads.wordpress.org/plugin/woocommerce.7.9.0.zip" }, "require": { "composer/installers": "^1.0 || ^2.0" @@ -2479,5 +2539,8 @@ "php": ">=7.0" }, "platform-dev": [], + "platform-overrides": { + "php": "7.0" + }, "plugin-api-version": "2.3.0" } diff --git a/elasticpress.php b/elasticpress.php index afd0d1335b..9a3bd39874 100644 --- a/elasticpress.php +++ b/elasticpress.php @@ -29,6 +29,11 @@ exit; // Exit if accessed directly. } +// Require Composer autoloader if it exists. +if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) { + require_once __DIR__ . '/vendor/autoload.php'; +} + define( 'EP_URL', plugin_dir_url( __FILE__ ) ); define( 'EP_PATH', plugin_dir_path( __FILE__ ) ); define( 'EP_FILE', plugin_basename( __FILE__ ) ); @@ -88,14 +93,28 @@ function( $class ) { define( 'EP_IS_NETWORK', true ); } +/** + * Return the ElasticPress container + * + * @since 4.7.0 + * @return Container + */ +function get_container() { + static $container = null; + + if ( ! $container ) { + $container = new Container(); + } + + return $container; +} + /** * Sets up the indexables and features. * * @return void */ function register_indexable_posts() { - global $wp_version; - /** * Handle indexables */ @@ -186,9 +205,7 @@ function register_indexable_posts() { * @return {QueryLogger} New query logger */ $query_logger = apply_filters( 'ep_query_logger', new \ElasticPress\QueryLogger() ); - if ( method_exists( $query_logger, 'setup' ) ) { - $query_logger->setup(); - } + get_container()->set( '\ElasticPress\QueryLogger', $query_logger, true ); } add_action( 'plugins_loaded', __NAMESPACE__ . '\register_indexable_posts' ); diff --git a/includes/classes/Container.php b/includes/classes/Container.php new file mode 100644 index 0000000000..61b67ee918 --- /dev/null +++ b/includes/classes/Container.php @@ -0,0 +1,84 @@ + + */ + private $instances = []; + + /** + * Finds an entry of the container by its identifier and returns it. + * + * @param string $id Identifier of the entry to look for. + * + * @throws NotFoundException No entry was found for **this** identifier. + * + * @return mixed Entry. + */ + public function get( $id ) { + if ( ! isset( $this->instances[ $id ] ) ) { + throw new NotFoundException( 'Class not found' ); + } + + return $this->instances[ $id ]; + } + + /** + * Returns true if the container can return an entry for the given identifier. + * Returns false otherwise. + * + * @param string $id Identifier of the entry to look for. + * + * @return bool + */ + public function has( $id ) : bool { + return isset( $this->instances[ $id ] ); + } + + /** + * Register an instance. + * + * @param string $id Identifier of the entry. + * @param object $instance The new instance. + * @param boolean $setup Whether the setup() method should be called or not. + * @return object The instance. + */ + public function set( string $id, $instance, bool $setup = false ) { + /** + * Filter an instance before it is added to the container + * + * @since 4.7.0 + * @hook ep_container_set + * @param {object} $instance Object instance + * @param {string} $id Id + * @return {object} New object + */ + $instance = apply_filters( 'ep_container_set', $instance, $id ); + + $this->instances[ $id ] = $instance; + + if ( $setup && method_exists( $instance, 'setup' ) ) { + $instance->setup(); + } + + return $instance; + } +} diff --git a/includes/classes/Exception/NotFoundException.php b/includes/classes/Exception/NotFoundException.php new file mode 100644 index 0000000000..96ce89507a --- /dev/null +++ b/includes/classes/Exception/NotFoundException.php @@ -0,0 +1,16 @@ +get( '\ElasticPress\QueryLogger' ); if ( $query_logger ) { $reports['failed-queries'] = new \ElasticPress\StatusReport\FailedQueries( $query_logger ); diff --git a/tests/php/TestContainer.php b/tests/php/TestContainer.php new file mode 100644 index 0000000000..aaa9f91868 --- /dev/null +++ b/tests/php/TestContainer.php @@ -0,0 +1,92 @@ +set( 'present', $new_object ); + + $this->assertSame( $new_object, $container->get( 'present' ) ); + + $this->expectException( '\Psr\Container\NotFoundExceptionInterface' ); + $container->get( 'absent' ); + } + + /** + * Test the `has` method + * + * @group container + */ + public function test_has() { + $container = new Container(); + + $new_object = new \stdClass(); + $container->set( 'present', $new_object ); + + $this->assertTrue( $container->has( 'present' ) ); + $this->assertFalse( $container->has( 'absent' ) ); + } + + /** + * Test the `set` method + * + * @group container + */ + public function test_set() { + $mock = $this->getMockBuilder( \stdClass::class ) + ->addMethods( [ 'setup' ] ) + ->getMock(); + + $mock->expects( $this->exactly( 1 ) )->method( 'setup' ); + + $container = new Container(); + + $container->set( 'mock', $mock ); + $container->set( 'mock', $mock, true ); + + $this->assertSame( $mock, $container->get( 'mock' ) ); + } + + /** + * Test the `ep_container_set` filter + * + * @group container + */ + public function test_set_ep_container_set_filter() { + $mock = $this->getMockBuilder( \stdClass::class ) + ->addMethods( [ 'setup' ] ) + ->getMock(); + + $container = new Container(); + $object = new \stdClass(); + + $change_instance = function ( $instance, $id ) use ( $mock, $object ) { + $this->assertSame( 'mock', $id ); + $this->assertSame( $instance, $object ); + return $mock; + }; + add_filter( 'ep_container_set', $change_instance, 10, 2 ); + + $container->set( 'mock', $object ); + $this->assertSame( $mock, $container->get( 'mock' ) ); + } +} diff --git a/tests/php/TestElasticPress.php b/tests/php/TestElasticPress.php new file mode 100644 index 0000000000..ee91eda14d --- /dev/null +++ b/tests/php/TestElasticPress.php @@ -0,0 +1,28 @@ +assertInstanceOf( '\ElasticPress\Container', $container ); + + // Calling it again should return the same instance + $this->assertSame( $container, \ElasticPress\get_container() ); + } +}