diff --git a/.editorconfig b/.editorconfig index 257221d..5e9a93e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,3 +12,6 @@ trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false + +[*.yml] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes index d3353e5..0423a05 100644 --- a/.gitattributes +++ b/.gitattributes @@ -34,4 +34,3 @@ # Avoid merge conflicts in CHANGELOG # https://about.gitlab.com/2015/02/10/gitlab-reduced-merge-conflicts-by-90-percent-with-changelog-placeholders/ /CHANGELOG.md merge=union - diff --git a/.github/workflows/bc.yml_ b/.github/workflows/bc.yml_ index 35b3a86..75f97a7 100644 --- a/.github/workflows/bc.yml_ +++ b/.github/workflows/bc.yml_ @@ -1,15 +1,15 @@ on: - - pull_request - - push + - pull_request + - push name: backwards compatibility jobs: - roave_bc_check: - name: Roave BC Check - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: fetch tags - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - name: Roave BC Check - uses: docker://nyholm/roave-bc-check-ga + roave_bc_check: + name: Roave BC Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: fetch tags + run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - name: Roave BC Check + uses: docker://nyholm/roave-bc-check-ga diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4853f6c..ed5ff69 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,13 +54,8 @@ jobs: - name: Update composer run: composer self-update - - name: Install dependencies with composer php 7.4 - if: matrix.php == '7.4' + - name: Install dependencies with composer run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - name: Install dependencies with composer php 8.0 - if: matrix.php == '8.0' - run: composer update --ignore-platform-reqs --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - name: Run tests with phpunit run: vendor/bin/phpunit --colors=always diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index e28bada..031737c 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -16,6 +16,7 @@ jobs: matrix: os: - ubuntu-latest + php: - "7.4" diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 078ced7..e985576 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -17,6 +17,7 @@ jobs: php: - "7.4" + - "8.0" steps: - name: Checkout diff --git a/.gitignore b/.gitignore index 18a33d4..56da114 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,3 @@ phpunit.phar /phpunit.xml # phpunit cache .phpunit.result.cache - -# Phan -analysis.txt - diff --git a/.phpunit-watcher.yml b/.phpunit-watcher.yml index 0e4d766..035a80a 100644 --- a/.phpunit-watcher.yml +++ b/.phpunit-watcher.yml @@ -1,11 +1,11 @@ watch: - directories: - - src - - tests - fileMask: '*.php' + directories: + - src + - tests + fileMask: '*.php' notifications: - passingTests: false - failingTests: false + passingTests: false + failingTests: false phpunit: - binaryPath: vendor/bin/phpunit - timeout: 180 + binaryPath: vendor/bin/phpunit + timeout: 180 diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 45b5dca..eca0599 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,36 +1,33 @@ checks: - php: true + php: true filter: - paths: - - "src/*" + paths: + - "src/*" build: - nodes: - analysis: - environment: - php: 7.4.12 - - tests: - override: - - php-scrutinizer-run - - tests-and-coverage: - environment: - php: 7.4.12 - - dependencies: - override: - - composer self-update - - composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi - - tests: - override: - - - command: "./vendor/bin/phpunit --coverage-clover ./coverage.xml" - on_node: 1 - coverage: - file: coverage.xml - format: php-clover - - + nodes: + analysis: + environment: + php: 7.4.12 + + tests: + override: + - php-scrutinizer-run + + tests-and-coverage: + environment: + php: 7.4.12 + + dependencies: + override: + - composer self-update + - composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + tests: + override: + - command: "./vendor/bin/phpunit --coverage-clover ./coverage.xml" + on_node: 1 + coverage: + file: coverage.xml + format: php-clover diff --git a/.styleci.yml b/.styleci.yml index 81b0650..2036119 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -4,86 +4,86 @@ risky: true version: 8 finder: - exclude: - - docs - - vendor - - resources - - views - - public - - templates - not-name: - - UnionCar.php - - TimerUnionTypes.php - - schema1.php + exclude: + - docs + - vendor + - resources + - views + - public + - templates + not-name: + - UnionCar.php + - TimerUnionTypes.php + - schema1.php enabled: - - alpha_ordered_traits - - array_indentation - - array_push - - combine_consecutive_issets - - combine_consecutive_unsets - - combine_nested_dirname - - declare_strict_types - - dir_constant - - final_static_access - - fully_qualified_strict_types - - function_to_constant - - hash_to_slash_comment - - is_null - - logical_operators - - magic_constant_casing - - magic_method_casing - - method_separation - - modernize_types_casting - - native_function_casing - - native_function_type_declaration_casing - - no_alias_functions - - no_empty_comment - - no_empty_phpdoc - - no_empty_statement - - no_extra_block_blank_lines - - no_short_bool_cast - - no_superfluous_elseif - - no_unneeded_control_parentheses - - no_unneeded_curly_braces - - no_unneeded_final_method - - no_unset_cast - - no_unused_imports - - no_unused_lambda_imports - - no_useless_else - - no_useless_return - - normalize_index_brace - - php_unit_dedicate_assert - - php_unit_dedicate_assert_internal_type - - php_unit_expectation - - php_unit_mock - - php_unit_mock_short_will_return - - php_unit_namespaced - - php_unit_no_expectation_annotation - - phpdoc_no_empty_return - - phpdoc_no_useless_inheritdoc - - phpdoc_order - - phpdoc_property - - phpdoc_scalar - - phpdoc_separation - - phpdoc_singular_inheritdoc - - phpdoc_trim - - phpdoc_trim_consecutive_blank_line_separation - - phpdoc_type_to_var - - phpdoc_types - - phpdoc_types_order - - print_to_echo - - regular_callable_call - - return_assignment - - self_accessor - - self_static_accessor - - set_type_to_cast - - short_array_syntax - - short_list_syntax - - simplified_if_return - - single_quote - - standardize_not_equals - - ternary_to_null_coalescing - - trailing_comma_in_multiline_array - - unalign_double_arrow - - unalign_equals + - alpha_ordered_traits + - array_indentation + - array_push + - combine_consecutive_issets + - combine_consecutive_unsets + - combine_nested_dirname + - declare_strict_types + - dir_constant + - final_static_access + - fully_qualified_strict_types + - function_to_constant + - hash_to_slash_comment + - is_null + - logical_operators + - magic_constant_casing + - magic_method_casing + - method_separation + - modernize_types_casting + - native_function_casing + - native_function_type_declaration_casing + - no_alias_functions + - no_empty_comment + - no_empty_phpdoc + - no_empty_statement + - no_extra_block_blank_lines + - no_short_bool_cast + - no_superfluous_elseif + - no_unneeded_control_parentheses + - no_unneeded_curly_braces + - no_unneeded_final_method + - no_unset_cast + - no_unused_imports + - no_unused_lambda_imports + - no_useless_else + - no_useless_return + - normalize_index_brace + - php_unit_dedicate_assert + - php_unit_dedicate_assert_internal_type + - php_unit_expectation + - php_unit_mock + - php_unit_mock_short_will_return + - php_unit_namespaced + - php_unit_no_expectation_annotation + - phpdoc_no_empty_return + - phpdoc_no_useless_inheritdoc + - phpdoc_order + - phpdoc_property + - phpdoc_scalar + - phpdoc_separation + - phpdoc_singular_inheritdoc + - phpdoc_trim + - phpdoc_trim_consecutive_blank_line_separation + - phpdoc_type_to_var + - phpdoc_types + - phpdoc_types_order + - print_to_echo + - regular_callable_call + - return_assignment + - self_accessor + - self_static_accessor + - set_type_to_cast + - short_array_syntax + - short_list_syntax + - simplified_if_return + - single_quote + - standardize_not_equals + - ternary_to_null_coalescing + - trailing_comma_in_multiline_array + - unalign_double_arrow + - unalign_equals diff --git a/README.md b/README.md index 343c152..ee67c0b 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,10 @@ -

Yii View

+

Yii View Extension


-The package provides bindings for [Yii View Rendering Library](https://github.com/yiisoft/view/). - [![Latest Stable Version](https://poser.pugx.org/yiisoft/yii-view/v/stable.png)](https://packagist.org/packages/yiisoft/yii-view) [![Total Downloads](https://poser.pugx.org/yiisoft/yii-view/downloads.png)](https://packagist.org/packages/yiisoft/yii-view) [![Build status](https://github.com/yiisoft/yii-view/workflows/build/badge.svg)](https://github.com/yiisoft/yii-view/actions?query=workflow%3Abuild) @@ -17,8 +15,24 @@ The package provides bindings for [Yii View Rendering Library](https://github.co [![static analysis](https://github.com/yiisoft/yii-view/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/yii-view/actions?query=workflow%3A%22static+analysis%22) [![type-coverage](https://shepherd.dev/github/yiisoft/yii-view/coverage.svg)](https://shepherd.dev/github/yiisoft/yii-view) +The package provides bindings for [Yii View Rendering Library](https://github.com/yiisoft/view/). + +## Requirements + +- PHP 7.4 or higher. + +## Installation + +The package could be installed with composer: + +```shell +composer require yiisoft/yii-view --prefer-dist +``` + ## General usage +## Testing + ### Unit testing The package is tested with [PHPUnit](https://phpunit.de/). To run tests: @@ -29,10 +43,11 @@ The package is tested with [PHPUnit](https://phpunit.de/). To run tests: ### Mutation testing -The package tests are checked with [Infection](https://infection.github.io/) mutation framework. To run it: +The package tests are checked with [Infection](https://infection.github.io/) mutation framework with +[Infection Static Analysis Plugin](https://github.com/Roave/infection-static-analysis-plugin). To run it: ```shell -./vendor/bin/infection +./vendor/bin/roave-infection-static-analysis-plugin ``` ### Static analysis @@ -43,21 +58,21 @@ The code is statically analyzed with [Psalm](https://psalm.dev/). To run static ./vendor/bin/psalm ``` -### Support the project +## License + +The Yii View Extension is free software. It is released under the terms of the BSD License. +Please see [`LICENSE`](./LICENSE.md) for more information. + +Maintained by [Yii Software](https://www.yiiframework.com/). + +## Support the project [![Open Collective](https://img.shields.io/badge/Open%20Collective-sponsor-7eadf1?logo=open%20collective&logoColor=7eadf1&labelColor=555555)](https://opencollective.com/yiisoft) -### Follow updates +## Follow updates [![Official website](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](https://www.yiiframework.com/) [![Twitter](https://img.shields.io/badge/twitter-follow-1DA1F2?logo=twitter&logoColor=1DA1F2&labelColor=555555?style=flat)](https://twitter.com/yiiframework) [![Telegram](https://img.shields.io/badge/telegram-join-1DA1F2?style=flat&logo=telegram)](https://t.me/yii3en) [![Facebook](https://img.shields.io/badge/facebook-join-1DA1F2?style=flat&logo=facebook&logoColor=ffffff)](https://www.facebook.com/groups/yiitalk) [![Slack](https://img.shields.io/badge/slack-join-1DA1F2?style=flat&logo=slack)](https://yiiframework.com/go/slack) - -## License - -The Yii View is free software. It is released under the terms of the BSD License. -Please see [`LICENSE`](./LICENSE.md) for more information. - -Maintained by [Yii Software](https://www.yiiframework.com/). diff --git a/composer.json b/composer.json index 6cbc663..0ebab2c 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "yiisoft/yii-view", "type": "library", - "description": "Yii binding for view rendering", + "description": "Yii View Extension", "keywords": [ "yii", "view" @@ -29,14 +29,13 @@ "yiisoft/view": "^3.0@dev" }, "require-dev": { - "nyholm/psr7": "^1.3", + "nyholm/psr7": "^1.4", "phpunit/phpunit": "^9.5", - "roave/infection-static-analysis-plugin": "^1.6", + "roave/infection-static-analysis-plugin": "^1.8", "spatie/phpunit-watcher": "^1.23", - "vimeo/psalm": "^4.3", - "yiisoft/di": "3.0.x-dev", - "yiisoft/event-dispatcher": "^1.0", - "yiisoft/test-support": "^1.0" + "vimeo/psalm": "^4.7", + "yiisoft/psr-dummy-provider": "^1.0", + "yiisoft/test-support": "^1.3" }, "autoload": { "psr-4": { diff --git a/src/Exception/InvalidLinkTagException.php b/src/Exception/InvalidLinkTagException.php index 88153ee..d9c419d 100644 --- a/src/Exception/InvalidLinkTagException.php +++ b/src/Exception/InvalidLinkTagException.php @@ -31,8 +31,7 @@ public function getName(): string public function getSolution(): ?string { - $solution = 'Got link tag:' . "\n" . var_export($this->tag, true); - $solution .= <<tag, true) . <<tag, true); - $solution .= <<tag, true) . <<assertSame('Invalid link tag configuration in injection', $exception->getName()); + $this->assertStringStartsWithIgnoringLineEndings( + "Got link tag:\narray (\n)\n\nIn injection that implements", + $exception->getSolution() + ); + } +} diff --git a/tests/Exception/InvalidMetaTagExceptionTest.php b/tests/Exception/InvalidMetaTagExceptionTest.php new file mode 100644 index 0000000..5470f7d --- /dev/null +++ b/tests/Exception/InvalidMetaTagExceptionTest.php @@ -0,0 +1,25 @@ +assertSame('Invalid meta tag configuration in injection', $exception->getName()); + $this->assertStringStartsWithIgnoringLineEndings( + "Got meta tag:\narray (\n)\n\nIn injection that implements", + $exception->getSolution() + ); + } +} diff --git a/tests/Support/InvalidLinkTagInjection.php b/tests/Support/InvalidLinkTagInjection.php new file mode 100644 index 0000000..211a3c2 --- /dev/null +++ b/tests/Support/InvalidLinkTagInjection.php @@ -0,0 +1,17 @@ + 'end', + ], + ]; + } +} diff --git a/tests/Support/TestInjection.php b/tests/Support/TestInjection.php index 21c2672..070fbec 100644 --- a/tests/Support/TestInjection.php +++ b/tests/Support/TestInjection.php @@ -5,6 +5,7 @@ namespace Yiisoft\Yii\View\Tests\Support; use Yiisoft\Html\Html; +use Yiisoft\View\WebView; use Yiisoft\Yii\View\ContentParametersInjectionInterface; use Yiisoft\Yii\View\LayoutParametersInjectionInterface; use Yiisoft\Yii\View\LinkTagsInjectionInterface; @@ -29,16 +30,30 @@ public function getLayoutParameters(): array public function getLinkTags(): array { return [ - 'favicon' => Html::link('/icon.png', [ - 'rel' => 'icon', - 'type' => 'image/png', - ]), + 'favicon' => Html::link( + '/icon.png', + [ + 'rel' => 'icon', + 'type' => 'image/png', + ] + ), + [ + 'rel' => 'preload', + 'href' => 'myFont.woff2', + 'as' => 'font', + 'type' => 'font/woff2', + ], + [ + Html::link('fancy.css', ['rel' => 'alternate stylesheet']), + '__position' => WebView::POSITION_END, + ], ]; } public function getMetaTags(): array { return [ + ['charset' => 'utf-8'], 'description' => Html::meta([ 'name' => 'description', 'content' => 'This website is about funny raccoons.', diff --git a/tests/Support/TestTrait.php b/tests/Support/TestTrait.php new file mode 100644 index 0000000..f1fa6e0 --- /dev/null +++ b/tests/Support/TestTrait.php @@ -0,0 +1,47 @@ +assertEquals($expected, $actual, $message); + } + + /** + * Asserts that a string starts with a given prefix ignoring line endings. + */ + protected function assertStringStartsWithIgnoringLineEndings( + string $prefix, + string $string, + string $message = '' + ): void { + $prefix = self::normalizeLineEndings($prefix); + $string = self::normalizeLineEndings($string); + + $this->assertStringStartsWith($prefix, $string, $message); + } + + private static function normalizeLineEndings(string $value): string + { + return strtr( + $value, + [ + "\r\n" => "\n", + "\r" => "\n", + ] + ); + } +} diff --git a/tests/ViewRendererTest.php b/tests/ViewRendererTest.php index 900bfc8..576cd4d 100644 --- a/tests/ViewRendererTest.php +++ b/tests/ViewRendererTest.php @@ -6,19 +6,26 @@ use Nyholm\Psr7\Factory\Psr17Factory; use PHPUnit\Framework\TestCase; -use Psr\Log\NullLogger; use RuntimeException; use stdClass; use Yiisoft\Aliases\Aliases; use Yiisoft\DataResponse\DataResponseFactory; use Yiisoft\Test\Support\EventDispatcher\SimpleEventDispatcher; use Yiisoft\View\WebView; +use Yiisoft\Yii\View\Exception\InvalidLinkTagException; +use Yiisoft\Yii\View\Exception\InvalidMetaTagException; use Yiisoft\Yii\View\Tests\Support\FakeController; +use Yiisoft\Yii\View\Tests\Support\InvalidLinkTagInjection; +use Yiisoft\Yii\View\Tests\Support\InvalidPositionInLinkTagInjection; +use Yiisoft\Yii\View\Tests\Support\InvalidMetaTagInjection; use Yiisoft\Yii\View\Tests\Support\TestInjection; +use Yiisoft\Yii\View\Tests\Support\TestTrait; use Yiisoft\Yii\View\ViewRenderer; final class ViewRendererTest extends TestCase { + use TestTrait; + public function testRender(): void { $renderer = $this->getRenderer() @@ -32,16 +39,18 @@ public function testRender(): void $expected = <<<'EOD' - - + + + +

donatello

copyright
- + EOD; - $this->assertSameWithoutLE($expected, (string)$response->getBody()); + $this->assertEqualStringsIgnoringLineEndings($expected, (string)$response->getBody()); } public function testRenderWithFullPathLayout(): void @@ -118,6 +127,48 @@ public function testWithViewPathWithAlias(): void $this->assertSame($this->getViewsDir() . '/dir', $renderer->getViewPath()); } + public function testInvalidMetaTag(): void + { + $renderer = $this->getRenderer() + ->withInjections(new InvalidMetaTagInjection()); + + $response = $renderer->render('empty'); + + $this->expectException(InvalidMetaTagException::class); + $this->expectExceptionMessage( + 'Meta tag in injection should be instance of Yiisoft\Html\Tag\Meta or an array. Got string.' + ); + $response->getBody(); + } + + public function testInvalidLinkTag(): void + { + $renderer = $this->getRenderer() + ->withInjections(new InvalidLinkTagInjection()); + + $response = $renderer->render('empty'); + + $this->expectException(InvalidLinkTagException::class); + $this->expectExceptionMessage( + 'Link tag in injection should be instance of Yiisoft\Html\Tag\Link or an array. Got string.' + ); + $response->getBody(); + } + + public function testInvalidPositionInLinkTag(): void + { + $renderer = $this->getRenderer() + ->withInjections(new InvalidPositionInLinkTagInjection()); + + $response = $renderer->render('empty'); + + $this->expectException(InvalidLinkTagException::class); + $this->expectExceptionMessage( + 'Link tag position in injection should be integer. Got string.' + ); + $response->getBody(); + } + public function testImmutability(): void { $original = $this->getRenderer(); @@ -139,8 +190,7 @@ private function getRenderer(): ViewRenderer new Aliases(['@views' => $this->getViewsDir()]), new WebView( '@views', - new SimpleEventDispatcher(), - new NullLogger() + new SimpleEventDispatcher() ), '@views', '@views/layout' @@ -151,18 +201,4 @@ private function getViewsDir(): string { return __DIR__ . '/views'; } - - /** - * Asserting two strings equality ignoring line endings. - * - * @param string $expected - * @param string $actual - * @param string $message - */ - public function assertSameWithoutLE(string $expected, string $actual, string $message = ''): void - { - $expected = str_replace("\r\n", "\n", $expected); - $actual = str_replace("\r\n", "\n", $actual); - $this->assertSame($expected, $actual, $message); - } } diff --git a/tests/views/empty.php b/tests/views/empty.php new file mode 100644 index 0000000..e69de29