diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a18b435 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto + +.gitattributes export-ignore +.gitignore export-ignore +composer.json export-ignore +/spec export-ignore diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..56466ba --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +language: php +dist: trusty +php: +- '7.1' +- '7.0' +- '5.6' +- '5.5' +- '5.4' + +matrix: + fast_finish: true + include: + - php: 5.2 + dist: precise + - php: 5.3 + dist: precise + + +install: +- phpenv local 5.6 +- composer selfupdate 1.0.0 --no-interaction +- composer install --no-interaction +- if [[ "$TRAVIS_PHP_VERSION" == "5.2" ]]; then composer remove --dev phpunit/phpunit; fi +- phpenv local --unset + +script: +- if [[ "$TRAVIS_PHP_VERSION" == "5.2" ]]; then phpunit; else ./vendor/bin/phpunit; fi diff --git a/README.md b/README.md index 62d8dc5..970a9b7 100644 --- a/README.md +++ b/README.md @@ -8,39 +8,66 @@ We recommend installing the library using [Composer](https://getcomposer.org/), composer require wpupdatephp/wp-update-php ``` -Another option is to download the [class file](https://github.com/WPupdatePHP/wp-update-php/blob/master/src/WPUpdatePhp.php) manually. +To prevent collisions, you can install this library inside your own prefixed class names (eg `CJ_WPUpdatePhp`), using [Mozart](https://github.com/coenjacobs/mozart) and we **highly recommend doing this** as it's currently the only way to prevent hard to debug conflicts. ## Usage -Usage of this library depends on how you start your plugin. The core `does_it_meet_required_php_version` method does all the checking for you and adds an admin notice in case the version requirement is not met. +Usage of this library depends on how you start your plugin. The core `check()` method does all the checking for you. You can output an admin notice in case the version requirement is not met. -For example, when you start your plugin by instantiating a new object, you should wrap a conditional check around it. +For example, when you start your plugin by instantiating a new object, you should wrap a conditional check around it. _Example:_ ```php -$updatePhp = new WPUpdatePhp( '5.4.0' ); - -if ( $updatePhp->does_it_meet_required_php_version() ) { +$arguments = array( + 'php' => array( + array( + 'version' => '7.0.0', + 'required' => false, + ), + array( + 'version' => '5.6.0', + 'required' => true, + ), + ), +); +$updatePhp = new WPUpdatePhp( 'Plugin Name', $arguments ); +$updatePhp->check(); + +if ( $updatePhp->passes() ) { // Instantiate new object here } -// The version check has failed, an admin notice has been thrown +// The version check has failed, an admin notice can be shown ``` -## Including the library file -Adding the library via Composer has preference. The Composer autoloader will automatically take care of preventing including two classes with the same name. - -In case you want to include the file manually, please wrap the include or require call in a [`class_exists`](http://php.net/class_exists) conditional, like so: +## Available arguments +The full list of available arguments: ```php -if ( ! class_exists( 'WPUpdatePhp' ) ) { - // do the file include or require here -} +$arguments = array( + 'wordpress' => array( + array( + 'version' => '3.7.1', + 'required' => false, + ), + array( + 'version' => '3.5.0', + 'required' => true, + ), + ), + 'php' => array( + array( + 'version' => '7.0.0', + 'required' => false, + ), + array( + 'version' => '5.6.0', + 'required' => true, + ), + ), +); ``` -## Setting the name of the plugin -The notice that will be thrown can also contain the name of the plugin. Use the `set_plugin_name( $name )` method on the `WPUpdatePhp` object to provide the name. This call needs to be made before the `does_it_meet_required_php_version()` method is called to check versions. - ## License (GPLv2 license or later) diff --git a/composer.json b/composer.json index b2f3eb6..c3296ab 100644 --- a/composer.json +++ b/composer.json @@ -5,11 +5,30 @@ "issues": "https://github.com/wpupdatephp/wp-update-php/issues", "source": "https://github.com/wpupdatephp/wp-update-php" }, + "require": { + "php": ">=5.2.4", + "xrstf/composer-php52": "^1.0" + }, "require-dev": { - "phpspec/phpspec": "~2.0" + "phpspec/phpspec": "~2.0", + "phpunit/phpunit": "^3.6.12" + }, + "suggest": { + "coenjacobs/mozart": "Easily wrap this library with your own prefix, to prevent collisions when multiple plugins use this library" }, "autoload": { "classmap": ["src"] }, - "license": "GPL-2.0+" + "license": "GPL-2.0+", + "scripts": { + "post-install-cmd": [ + "xrstf\\Composer52\\Generator::onPostInstallCmd" + ], + "post-update-cmd": [ + "xrstf\\Composer52\\Generator::onPostInstallCmd" + ], + "post-autoload-dump": [ + "xrstf\\Composer52\\Generator::onPostInstallCmd" + ] + } } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..e8de0ff --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,17 @@ + + + + + ./tests/unit/ + + + diff --git a/spec/WPUpdatePhpSpec.php b/spec/WPUpdatePhpSpec.php deleted file mode 100644 index 96fdeee..0000000 --- a/spec/WPUpdatePhpSpec.php +++ /dev/null @@ -1,45 +0,0 @@ -beConstructedWith( '5.4.0', '5.3.0' ); - } - - function it_can_run_on_minimum_version() { - $this->does_it_meet_required_php_version( '5.4.0' )->shouldReturn( true ); - } - - function it_passes_the_recommended_version() { - $this->does_it_meet_recommended_php_version( '5.3.0' )->shouldReturn( true ); - } - - function it_will_not_run_on_old_version() { - $this->does_it_meet_required_php_version( '5.2.4' )->shouldReturn( false ); - } - - function it_fails_the_recommended_version() { - $this->does_it_meet_recommended_php_version( '5.2.9' )->shouldReturn( false ); - } - - function it_adds_plugin_name_to_admin_notice() { - $this->set_plugin_name( 'Test Plugin' ); - $this->get_admin_notice()->shouldMatch('/Test Plugin/i'); - $this->get_admin_notice( 'recommended' )->shouldMatch('/Test Plugin/i'); - } - } -} \ No newline at end of file diff --git a/src/Checker.php b/src/Checker.php new file mode 100644 index 0000000..2a88167 --- /dev/null +++ b/src/Checker.php @@ -0,0 +1,51 @@ +arguments = $arguments; + } + + public function setup() + { + $this->checks = array( + new WPUP_PhpVersion($this), + new WPUP_WordPressVersion($this), + ); + + foreach($this->checks as $check) { + $check->setup(); + } + } + + public function check() + { + /** @var WPUP_Check_Interface $check */ + foreach($this->checks as $check) { + $check->check(); + } + } + + public function reportFail($failure) + { + $this->failures[] = $failure; + } + + public function reportRecommendation($recommendation) + { + $this->recommendations[] = $recommendation; + } +} diff --git a/src/Checks/Interface.php b/src/Checks/Interface.php new file mode 100644 index 0000000..b1a61f8 --- /dev/null +++ b/src/Checks/Interface.php @@ -0,0 +1,8 @@ +match_version = PHP_VERSION; + } +} diff --git a/src/Checks/VersionCheck.php b/src/Checks/VersionCheck.php new file mode 100644 index 0000000..82de040 --- /dev/null +++ b/src/Checks/VersionCheck.php @@ -0,0 +1,61 @@ +arguments = $checker->arguments; + $this->checker = $checker; + } + + public function checkArguments($arguments, $key) + { + if (!isset($arguments[$key])) { + return false; + } + + if (!is_array($arguments[$key])) { + return false; + } + + return true; + } + + public function check() + { + if ( ! $this->checkArguments($this->arguments, $this->arguments_key )) { + return; + } + + $this->checkVersions($this->arguments[$this->arguments_key]); + } + + public function checkVersions($arguments) + { + foreach ($arguments as $argument) { + if (!is_array($argument)) { + continue; + } + + if (version_compare($this->match_version, $argument['version']) === -1) { + if ($argument['required'] === true) { + $this->checker->reportFail($argument); + } else { + $this->checker->reportRecommendation($argument); + } + } + } + } +} diff --git a/src/Checks/WordPressVersion.php b/src/Checks/WordPressVersion.php new file mode 100644 index 0000000..033d5cf --- /dev/null +++ b/src/Checks/WordPressVersion.php @@ -0,0 +1,13 @@ +match_version = $wp_version; + } +} diff --git a/src/Notices/Abstract.php b/src/Notices/Abstract.php new file mode 100644 index 0000000..bfd1d07 --- /dev/null +++ b/src/Notices/Abstract.php @@ -0,0 +1,30 @@ +version = $version; + $this->plugin_name = $plugin_name; + } + + /** + * @param $translator WPUP_Translator + */ + public function setTranslator($translator ) + { + $this->translator = $translator; + } + + public function display() + { + return '
' . $this->getNoticeText() . '
'; + } +} \ No newline at end of file diff --git a/src/Notices/Interface.php b/src/Notices/Interface.php new file mode 100644 index 0000000..6c42e9a --- /dev/null +++ b/src/Notices/Interface.php @@ -0,0 +1,6 @@ +translator->getString('minimum'); + + return sprintf($string, $this->plugin_name, $this->version, esc_url($this->url)); + } +} \ No newline at end of file diff --git a/src/Notices/Recommended.php b/src/Notices/Recommended.php new file mode 100644 index 0000000..fb3775f --- /dev/null +++ b/src/Notices/Recommended.php @@ -0,0 +1,14 @@ +translator->getString('minimum'); + + return sprintf($string, $this->plugin_name, $this->version, esc_url($this->url)); + } +} \ No newline at end of file diff --git a/src/Translator.php b/src/Translator.php new file mode 100644 index 0000000..ec377a9 --- /dev/null +++ b/src/Translator.php @@ -0,0 +1,32 @@ + 'Unfortunately, %s cannot run on PHP versions older than %s. Read more information about how you can update.', + 'recommended' => '%s recommends a PHP version higher than %s. Read more information about how you can update.', + ); + + /** + * @param $key string + * @return bool|string + */ + public function getString($key ) + { + if ( isset($this->strings[$key] ) ) { + return $this->strings[$key]; + } + + return false; + } + + /** + * @param $key string + * @param $string string + */ + public function setString($key, $string ) + { + $this->strings[$key] = $string; + } +} \ No newline at end of file diff --git a/src/WPUpdatePhp.php b/src/WPUpdatePhp.php index 16a21bb..7cf5890 100644 --- a/src/WPUpdatePhp.php +++ b/src/WPUpdatePhp.php @@ -12,33 +12,32 @@ * WPUpdatePhp. */ class WPUpdatePhp { - /** @var string */ - private $minimum_version; + /** @var string */ + private $plugin_name; - /** @var string */ - private $recommended_version; + /** @var WPUP_Translator */ + public $translator; - /** @var string */ - private $plugin_name = ''; + /** @var WPUP_Checker */ + private $checker; - /** - * @param string $minimum_version Minimum version of PHP. - * @param string $recommended_version Recommended version of PHP. - */ - public function __construct( $minimum_version, $recommended_version = null ) { - $this->minimum_version = $minimum_version; - $this->recommended_version = $recommended_version; - } + /** + * @param string $plugin_name + * @param array $arguments + */ + public function __construct( $plugin_name, $arguments = array()) { + $this->plugin_name = $plugin_name; - /** - * Set the plugin name for the admin notice. - * - * @param string $name Name of the plugin to be used in admin notices. - */ - public function set_plugin_name( $name ) { - $this->plugin_name = $name; + $this->translator = new WPUP_Translator(); + $this->checker = new WPUP_Checker($arguments); } + public function check() + { + $this->checker->setup(); + $this->checker->check(); + } + /** * Check given PHP version against minimum required version. * @@ -52,7 +51,9 @@ public function does_it_meet_required_php_version( $version = PHP_VERSION ) { return true; } - $this->load_version_notice( array( $this, 'minimum_admin_notice' ) ); + $notice = new WPUP_Minimum_Notice( $this->minimum_version, $this->plugin_name ); + $notice->setTranslator($this->translator); + $this->load_version_notice( array( $notice, 'display' ) ); return false; } @@ -69,7 +70,9 @@ public function does_it_meet_recommended_php_version( $version = PHP_VERSION ) { return true; } - $this->load_version_notice( array( $this, 'recommended_admin_notice' ) ); + $notice = new WPUP_Recommended_Notice( $this->recommended_version, $this->plugin_name ); + $notice->setTranslator($this->translator); + $this->load_version_notice( array( $notice, 'display' ) ); return false; } @@ -95,54 +98,4 @@ private function load_version_notice( $callback ) { add_action( 'network_admin_notices', $callback ); } } - - /** - * Return the string to be shown in the admin notice. - * - * This is based on the level (`recommended` or default `minimum`) of the - * notice. This will also add the plugin name to the notice string, if set. - * - * @param string $level Optional. Admin notice level, `recommended` or `minimum`. - * Default is `minimum`. - * @return string - */ - public function get_admin_notice( $level = 'minimum' ) { - if ( 'recommended' === $level ) { - if ( ! empty( $this->plugin_name ) ) { - return '

' . $this->plugin_name . ' recommends a PHP version higher than ' . $this->recommended_version . '. Read more information about how you can update.

'; - } else { - return '

This plugin recommends a PHP version higher than ' . $this->recommended_version . '. Read more information about how you can update.

'; - } - } - - if ( ! empty( $this->plugin_name ) ) { - return '

Unfortunately, ' . $this->plugin_name . ' cannot run on PHP versions older than ' . $this->minimum_version . '. Read more information about how you can update.

'; - } else { - return '

Unfortunately, this plugin cannot run on PHP versions older than ' . $this->minimum_version . '. Read more information about how you can update.

'; - } - } - - /** - * Method hooked into admin_notices when minimum required PHP version is not - * available to show this in a notice. - * - * @hook admin_notices - */ - public function minimum_admin_notice() { - echo '
'; - echo $this->get_admin_notice( 'minimum' ); - echo '
'; - } - - /** - * Method hooked into admin_notices when recommended PHP version is not - * available to show this in a notice. - * - * @hook admin_notices - */ - public function recommended_admin_notice() { - echo '
'; - echo $this->get_admin_notice( 'recommended' ); - echo '
'; - } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..e9b8568 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,5 @@ + array( + array( + 'version' => '5.6.0', + 'required' => true, + ), + ), + ); + $testedUnit = $this->getMock('WPUP_Checker', array()); + $testedUnit->arguments = $arguments; + + $check = new TestCheck($testedUnit); + $this->assertFalse($check->checkArguments($arguments, 'notSetKey')); + } + + /** @test */ + public function itReturnsFalseWhenKeyIsNotArray() + { + $arguments = array( + 'key' => 'dummy value' + ); + $testedUnit = $this->getMock('WPUP_Checker', array()); + $testedUnit->arguments = $arguments; + + $check = new TestCheck($testedUnit); + $this->assertFalse($check->checkArguments($arguments, 'notSetKey')); + } + + /** @test */ + public function itReturnsTrueOnProperConfig() + { + $arguments = array( + 'php' => array( + array( + 'version' => '5.6.0', + 'required' => true, + ), + ), + ); + $testedUnit = $this->getMock('WPUP_Checker', array()); + $testedUnit->arguments = $arguments; + + $check = new TestCheck($testedUnit); + $this->assertTrue($check->checkArguments($arguments, 'php')); + } + + /** @test */ + public function itReportsFailWhenVersionFails() + { + $arguments = array( + 'test' => array( + array( + 'version' => '5.6.0', + 'required' => true, + ), + ), + ); + $testedUnit = $this->getMock('WPUP_Checker', array('reportFail')); + $testedUnit->arguments = $arguments; + + $check = new TestCheck($testedUnit); + $check->match_version = '5.2.2'; + $testedUnit->expects($this->once())->method('reportFail'); + $check->check(); + } + + /** @test */ + public function itReportsRecommendationWhenVersionRecommendationIsNotMet() + { + $arguments = array( + 'test' => array( + array( + 'version' => '7.0.0', + 'required' => false, + ), + ), + ); + $testedUnit = $this->getMock('WPUP_Checker', array('reportRecommendation')); + $testedUnit->arguments = $arguments; + + $check = new TestCheck($testedUnit); + $check->match_version = '5.2.2'; + $testedUnit->expects($this->once())->method('reportRecommendation'); + $check->check(); + } +} + +class TestCheck extends WPUP_VersionCheck +{ + public $arguments_key = 'test'; + public function setup(){} +} diff --git a/tests/unit/TranslatorTest.php b/tests/unit/TranslatorTest.php new file mode 100644 index 0000000..59d2fc2 --- /dev/null +++ b/tests/unit/TranslatorTest.php @@ -0,0 +1,19 @@ +setString('minimum', 'test string'); + $this->assertEquals('test string', $translator->getString('minimum')); + } + + /** @test */ + public function itReturnsFalseIfNoStringIsSetForKey() + { + $translator = new WPUP_Translator(); + $this->assertFalse($translator->getString('test')); + } +} \ No newline at end of file