diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..a612c0c5a35974f06e09e2d4d36bfed37630805b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +tests/ export-ignore +vendor/ export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.git/ export-ignore +.gitlab-ci.yml export-ignore +.idea export-ignore +apigen.neon export-ignore +build-coverage/ export-ignore +docs/ export-ignore +LICENSE.md export-ignore +phpcs.xml.dist export-ignore +phpunit-integration.xml export-ignore +phpunit-unit.xml export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4b86223d6cae8ddb86d7cc3d12e0fcca43717f54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/vendor/ +.idea +composer.lock +build-coverage +swagger \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..38447e9e09d3e045220f8589039a98f7368dba3b --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,9 @@ +variables: + DISABLE_FUNCTIONAL: 1 + DISABLE_ACCEPTANCE: 1 + DISABLE_PHP_5_5: 1 + DISABLE_CODECEPTION: 1 + DISABLE_INTEGRATION_TESTS: 1 + IS_LIBRARY: 1 + +include: 'https://gitlab.com/wpdesk/gitlab-ci/raw/master/gitlab-ci-1.2.yml' diff --git a/README.md b/README.md index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2afdc49ebcf29121e32571ba862a760ae34de543 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,54 @@ +[](https://gitlab.com/wpdesk/wp-show-decision/pipelines) +[](https://gitlab.com/wpdesk/wp-show-decision/commits/master) +[](https://packagist.org/packages/wpdesk/wp-show-decision) +[](https://packagist.org/packages/wpdesk/wp-show-decision) +[](https://packagist.org/packages/wpdesk/wp-show-decision) +[](https://packagist.org/packages/wpdesk/wp-show-decision) + +WordPress Library for Decision whether to show something. +=================================================== +Idea is that you have ShouldShowStrategy interface with one bool method. Thanks to this you can create a class that +delegates decision whether to show something. Your class does not have to hardcode that decision. + +## Requirements + +PHP 5.6 or later. + +## Composer + +You can install the bindings via [Composer](http://getcomposer.org/). Run the following command: + +```bash +composer require --dev wpdesk/wp-show-decision +``` + +To use the bindings, use Composer's [autoload](https://getcomposer.org/doc/01-basic-usage.md#autoloading): + +```php +require_once 'vendor/autoload.php'; +``` + +## Usage + +```php + new Beacon( + '6057086f-4b25-4e12-8735-fbc556d2dc01', + new PostTypeStrategy('automation'), + $this->get_plugin_assets_url() +``` + +```php + if ( is_admin() ) { + ( new RateNotices( + [ new TwoWeeksNotice( $this->plugin_url . '/assets', new PostTypeStrategy([ + [ 'page' => 'x', 'name' => 'stefan' ], // show when page = x and name = stefan + [ 'page' => 'y' ] // OR when page = y + ] ) ) ] + ) )->hooks(); + } +``` + + +## Project documentation + +PHPDoc: https://wpdesk.gitlab.io/wp-show-decision/index.html \ No newline at end of file diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000000000000000000000000000000000000..8531c034488faafdf5b4bd890e424a615b5234b9 --- /dev/null +++ b/changelog.txt @@ -0,0 +1 @@ +* First release diff --git a/composer.json b/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..667851ae2627f9638401ce784c8da4a495170c48 --- /dev/null +++ b/composer.json @@ -0,0 +1,34 @@ +{ + "name": "wpdesk/wp-show-decision", + "authors": [ + { + "name": "Krzysiek", + "email": "krzysiek@wpdesk.pl" + } + ], + "require": { + "php": ">=5.6", + "ext-curl": "*", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "<7", + "wp-coding-standards/wpcs": "^0.14.1", + "squizlabs/php_codesniffer": "^3.0.2", + "mockery/mockery": "*", + "10up/wp_mock": "*" + }, + "autoload": { + "psr-4": { + "WPDesk\\ShowDecision\\": "src/" + } + }, + "autoload-dev": { + }, + "scripts": { + "phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never", + "phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage", + "phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never", + "phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage" + } +} diff --git a/phpunit-integration.xml b/phpunit-integration.xml new file mode 100644 index 0000000000000000000000000000000000000000..4a342abf125d638d044bafa01cd9a75a771b4b3d --- /dev/null +++ b/phpunit-integration.xml @@ -0,0 +1,28 @@ +<phpunit bootstrap="tests/integration/bootstrap.php" + backupGlobals="false" + > + <testsuites> + <testsuite> + <directory prefix="Test" suffix=".php">./tests/integration</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory suffix=".php">src</directory> + </whitelist> + </filter> + + <logging> + <log type="junit" target="build-coverage/report.junit.xml"/> + <log type="coverage-html" target="build-coverage/coverage" charset="UTF-8" yui="true" highlight="true"/> + <log type="coverage-text" target="build-coverage/coverage.txt"/> + <log type="coverage-clover" target="build-coverage/clover.xml"/> + </logging> + + <php> + <env name="WP_DEVELOP_DIR" value="/tmp/wordpress-develop"/> + <env name="WC_DEVELOP_DIR" value="/tmp/woocommerce"/> + </php> + +</phpunit> \ No newline at end of file diff --git a/phpunit-unit.xml b/phpunit-unit.xml new file mode 100644 index 0000000000000000000000000000000000000000..31e5c9f9c202769cac9487ac192f331e827c9489 --- /dev/null +++ b/phpunit-unit.xml @@ -0,0 +1,21 @@ +<phpunit bootstrap="tests/unit/bootstrap.php"> + <testsuites> + <testsuite> + <directory prefix="Test" suffix=".php">./tests/unit/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory suffix=".php">src</directory> + </whitelist> + </filter> + + <logging> + <log type="junit" target="build-coverage/report.junit.xml"/> + <log type="coverage-html" target="build-coverage/coverage" charset="UTF-8" yui="true" highlight="true"/> + <log type="coverage-text" target="build-coverage/coverage.txt"/> + <log type="coverage-clover" target="build-coverage/clover.xml"/> + </logging> + +</phpunit> diff --git a/src/GetStrategy.php b/src/GetStrategy.php new file mode 100644 index 0000000000000000000000000000000000000000..b22ac9291b9401b1f3a74accef677a54c3da51b1 --- /dev/null +++ b/src/GetStrategy.php @@ -0,0 +1,44 @@ +<?php + +namespace WPDesk\ShowDecision; + +/** + * Show when some conditions with $_GET are meet. + */ +class GetStrategy implements ShouldShowStrategy { + /** + * @var array + */ + private $conditions; + + /** + * @param array $conditions Whether to show on the page or not. Array of arrays with condition for _GET. + * + * Inner arrays mean AND, outer arrays mean OR conditions. + * + * ie. [ [ .. and .. and ..] or [ .. and .. and ..] or .. ] + * + */ + public function __construct( array $conditions ) { + $this->conditions = $conditions; + } + + /** + * @return bool + */ + public function shouldDisplay() { + foreach ( $this->conditions as $or_conditions ) { + $display = true; + foreach ( $or_conditions as $parameter => $value ) { + if ( ! isset( $_GET[ $parameter ] ) || $_GET[ $parameter ] !== $value ) { + $display = false; + } + } + if ( $display ) { + return $display; + } + } + + return false; + } +} diff --git a/src/PostTypeStrategy.php b/src/PostTypeStrategy.php new file mode 100644 index 0000000000000000000000000000000000000000..fe768f1ada86e85ec6fa3d94cd2e6a01de15b637 --- /dev/null +++ b/src/PostTypeStrategy.php @@ -0,0 +1,39 @@ +<?php + +namespace WPDesk\ShowDecision; + +/** + * Show when pages associated with given post type is displayed. + */ +class PostTypeStrategy implements ShouldShowStrategy { + /** @var string */ + private $post_type; + + public function __construct( $post_type ) { + $this->post_type = $post_type; + } + + /** + * Should Beacon be visible? + * + * @return bool + */ + public function shouldDisplay() { + return $this->is_current_post_type_automation() || + ( isset( $_GET['post_type'] ) && $_GET['post_type'] === $this->post_type ); + } + + /** + * @return bool + */ + private function is_current_post_type_automation() { + if ( isset( $_GET['post'] ) ) { + $post = get_post( (int) $_GET['post'] ); + if ( $post instanceof \WP_Post ) { + return $post->post_type === $this->post_type; + } + } + + return false; + } +} diff --git a/src/ShouldShowStrategy.php b/src/ShouldShowStrategy.php new file mode 100644 index 0000000000000000000000000000000000000000..c957cd0d444e6456ca48779b8b05efa81849b4c2 --- /dev/null +++ b/src/ShouldShowStrategy.php @@ -0,0 +1,13 @@ +<?php + +namespace WPDesk\ShowDecision; + +/** + * Should something be shown? + */ +interface ShouldShowStrategy { + /** + * @return bool + */ + public function shouldDisplay(); +} diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2a86b036f682ed318b27b028d2e96dfcd5979afd --- /dev/null +++ b/tests/docker-compose.yaml @@ -0,0 +1,172 @@ +version: '2.0' + +services: + + wordpress: + image: wpdesknet/phpunit-woocommerce:0-0 + volumes: + - .././:/opt/project + depends_on: + - mysql0 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql0 + + wordpress-0-1: + image: wpdesknet/phpunit-woocommerce:0-1 + volumes: + - .././:/opt/project + depends_on: + - mysql1 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql1 + + wordpress-0-2: + image: wpdesknet/phpunit-woocommerce:0-2 + volumes: + - .././:/opt/project + depends_on: + - mysql2 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql2 + + wordpress-0-3: + image: wpdesknet/phpunit-woocommerce:0-3 + volumes: + - .././:/opt/project + depends_on: + - mysql3 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql3 + + wordpress-0-4: + image: wpdesknet/phpunit-woocommerce:0-4 + volumes: + - .././:/opt/project + depends_on: + - mysql4 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql4 + + wordpress-0-5: + image: wpdesknet/phpunit-woocommerce:0-5 + volumes: + - .././:/opt/project + depends_on: + - mysql5 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql5 + + wordpress-1-0: + image: wpdesknet/phpunit-woocommerce:1-0 + volumes: + - .././:/opt/project + depends_on: + - mysql0 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql0 + + wordpress-2-0: + image: wpdesknet/phpunit-woocommerce:2-0 + volumes: + - .././:/opt/project + depends_on: + - mysql0 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql0 + + wordpress-3-0: + image: wpdesknet/phpunit-woocommerce:3-0 + volumes: + - .././:/opt/project + depends_on: + - mysql0 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql0 + + wordpress-4-0: + image: wpdesknet/phpunit-woocommerce:4-0 + volumes: + - .././:/opt/project + depends_on: + - mysql0 + environment: + WORDPRESS_DB_NAME: wptest + WORDPRESS_DB_USER: mysql + WORDPRESS_DB_PASSWORD: mysql + WORDPRESS_DB_HOST: mysql0 + + mysql0: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: mysql + MYSQL_DATABASE: wptest + MYSQL_USER: mysql + MYSQL_PASSWORD: mysql + + mysql1: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: mysql + MYSQL_DATABASE: wptest + MYSQL_USER: mysql + MYSQL_PASSWORD: mysql + + mysql2: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: mysql + MYSQL_DATABASE: wptest + MYSQL_USER: mysql + MYSQL_PASSWORD: mysql + + mysql3: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: mysql + MYSQL_DATABASE: wptest + MYSQL_USER: mysql + MYSQL_PASSWORD: mysql + + mysql4: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: mysql + MYSQL_DATABASE: wptest + MYSQL_USER: mysql + MYSQL_PASSWORD: mysql + + mysql5: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: mysql + MYSQL_DATABASE: wptest + MYSQL_USER: mysql + MYSQL_PASSWORD: mysql + diff --git a/tests/integration/bootstrap.php b/tests/integration/bootstrap.php new file mode 100644 index 0000000000000000000000000000000000000000..a422fd9c7fea652a15b2aced0b2e6134a5590201 --- /dev/null +++ b/tests/integration/bootstrap.php @@ -0,0 +1,28 @@ +<?php + +ini_set('error_reporting', E_ALL); // or error_reporting(E_ALL); +ini_set('display_errors', '1'); +ini_set('display_startup_errors', '1'); + +require_once __DIR__ . '/../../vendor/autoload.php'; + +// disable xdebug backtrace +if ( function_exists( 'xdebug_disable' ) ) { + xdebug_disable(); +} + +if ( getenv( 'PLUGIN_PATH' ) !== false ) { + define( 'PLUGIN_PATH', getenv( 'PLUGIN_PATH' ) ); +} else { + define( 'PLUGIN_PATH', __DIR__ . DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR ); +} + +require_once( getenv( 'WP_DEVELOP_DIR' ) . '/tests/phpunit/includes/functions.php' ); + +tests_add_filter( 'muplugins_loaded', function () { +}, 100 ); + +putenv('WP_TESTS_DIR=' . getenv( 'WP_DEVELOP_DIR' ) . '/tests/phpunit'); +require_once( getenv( 'WC_DEVELOP_DIR' ) . '/tests/bootstrap.php' ); + +do_action('plugins_loaded'); \ No newline at end of file diff --git a/tests/unit/Stub/WP_Post.php b/tests/unit/Stub/WP_Post.php new file mode 100644 index 0000000000000000000000000000000000000000..bba4f366d9ee04ea1002cbf4541411407c5e1315 --- /dev/null +++ b/tests/unit/Stub/WP_Post.php @@ -0,0 +1,6 @@ +<?php + +class WP_Post { + public $ID; + public $post_type; +} \ No newline at end of file diff --git a/tests/unit/TestGetStrategy.php b/tests/unit/TestGetStrategy.php new file mode 100644 index 0000000000000000000000000000000000000000..7da82b56f829de2cb217d7a431d48da852c6cd31 --- /dev/null +++ b/tests/unit/TestGetStrategy.php @@ -0,0 +1,83 @@ +<?php + +namespace unit; + +use PHPUnit\Framework\TestCase; +use WPDesk\ShowDecision\GetStrategy; + +class TestGetStrategy extends TestCase { + const true_1 = [ 'a' => '1' ]; + const true_2 = [ 'b' => '2' ]; + const true_3 = [ 'c' => '3' ]; + + const false_1 = [ 'x' => '1' ]; + const false_2 = [ 'y' => '2' ]; + + /** + * Prepares $_GET with true clauses + */ + private function prepare_get() { + $_GET = [ + self::true_1, + self::true_2, + self::true_3 + ]; + } + + protected function setUp() { + parent::setUp(); + $this->prepare_get(); + } + + public function testAndClausesFailure() { + $strategy = new GetStrategy( [ + [ + self::true_1, + self::false_1 + ] + ] ); + $this->assertFalse( $strategy->shouldDisplay() ); + } + + public function testAndClausesSuccess() { + $strategy = new GetStrategy( [ + [ + self::true_1, + self::true_2, + self::true_3 + ] + ] ); + $this->assertTrue( $strategy->shouldDisplay() ); + } + + public function testOrClausesSuccess() { + $strategy = new GetStrategy( [ + [ + self::true_1, + self::false_1 + ], + [ + self::true_1, + self::true_2 + ] + ] ); + $this->assertTrue( $strategy->shouldDisplay() ); + } + + public function testOrClausesFailure() { + $strategy = new GetStrategy( [ + [ + self::true_1, + self::false_1 + ], + [ + self::true_1, + self::true_2, + self::true_3, + self::false_1 + ] + ] ); + $this->assertFalse( $strategy->shouldDisplay() ); + } + +} diff --git a/tests/unit/TestPostTypeStrategy.php b/tests/unit/TestPostTypeStrategy.php new file mode 100644 index 0000000000000000000000000000000000000000..31eb4caa0bbee85a50bf06945b4c58e3b221ab92 --- /dev/null +++ b/tests/unit/TestPostTypeStrategy.php @@ -0,0 +1,55 @@ +<?php + +namespace unit; + +use PHPUnit\Framework\TestCase; +use WPDesk\ShowDecision\PostTypeStrategy; + + +class TestPostTypeStrategy extends TestCase { + const valid_post_type = 'test_post_type'; + const invalid_post_type = 'invalid'; + + protected function setUp() { + require_once __DIR__ . DIRECTORY_SEPARATOR . 'Stub' . DIRECTORY_SEPARATOR . 'WP_Post.php'; + parent::setUp(); + \WP_Mock::setUp(); + } + + protected function tearDown() { + parent::tearDown(); + \WP_Mock::tearDown(); + } + + public function testFailureWhenTriesUseInvalidPostType() { + $strategy = new PostTypeStrategy( self::invalid_post_type ); + $this->assertFalse( $strategy->shouldDisplay() ); + } + + public function testValidPostTypeUsingGetSuccess() { + $_GET = [ 'post_type' => self::valid_post_type ]; + $strategy = new PostTypeStrategy( self::valid_post_type ); + $this->assertTrue( $strategy->shouldDisplay() ); + } + + public function testValidPostTypeUsingPostIdSuccess() { + $post_id = 123; + $_GET = [ + 'post' => $post_id + ]; + \WP_Mock::userFunction( 'get_post', [ + 'times' => 1, + 'return' => function () use ( $post_id ) { + $post = new \WP_Post(); + $post->ID = $post_id; + $post->post_type = self::valid_post_type; + + return $post; + } + ] ); + + $strategy = new PostTypeStrategy( self::valid_post_type ); + $this->assertTrue( $strategy->shouldDisplay() ); + } + +} diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php new file mode 100644 index 0000000000000000000000000000000000000000..76b8109582ae17560b77a6e0499b232e09047810 --- /dev/null +++ b/tests/unit/bootstrap.php @@ -0,0 +1,9 @@ +<?php +/** + * PHPUnit bootstrap file + */ + +require_once __DIR__ . '/../../vendor/autoload.php'; + +WP_Mock::setUsePatchwork( true ); +WP_Mock::bootstrap();