diff --git a/.distignore b/.distignore index 83b15fe..5d7f178 100644 --- a/.distignore +++ b/.distignore @@ -12,13 +12,13 @@ coverage.xml .gitignore .phpunit.result.cache .scrutinizer.yml -Changelog.md -composer.json composer.lock mslsmenu.zip package.json package-lock.json phpdoc.xml -phpstan.neon +.phpstan.neon.dist +.phpcs.cache +.phpcs.xml.dist phpunit.xml README.md diff --git a/.gitignore b/.gitignore index 1bac2c0..83ff10f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store .phpunit.result.cache +.phpcs.cache .idea/ vendor/ reports/ diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist new file mode 100644 index 0000000..4d0b4c1 --- /dev/null +++ b/.phpcs.xml.dist @@ -0,0 +1,26 @@ + + + PHPCS MslsMenu configuration + + bin/* + tests/* + vendor/* + + + + + + + + + + + + + + + + + + + diff --git a/phpstan.neon b/.phpstan.neon.dist similarity index 100% rename from phpstan.neon rename to .phpstan.neon.dist diff --git a/MslsMenu.php b/MslsMenu.php index 34ce0a2..9bbf3a3 100644 --- a/MslsMenu.php +++ b/MslsMenu.php @@ -5,6 +5,7 @@ * @copyright Copyright (C) 2011-2022, Dennis Ploetner, re@lloc.de * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 or later * @wordpress-plugin + * @package mslsmenu * * Plugin Name: MslsMenu * Requires Plugins: multisite-language-switcher @@ -35,6 +36,7 @@ /** * MslsMenu Class + * * @package mslsmenu */ final class MslsMenu { @@ -56,8 +58,6 @@ final class MslsMenu { */ public function __construct( $options ) { $this->options = $options; - - load_plugin_textdomain( 'mslsmenu', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); } /** @@ -71,21 +71,21 @@ public static function init( $options ): MslsMenu { $obj = new self( $options ); if ( ! is_null( $options ) ) { - add_filter( 'wp_nav_menu_items', [ $obj, 'nav_item' ], 10, 2 ); - add_action( 'msls_admin_register', [ $obj, 'admin_register' ] ); + add_filter( 'wp_nav_menu_items', array( $obj, 'nav_item' ), 10, 2 ); + add_action( 'msls_admin_register', array( $obj, 'admin_register' ) ); } return $obj; } - private function get_msls_output(): lloc\Msls\MslsOutput{ + private function get_msls_output(): lloc\Msls\MslsOutput { return function_exists( 'msls_output' ) ? msls_output() : lloc\Msls\MslsOutput::init(); } /** * Callback for wp_nav_menu_items * - * @param string $items + * @param string $items * @param \stdClass $args * * @return string @@ -94,7 +94,7 @@ public function nav_item( string $items, \stdClass $args ): string { $menu_locations = $this->options->mslsmenu_theme_location ?? ''; $theme_location = $args->theme_location ?? ''; - if ( is_array( $menu_locations ) && in_array( $theme_location, $menu_locations ) ) { + if ( is_array( $menu_locations ) && in_array( $theme_location, $menu_locations, true ) ) { $menu = ''; $obj = $this->get_msls_output(); @@ -118,31 +118,31 @@ public function admin_register( string $page ) { $this->page = $page; - add_settings_section( self::SID, $label, [ $this, 'add_settings' ], $page ); + add_settings_section( self::SID, $label, array( $this, 'add_settings' ), $page ); } /** * Callback for add_settings_section in admin_register */ public function add_settings(): void { - $args = [ 'msls_admin' => lloc\Msls\MslsAdmin::init() ]; + $args = array( 'msls_admin' => lloc\Msls\MslsAdmin::init() ); $label = __( 'Theme Location', 'mslsmenu' ); - $callback = [ $this, 'theme_location' ]; + $callback = array( $this, 'theme_location' ); add_settings_field( 'mslsmenu_theme_location', $label, $callback, $this->page, self::SID, $args ); $label = __( 'Display', 'mslsmenu' ); - $callback = [ $this, 'display' ]; + $callback = array( $this, 'display' ); add_settings_field( 'mslsmenu_display', $label, $callback, $this->page, self::SID, $args ); - $fields = [ + $fields = array( 'mslsmenu_before_output' => __( 'Text/HTML before the list', 'mslsmenu' ), 'mslsmenu_after_output' => __( 'Text/HTML after the list', 'mslsmenu' ), 'mslsmenu_before_item' => __( 'Text/HTML before each item', 'mslsmenu' ), 'mslsmenu_after_item' => __( 'Text/HTML after each item', 'mslsmenu' ), - ]; + ); - $callback = [ $this, 'input' ]; + $callback = array( $this, 'input' ); foreach ( $fields as $id => $label ) { $args['mslsmenu_input'] = $id; add_settings_field( $id, $label, $callback, $this->page, self::SID, $args ); @@ -157,26 +157,26 @@ public function add_settings(): void { public function theme_location( array $args ) { $menu_locations = get_nav_menu_locations(); $theme_locations = $this->options->mslsmenu_theme_location ?? ''; - $options = [ - sprintf( '', $this->selected( '', $theme_locations ), esc_html__( '-- empty --', 'mslsmenu' ) ) - ]; + $options = array( + sprintf( '', $this->selected( '', $theme_locations ), esc_html__( '-- empty --', 'mslsmenu' ) ), + ); foreach ( array_keys( $menu_locations ) as $value ) { $options[] = sprintf( '', esc_attr( $value ), $this->selected( $value, $theme_locations ) ); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - printf( '', 'mslsmenu_theme_location', implode( '', $options ) ); + printf( '', 'mslsmenu_theme_location', implode( '', $options ) ); } /** * @param string $needle - * @param mixed $locations + * @param mixed $locations * * @return string */ protected function selected( string $needle, $locations ): string { - return is_array( $locations ) ? selected( true, in_array( $needle, $locations ), false ) : ''; + return is_array( $locations ) ? selected( true, in_array( $needle, $locations, true ), false ) : ''; } /** @@ -188,9 +188,9 @@ public function display( array $args ) { $types = lloc\Msls\MslsLink::get_types_description(); $display = $this->options->mslsmenu_display ?? '0'; - /** - * Backward compatibility - */ + /** + * Backward compatibility + */ if ( ! class_exists( lloc\Msls\Component\Input\Select::class ) ) { // @codeCoverageIgnoreStart @@ -211,14 +211,14 @@ public function display( array $args ) { * @param array $args */ public function input( array $args ) { - /** - * Backward compatibility - */ + /** + * Backward compatibility + */ if ( ! class_exists( 'lloc\Msls\Component\Input\Text' ) ) { // @codeCoverageIgnoreStart // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo $args['msls_admin']->render_input( $args['mslsmenu_input'] ); + echo $args['msls_admin']->render_input( $args['mslsmenu_input'] ); return; // @codeCoverageIgnoreEnd @@ -228,16 +228,18 @@ public function input( array $args ) { $value = $this->options->$key ?? ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo ( new lloc\Msls\Component\Input\Text( $key, $value ) )->render(); + echo ( new lloc\Msls\Component\Input\Text( $key, $value ) )->render(); } - } // @codeCoverageIgnoreStart if ( function_exists( 'add_action' ) ) { - add_action( 'plugins_loaded', function () { - $options = class_exists( lloc\Msls\MslsOptions::class ) ? lloc\Msls\MslsOptions::instance() : null; - MslsMenu::init( $options ); - } ); + add_action( + 'plugins_loaded', + function () { + $options = class_exists( lloc\Msls\MslsOptions::class ) ? lloc\Msls\MslsOptions::instance() : null; + MslsMenu::init( $options ); + } + ); } -// @codeCoverageIgnoreEnd \ No newline at end of file +// @codeCoverageIgnoreEnd diff --git a/bin/githooks/pre-commit b/bin/githooks/pre-commit new file mode 100644 index 0000000..fd4d359 --- /dev/null +++ b/bin/githooks/pre-commit @@ -0,0 +1,28 @@ +#!/bin/bash + +echo "" +echo "phpcbf pre commit hook start" + +PHP_CS_FIXER="vendor/bin/phpcbf" +HAS_PHP_CS_FIXER=false + +# check if php-cs-fixer is installed as a composer dependency +if [ -x "$PHP_CS_FIXER" ]; then + HAS_PHP_CS_FIXER=true +fi + +if $HAS_PHP_CS_FIXER; then + + # gets a list of all staged but not deleted php-files + CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACMRTUXB HEAD | grep '\.php$') + + if [ ! -z "${CHANGED_FILES}" ]; then + # runs phpcbf on the changed files + vendor/bin/phpcbf -w ${CHANGED_FILES} + # adds the changed files to staging again + git add ${CHANGED_FILES} + fi +fi + +echo "phpcbf pre commit hook finish" +echo "" diff --git a/composer.json b/composer.json index 9325441..3c062d0 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "brain/monkey": "2.*", "phpstan/phpstan": "^1.8", "szepeviktor/phpstan-wordpress": "^1.1", - "phpstan/extension-installer": "^1.1" + "phpstan/extension-installer": "^1.1", + "wp-coding-standards/wpcs": "^3.0" }, "autoload-dev": { "files": [ "MslsMenu.php" ] @@ -21,10 +22,20 @@ "scripts": { "test": "vendor/bin/pest", "coverage": "php -d xdebug.mode=coverage vendor/bin/pest --coverage", - "analyze": "vendor/bin/phpstan analyze", + "phpstan": "vendor/bin/phpstan analyze", "git-release": "bin/git-release.sh", "build": [ "@git-release" + ], + "githooks": [ + "if [ -e bin/githooks/pre-commit ]; then cp bin/githooks/pre-commit ./.git/hooks/; fi", + "if [ -e .git/hooks/pre-commit ]; then chmod 0755 .git/hooks/pre-commit; fi" + ], + "post-install-cmd": [ + "@githooks" + ], + "post-update-cmd": [ + "@githooks" ] }, "authors": [ @@ -45,7 +56,8 @@ "allow-plugins": { "composer/installers": true, "phpstan/extension-installer": true, - "pestphp/pest-plugin": true + "pestphp/pest-plugin": true, + "dealerdirect/phpcodesniffer-composer-installer": true } } } diff --git a/languages/index.php b/languages/index.php index ac7a857..ea6de67 100644 --- a/languages/index.php +++ b/languages/index.php @@ -1 +1 @@ - +atLeast()->once(); - Functions\stubs( [ - 'plugin_basename' => 'abc', - '__' - ] ); -} ); - - -beforeEach( function () { - $this->sut = \MslsMenu::init( null ); -} ); - -afterAll( function () { - Monkey\tearDown(); -} ); - -it( 'returns an instance of MslsMenu even when factory received null', function () { - expect( $this->sut )->toBeInstanceOf( \MslsMenu::class ); -} ); - -it( 'adds no filter when factory received null', function() { - expect( has_filter( 'wp_nav_menu_items', [ \MslsMenu::class, 'nav_item' ] ) )->toBeFalse(); -} ); - -it( 'adds no action when factory received null', function () { - expect( has_action( 'msls_admin_register', [ \MslsMenu::class, 'admin_register' ] ) )->toBeFalse(); -} ); - -it( 'returns an empty string on $sut->nav_item() when factory received null', function() { - $result = $this->sut->nav_item( '', (object) [] ); - - expect( $result )->toEqual( '' ); -} ); \ No newline at end of file +beforeAll( + function () { + Monkey\setUp(); + + Functions\stubs( + array( + 'plugin_basename' => 'abc', + '__', + ) + ); + } +); + + +beforeEach( + function () { + $this->sut = \MslsMenu::init( null ); + } +); + +afterAll( + function () { + Monkey\tearDown(); + } +); + +it( + 'returns an instance of MslsMenu even when factory received null', + function () { + expect( $this->sut )->toBeInstanceOf( \MslsMenu::class ); + } +); + +it( + 'adds no filter when factory received null', + function () { + expect( has_filter( 'wp_nav_menu_items', array( \MslsMenu::class, 'nav_item' ) ) )->toBeFalse(); + } +); + +it( + 'adds no action when factory received null', + function () { + expect( has_action( 'msls_admin_register', array( \MslsMenu::class, 'admin_register' ) ) )->toBeFalse(); + } +); + +it( + 'returns an empty string on $sut->nav_item() when factory received null', + function () { + $result = $this->sut->nav_item( '', (object) array() ); + + expect( $result )->toEqual( '' ); + } +); diff --git a/tests/ValidObjectTest.php b/tests/ValidObjectTest.php index d551be6..8e39cf8 100644 --- a/tests/ValidObjectTest.php +++ b/tests/ValidObjectTest.php @@ -5,87 +5,121 @@ use Brain\Monkey; use Brain\Monkey\Functions; -beforeAll( function () { - Monkey\setUp(); - - Functions\expect( 'load_plugin_textdomain' )->atLeast()->once(); - Functions\stubs( [ - 'plugin_basename' => 'abc', - '__', - 'selected' => 'selected="selected"', - ] ); -} ); - -beforeEach( function() { - $options = \Mockery::mock( 'lloc\Msls\MslsOptions' ); - $options->mslsmenu_theme_location = [ 'test' ]; - - $this->sut = \MslsMenu::init( $options ); -} ); - -afterAll( function () { - Monkey\tearDown(); -} ); - -it( 'returns an instance of MslsMenu when factory receives an MslsOptions object', function () { - expect( $this->sut )->toBeInstanceOf( \MslsMenu::class ); -} ); - -it( 'adds a filter when factory receives an MslsOptions object', function () { - expect( has_filter( 'wp_nav_menu_items', [ $this->sut, 'nav_item' ] ) )->toEqual( 10 ); -} ); - -it( 'adds an action when factory receives an MslsOptions object', function () { - expect( has_action( 'msls_admin_register', [ $this->sut, 'admin_register' ] ) )->toEqual( 10 ); -} ); - -it( 'calls add_settings_section on $sut->admin_register()', function () { - Functions\expect( 'add_settings_section' )->once(); - - $this->sut->admin_register( 'test' ); -} ); - -it( 'returns an empty string on $sut->nav_item()', function() { - $expected = ''; - - $args = new \stdClass(); - $args->theme_locations = 'test'; - - $result = $this->sut->nav_item( '', $args ); - - expect( $result )->toEqual( $expected ); -} ); - -it( 'calls add_settings_field on $sut->add_settings()', function () { - Functions\expect( 'add_settings_field' )->times( 6 ); - - $this->sut->add_settings(); -} ); - -it( 'calls get_nav_menu_locations on $sut->theme_location()', function () { - Functions\expect( 'get_nav_menu_locations' )->once()->andReturn( [ 'test' => 1 ] ); - Functions\expect( 'esc_attr' )->once()->andReturnFirstArg(); - Functions\expect( 'esc_html__' )->once()->andReturnFirstArg(); - - $expected = ''; - - $this->sut->theme_location( [] ); - - $this->expectOutputString( $expected ); -} ); - -it( 'prints a string on $sut->display()', function () { - $expected = ''; - - $this->sut->display( [] ); - - $this->expectOutputString( $expected ); -} ); - -it( 'prints a string on $sut->input()', function () { - $expected = ''; - - $this->sut->input( [] ); - - $this->expectOutputString( $expected ); -} ); +beforeAll( + function () { + Monkey\setUp(); + + Functions\stubs( + array( + 'plugin_basename' => 'abc', + '__', + 'selected' => 'selected="selected"', + ) + ); + } +); + +beforeEach( + function () { + $options = \Mockery::mock( 'lloc\Msls\MslsOptions' ); + $options->mslsmenu_theme_location = array( 'test' ); + + $this->sut = \MslsMenu::init( $options ); + } +); + +afterAll( + function () { + Monkey\tearDown(); + } +); + +it( + 'returns an instance of MslsMenu when factory receives an MslsOptions object', + function () { + expect( $this->sut )->toBeInstanceOf( \MslsMenu::class ); + } +); + +it( + 'adds a filter when factory receives an MslsOptions object', + function () { + expect( has_filter( 'wp_nav_menu_items', array( $this->sut, 'nav_item' ) ) )->toEqual( 10 ); + } +); + +it( + 'adds an action when factory receives an MslsOptions object', + function () { + expect( has_action( 'msls_admin_register', array( $this->sut, 'admin_register' ) ) )->toEqual( 10 ); + } +); + +it( + 'calls add_settings_section on $sut->admin_register()', + function () { + Functions\expect( 'add_settings_section' )->once(); + + $this->sut->admin_register( 'test' ); + } +); + +it( + 'returns an empty string on $sut->nav_item()', + function () { + $expected = ''; + + $args = new \stdClass(); + $args->theme_locations = 'test'; + + $result = $this->sut->nav_item( '', $args ); + + expect( $result )->toEqual( $expected ); + } +); + +it( + 'calls add_settings_field on $sut->add_settings()', + function () { + Functions\expect( 'add_settings_field' )->times( 6 ); + + $this->sut->add_settings(); + } +); + +it( + 'calls get_nav_menu_locations on $sut->theme_location()', + function () { + Functions\expect( 'get_nav_menu_locations' )->once()->andReturn( array( 'test' => 1 ) ); + Functions\expect( 'esc_attr' )->once()->andReturnFirstArg(); + Functions\expect( 'esc_html__' )->once()->andReturnFirstArg(); + + $expected = ''; + + $this->sut->theme_location( array() ); + + $this->expectOutputString( $expected ); + } +); + +it( + 'prints a string on $sut->display()', + function () { + $expected = ''; + + $this->sut->display( array() ); + + $this->expectOutputString( $expected ); + } +); + +it( + 'prints a string on $sut->input()', + function () { + $expected = ''; + + $this->sut->input( array() ); + + $this->expectOutputString( $expected ); + } +);