diff --git a/.editorconfig b/.editorconfig index 63cd4cf..42f292d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,21 +10,22 @@ indent_style = space indent_size = 4 trim_trailing_whitespace = true -[*.php] -ij_php_space_before_short_closure_left_parenthesis = false -ij_php_space_after_type_cast = true +[*.js] +indent_size = 2 [*.md] trim_trailing_whitespace = false -[*.neon] -indent_size = 4 +[*.php] +ij_php_space_before_short_closure_left_parenthesis = false +ij_php_space_after_type_cast = true -[*.yml] +[*.yaml] indent_size = 2 -[*.xml] +[*.yml] indent_size = 2 -[*.xml.dist] -indent_size = 2 +[LICENSE*] +indent_style = unset +indent_size = unset diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 1946f00..6ed6edb 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -9,34 +9,34 @@ respect all community members. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall community +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities -Core team members are responsible for clarifying and enforcing our standards of acceptable behavior and will take +Core team members are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Core team members have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, -issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for +issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing -the community in public spaces. Examples of representing a project or community include using an official e-mail +the community in public spaces. Examples of representing a project or community include using an official email address, posting via an official social media account, within project GitHub, official forum or acting as an appointed representative at an online or offline event. @@ -54,7 +54,7 @@ deem in violation of this Code of Conduct: ### 1. Correction -**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from core team members, providing clarity around the nature of the violation @@ -66,7 +66,7 @@ and an explanation of why the behavior was inappropriate. A public apology may b **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding -interactions in community spaces as well as external channels like social media. Violating these terms may lead to +interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 4b4046c..102c3ed 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,2 @@ -# These are supported funding model platforms - +--- github: [terabytesoftw] diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 7e17783..0d78c31 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,14 +1,15 @@ -### What steps will reproduce the problem? +# Issue Report -### What is the expected result? +## What steps will reproduce the problem? -### What do you get instead? +## What is the expected result? +## What do you get instead? -### Additional info +## Additional info -| Q | A -| ---------------- | --- -| Version | 1.0.? -| PHP version | -| Operating system | +| Q | A | +| ---------------- | ----- | +| Version | 1.0.? | +| PHP version | | +| Operating system | | diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cecccf6..caa140a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,8 @@ -| Q | A -| ------------- | --- -| Is bugfix? | ✔️/❌ -| New feature? | ✔️/❌ -| Breaks BC? | ✔️/❌ -| Fixed issues | +# Pull Request + +| Q | A | +| ------------ | ------------------------------------------------------------------ | +| Is bugfix? | ✔️/❌ | +| New feature? | ✔️/❌ | +| Breaks BC? | ✔️/❌ | +| Fixed issues | | diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c8150bf..ce0844c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,4 @@ +--- version: 2 updates: # Maintain dependencies for GitHub Actions diff --git a/.github/linters/actionlint.yml b/.github/linters/actionlint.yml new file mode 100644 index 0000000..785d850 --- /dev/null +++ b/.github/linters/actionlint.yml @@ -0,0 +1,7 @@ +--- +paths: + .github/workflows/**/*.yml: + ignore: + - '"pull_request" section is alias node but mapping node is expected' + - '"push" section is alias node but mapping node is expected' + - "section is alias node but mapping node is expected" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ef87a7..4511553 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,35 +1,35 @@ +--- on: - pull_request: + pull_request: &ignore-paths paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' + - ".gitattributes" + - ".gitignore" + - "CHANGELOG.md" + - "docs/**" + - "README.md" - push: - paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' + push: *ignore-paths name: build +permissions: + contents: read + jobs: phpunit: - uses: php-forge/actions/.github/workflows/phpunit.yml@v2 + uses: yii2-framework/actions/.github/workflows/phpunit.yml@v1 secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: - composer-command: | - composer require yiisoft/yii2:22.0.x-dev --prefer-dist --no-progress --no-interaction --no-scripts --ansi + composer-command: require yiisoft/yii2:22.0.x-dev concurrency-group: phpunit-${{ github.workflow }}-${{ github.ref }} + hook: | + phpunit-compatibility: - uses: php-forge/actions/.github/workflows/phpunit.yml@v2 + uses: yii2-framework/actions/.github/workflows/phpunit.yml@v1 secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: - concurrency-group: phpunit-compatibility-${{ github.workflow }}-${{ github.ref }} + concurrency-group: | + phpunit-compatibility-${{ github.workflow }}-${{ github.ref }} extensions: intl diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index da5d4be..294a347 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -1,22 +1,21 @@ +--- on: - pull_request: + pull_request: &ignore-paths paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' + - ".gitattributes" + - ".gitignore" + - "CHANGELOG.md" + - "docs/**" + - "README.md" - push: - paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' + push: *ignore-paths name: Composer require checker +permissions: + contents: read + pull-requests: write + jobs: composer-require-checker: - uses: php-forge/actions/.github/workflows/composer-require-checker.yml@v2 + uses: yii2-framework/actions/.github/workflows/composer-require-checker.yml@v1 diff --git a/.github/workflows/ecs.yml b/.github/workflows/ecs.yml index c78245f..76f6a37 100644 --- a/.github/workflows/ecs.yml +++ b/.github/workflows/ecs.yml @@ -1,22 +1,21 @@ +--- on: - pull_request: + pull_request: &ignore-paths paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' + - ".gitattributes" + - ".gitignore" + - "CHANGELOG.md" + - "docs/**" + - "README.md" - push: - paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' + push: *ignore-paths name: ecs +permissions: + contents: read + pull-requests: write + jobs: easy-coding-standard: - uses: php-forge/actions/.github/workflows/ecs.yml@v2 + uses: yii2-framework/actions/.github/workflows/ecs.yml@v1 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..7b46557 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,17 @@ +--- +on: + - pull_request + - push + +name: linter + +permissions: + checks: write + contents: read + statuses: write + +jobs: + linter: + uses: yii2-framework/actions/.github/workflows/super-linter.yml@v1 + secrets: + AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index 4197bdf..7b449f7 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -1,33 +1,29 @@ +--- on: - pull_request: + pull_request: &ignore-paths paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' - - 'infection.json.dist' - - 'phpunit.xml.dist' + - ".gitattributes" + - ".gitignore" + - "CHANGELOG.md" + - "docs/**" + - "README.md" - push: - paths-ignore: - - 'docs/**' - - 'README.md' - - 'CHANGELOG.md' - - '.gitignore' - - '.gitattributes' - - 'infection.json.dist' - - 'phpunit.xml.dist' + push: *ignore-paths name: static analysis +permissions: + contents: read + pull-requests: write + jobs: phpstan: - uses: php-forge/actions/.github/workflows/phpstan.yml@v2 + uses: yii2-framework/actions/.github/workflows/phpstan.yml@v1 with: concurrency-group: phpstan-${{ github.workflow }}-${{ github.ref }} phpstan-console: - uses: php-forge/actions/.github/workflows/phpstan.yml@v2 + uses: yii2-framework/actions/.github/workflows/phpstan.yml@v1 with: - configuration: 'phpstan-console.neon' - concurrency-group: phpstan-console-${{ github.workflow }}-${{ github.ref }} + configuration: "phpstan-console.neon" + concurrency-group: | + phpstan-console-${{ github.workflow }}-${{ github.ref }} diff --git a/.gitignore b/.gitignore index 33918c0..cc9b65f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,29 @@ #code coverage -/code_coverage +code_coverage -# composer vendor dir -/vendor -/composer.lock +# composer +composer.lock + +# gitHub copilot config (if present) +.copilot/ +.github/copilot/** #node_modules -/node_modules +node_modules # phpstorm project files .idea # phpunit -phpunit.phar -.phpunit.result.cache .phpunit.cache -phpunit.xlm +.phpunit.result.cache +phpunit.xml* + +# vendor directory +vendor -#yii3 config packages -/config/packages +# vscode +.vscode # windows thumbnail cache Thumbs.db diff --git a/.styleci.yml b/.styleci.yml index f6dbf71..d7a76c2 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,3 +1,4 @@ +--- preset: psr12 risky: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 4967c07..029b86e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# Change Log +# Changelog ## 0.3.2 Under development @@ -7,6 +7,7 @@ - Bug #73: Update workflow actions to use `v1` stable version instead of `main`, update `LICENSE.md` (@terabytesoftw) - Bug #74: Update `README.md` to include `Behavior` integration section and example usage (@terabytesoftw) - Bug #75: Update `README.md` to enhance badge visibility and improve installation instructions (@terabytesoftw) +- Bug #76: Update workflows and documentation for improved CI/CD processes and feature clarity (@terabytesoftw) ## 0.3.1 August 16, 2025 @@ -15,7 +16,7 @@ - Bug #64: Correct badge URL formatting in `README.md` (@terabytesoftw) - Bug #65: Add missing `Composer` requirement in installation guide (@terabytesoftw) - Bug #66: Update license badge in `README.md` for correct display and add missing header in `LICENSE.md` (@terabytesoftw) -- Bug #67: Correct default stub file name in `StubFilesExtension.php` for accurate PHPStan analysis (@terabytesoftw) +- Bug #67: Correct default stub filename in `StubFilesExtension.php` for accurate PHPStan analysis (@terabytesoftw) - Bug #68: Refactor dynamic return type inference for `HeaderCollection::get()` method in PHPStan analysis, and add tests suite for type inference (@terabytesoftw) ## 0.3.0 June 27, 2025 @@ -73,7 +74,7 @@ - Enh #14: Consolidate `PHPUnit` workflows and update `README.md` with `Yii2` version badges (@terabytesoftw) - Bug #15: Correct badge label formatting for `Yii2` version in `README.md` (@terabytesoftw) - Bug #16: Remove duplicate concurrency settings from phpunit-compatibility job in `build.yml` (@terabytesoftw) -- Bug #17: Update changelog for version `0.2.0` with recent enhancements and bug fixes (@terabytesoftw) +- Bug #17: Update changelog for version `0.2.0` with recent enhancements and bugfixes (@terabytesoftw) - Bug #18: Add usage instructions and configuration details for `phpstan.neon` in `README.md` (@terabytesoftw) ## 0.1.0 February 27, 2024 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ece5fe --- /dev/null +++ b/LICENSE @@ -0,0 +1,31 @@ +SPDX-License-Identifier: BSD-3-Clause + +BSD 3-Clause License + +Copyright (c) 2008, Terabytesoftw (https://github.com/terabytesoftw/) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 1a93d4e..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,27 +0,0 @@ -# BSD 3-Clause License - -Copyright © 2008 by Terabytesoftw () -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. -* Neither the name of Yii2 Extensions (Terabytesoftw) nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index ea88bcf..530844a 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,35 @@ +

- - Yii Framework - -

Extension for PHPStan

+ + + + Yii Framework + +

PHPStan

+

+

- - PHP version - - - Yii 2.0.x - - - Yii 22.0.x - - PHPUnit + PHPUnit - PHPStan - + PHPStan +

-A comprehensive PHPStan extension that provides enhanced static analysis for Yii2 applications with precise type -inference, dynamic method resolution, and comprehensive property reflection. +

+ Enhanced static analysis for Yii2 applications with PHPStan
+ Precise type inference, dynamic method resolution, and comprehensive property reflection +

## Features -✅ **ActiveRecord & ActiveQuery Analysis** -- Array/object result type inference based on `asArray()` usage. -- Dynamic return type inference for `find()`, `findOne()`, `findAll()` methods. -- Generic type support for `ActiveQuery` with proper chaining. -- Hierarchical type resolution: model properties take precedence over behavior properties. -- Precise type inference for `getAttribute()` method calls based on PHPDoc annotations. -- Property type resolution from both model classes and attached behaviors. -- Relation methods (`hasOne()`, `hasMany()`) with accurate return types. -- Support for behavior property definitions through ServiceMap integration. - -✅ **Application Component Resolution** -- Automatic type inference for `Yii::$app->component` access. -- Behavior property and method reflection. -- Generic component support with configurable type parameters. -- Non-destructive generic configuration - extend without overriding defaults. -- Support for custom component configurations. -- User component with `identity`, `id`, `isGuest` property types. - -✅ **Behavior Integration** -- Behavior configuration via ServiceMap (see the Behaviors section below). -- Hierarchical type resolution: model properties take precedence over behavior properties. -- Property and method resolution from attached behaviors. - -✅ **Dependency Injection Container** -- Service map integration for custom services. -- Support for closures, singletons, and nested definitions. -- Type-safe `Container::get()` method resolution. - -✅ **Framework Integration** -- Header collection dynamic method types. -- Stub files for different application types (web, console, base). -- Support for Yii2 constants (`YII_DEBUG`, `YII_ENV_*`). - -✅ **Service Locator Component Resolution** -- Automatic fallback to mixed type for unknown component identifiers. -- Dynamic return type inference for `ServiceLocator::get()` calls. -- Priority-based resolution: ServiceMap components > ServiceMap services > Real classes > Mixed type. -- Support for all Service Locator subclasses (Application, Module, custom classes). -- Type inference with string variables and class name constants. + + + Feature Overview + ### Installation @@ -84,19 +47,19 @@ includes: parameters: level: 5 - + paths: - src - controllers - models - tmpDir: %currentWorkingDirectory%/runtime - + tmpDir: %currentWorkingDirectory%/runtime + yii2: config_path: config/phpstan-config.php component_generics: user: identityClass # Built-in (already configured) - repository: modelClass # Custom generic component + repository: modelClass # Custom generic component ``` Create a PHPStan-specific config file (`config/phpstan-config.php`). @@ -113,7 +76,7 @@ return [ app\behaviors\SoftDeleteBehavior::class, yii\behaviors\TimestampBehavior::class, ], - ], + ], 'components' => [ 'db' => [ 'class' => yii\db\Connection::class, @@ -181,7 +144,7 @@ if (Yii::$app->user->isGuest === false) { /** * @property string $slug * @property-read int $created_at - * + * * Note: `created_at` is provided by `TimestampBehavior`. */ class SoftDeleteBehavior extends \yii\base\Behavior @@ -258,13 +221,17 @@ For detailed configuration options and advanced usage. ## Package information +[![PHP](https://img.shields.io/badge/%3E%3D8.1-777BB4.svg?style=for-the-badge&logo=php&logoColor=white)](https://www.php.net/releases/8.1/en.php) +[![Yii 2.0.x](https://img.shields.io/badge/2.0.53-0073AA.svg?style=for-the-badge&logo=yii&logoColor=white)](https://github.com/yiisoft/yii2/tree/2.0.53) +[![Yii 22.0.x](https://img.shields.io/badge/22.0.x-0073AA.svg?style=for-the-badge&logo=yii&logoColor=white)](https://github.com/yiisoft/yii2/tree/22.0) [![Latest Stable Version](https://img.shields.io/packagist/v/yii2-extensions/phpstan.svg?style=for-the-badge&logo=packagist&logoColor=white&label=Stable)](https://packagist.org/packages/yii2-extensions/phpstan) -[![Total Downloads](https://img.shields.io/packagist/dt/yii2-extensions/phpstan.svg?style=for-the-badge&logo=packagist&logoColor=white&label=Downloads)](https://packagist.org/packages/yii2-extensions/phpstan) +[![Total Downloads](https://img.shields.io/packagist/dt/yii2-extensions/phpstan.svg?style=for-the-badge&logo=composer&logoColor=white&label=Downloads)](https://packagist.org/packages/yii2-extensions/phpstan) ## Quality code [![Codecov](https://img.shields.io/codecov/c/github/yii2-extensions/phpstan.svg?branch=main&style=for-the-badge&logo=codecov&logoColor=white&label=Coverage)](https://codecov.io/github/yii2-extensions/phpstan) [![PHPStan Level Max](https://img.shields.io/badge/PHPStan-Level%20Max-4F5D95.svg?style=for-the-badge&logo=php&logoColor=white)](https://github.com/yii2-extensions/phpstan/actions/workflows/static.yml) +[![Super-Linter](https://img.shields.io/github/actions/workflow/status/yii2-extensions/phpstan/linter.yml?style=for-the-badge&label=Super-Linter&logo=github)](https://github.com/yii2-extensions/phpstan/actions/workflows/linter.yml) [![StyleCI](https://img.shields.io/badge/StyleCI-Passed-44CC11.svg?style=for-the-badge&logo=styleci&logoColor=white)](https://github.styleci.io/repos/701347895?branch=main) ## Our social networks @@ -273,4 +240,4 @@ For detailed configuration options and advanced usage. ## License -[![License](https://img.shields.io/github/license/yii2-extensions/phpstan?style=for-the-badge&logo=opensourceinitiative&logoColor=white&labelColor=333333)](LICENSE.md) +[![License](https://img.shields.io/badge/License-BSD--3--Clause-brightgreen.svg?style=for-the-badge&logo=opensourceinitiative&logoColor=white&labelColor=555555)](LICENSE) diff --git a/composer.json b/composer.json index e0af7a9..b468647 100644 --- a/composer.json +++ b/composer.json @@ -34,11 +34,11 @@ "branch-alias": { "dev-main": "0.4.x-dev" }, - "phpstan": { - "includes": [ - "extension.neon" - ] - } + "phpstan": { + "includes": [ + "extension.neon" + ] + } }, "config": { "sort-packages": true, diff --git a/docs/configuration.md b/docs/configuration.md index 643ccf3..59f6347 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -18,8 +18,8 @@ parameters: paths: - src - tmpDir: %currentWorkingDirectory%/runtime - + tmpDir: %currentWorkingDirectory%/runtime + yii2: config_path: config/phpstan-config.php ``` @@ -38,7 +38,7 @@ parameters: - config/ - runtime/ - vendor/ - - web/assets/ + - web/assets/ level: 6 @@ -107,7 +107,7 @@ parameters: - commands - console - tmpDir: %currentWorkingDirectory%/runtime + tmpDir: %currentWorkingDirectory%/runtime yii2: config_path: config/phpstan-console-config.php @@ -167,14 +167,14 @@ return [ 'class' => \yii\db\Connection::class, 'dsn' => 'mysql:host=localhost;dbname=test', ], - + // User component with identity class 'user' => [ 'class' => \yii\web\User::class, 'identityClass' => \app\models\User::class, 'loginUrl' => ['/site/login'], ], - + // Mailer 'mailer' => [ 'class' => \yii\symfonymailer\Mailer::class, @@ -183,19 +183,19 @@ return [ 'host' => 'localhost', ], ], - + // Cache 'cache' => [ 'class' => \yii\caching\FileCache::class, 'cachePath' => '@runtime/cache', ], - + // Custom components 'paymentService' => [ 'class' => \app\services\PaymentService::class, 'apiKey' => 'test-key', ], - + // URL Manager 'urlManager' => [ 'class' => \yii\web\UrlManager::class, @@ -274,16 +274,16 @@ class UserController { // ✅ PHPStan knows this is User $user = Yii::$app->user; - + // ✅ PHPStan knows identity is app\models\User $identity = $user->identity; - + // ✅ PHPStan knows this is Repository $repository = Yii::$app->userRepository; - + // ✅ PHPStan knows this is Collection $collection = Yii::$app->postCollection; - + return $this->render('profile', ['user' => $identity]); } } @@ -304,16 +304,16 @@ use yii\base\Component; /** * Generic repository component. - * + * * @template T of \yii\db\ActiveRecord */ class Repository extends Component { - /** + /** * @phpstan-var class-string */ public string $modelClass; - + /** * @phpstan-return T|null */ @@ -321,7 +321,7 @@ class Repository extends Component { return $this->modelClass::findOne($id); } - + /** * @phpstan-return T[] */ @@ -343,21 +343,21 @@ use yii\base\Component; /** * Generic collection component. - * + * * @template T */ class Collection extends Component { - /** + /** * @phpstan-var class-string */ public string $elementType; - - /** + + /** * @phpstan-var T[] */ private array $items = []; - + /** * @phpstan-param T $item */ @@ -365,7 +365,7 @@ class Collection extends Component { $this->items[] = $item; } - + /** * @phpstan-return T[] */ @@ -438,19 +438,19 @@ return [ // Interface to implementation mapping \Psr\Log\LoggerInterface::class => \Monolog\Logger::class, \app\contracts\PaymentInterface::class => \app\services\StripePayment::class, - + // Service definitions 'logger' => [ 'class' => \Monolog\Logger::class, ['name' => 'app'], ], - + // Closure definitions 'eventDispatcher' => function() { return new \app\services\EventDispatcher(); }, ], - + 'singletons' => [ // Singleton services \app\services\CacheManager::class => \app\services\CacheManager::class, @@ -480,7 +480,7 @@ parameters: - vendor/ level: 8 - + paths: - src - controllers @@ -488,7 +488,7 @@ parameters: - widgets - components - tmpDir: %currentWorkingDirectory%/runtime + tmpDir: %currentWorkingDirectory%/runtime yii2: config_path: config/phpstan-config.php @@ -502,7 +502,7 @@ parameters: reportAnyTypeWideningInVarTag: true reportPossiblyNonexistentConstantArrayOffset: true reportPossiblyNonexistentGeneralArrayOffset: true - + ignoreErrors: # Ignore specific errors - '#Call to an undefined method.*#' @@ -512,7 +512,7 @@ parameters: ### Performance optimization ```neon -parameters: +parameters: # Bootstrap optimization bootstrapFiles: - vendor/autoload.php @@ -563,6 +563,7 @@ This will work with basic type inference but won't have custom component types. For projects with both web and console applications: ### Project structure + ```text phpstan-web.neon # Web-specific configuration phpstan-console.neon # Console-specific configuration @@ -570,6 +571,7 @@ phpstan.neon # Base configuration ``` ### Base configuration + ```neon # phpstan.neon includes: @@ -582,6 +584,7 @@ parameters: ``` ### Web configuration + ```neon # phpstan-web.neon includes: @@ -599,6 +602,7 @@ parameters: ``` ### Console configuration + ```neon # phpstan-console.neon includes: @@ -614,11 +618,12 @@ parameters: ``` ### Usage + ```bash # Analyze web application vendor/bin/phpstan analyse -c phpstan-web.neon -# Analyze console application +# Analyze console application vendor/bin/phpstan analyse -c phpstan-console.neon ``` diff --git a/docs/examples.md b/docs/examples.md index 2112721..1f5062b 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -22,29 +22,29 @@ class UserService // ✅ PHPStan knows this returns User|null return User::findOne($id); } - + public function getAllActiveUsers(): array { // ✅ PHPStan knows this returns User[] return User::findAll(['status' => 'active']); } - + public function getUsersAsArray(): array { // ✅ PHPStan knows this return array return User::find()->asArray()->all(); } - + public function createUser(array $attributes): User { $user = new User(); $user->setAttributes($attributes); - + if ($user->save()) { // ✅ PHPStan knows $user is a User type return $user; } - + throw new \RuntimeException('Failed to create user'); } } @@ -70,11 +70,11 @@ class PostRepository ->andWhere(['>', 'published_at', time() - 86400]) ->orderBy('published_at DESC') ->limit(10); - + // ✅ Returns Post[] return $query->all(); } - + public function getPostsAsArrayWithAuthor(): array { // ✅ PHPStan knows this return array @@ -83,7 +83,7 @@ class PostRepository ->asArray() ->all(); } - + public function getLatestPost(): Post|null { // ✅ PHPStan knows this return Post|null @@ -92,7 +92,7 @@ class PostRepository ->orderBy('created_at DESC') ->one(); } - + public function getPostsByAuthor(User $author): ActiveQuery { // ✅ Return type is inferred as ActiveQuery @@ -117,7 +117,7 @@ class UserModel extends \yii\db\ActiveRecord // ✅ PHPStan knows this return ActiveQuery return $this->hasMany(Post::class, ['author_id' => 'id']); } - + public function getProfile(): \yii\db\ActiveQuery { // ✅ PHPStan knows this return ActiveQuery @@ -134,23 +134,23 @@ class PostService ->with('posts', 'profile') ->where(['id' => $userId]) ->one(); - + if ($user !== null) { // ✅ PHPStan knows $user->posts is Post[] foreach ($user->posts as $post) { // ✅ $post is typed as Post echo $post->title; } - + // ✅ PHPStan knows $user->profile is UserProfile|null if ($user->profile !== null) { echo $user->profile->bio; } } - + return $user; } - + public function getPostsWithCategories(): array { // ✅ PHPStan knows the result structure @@ -177,13 +177,13 @@ class PostQuery extends ActiveQuery { return $this->andWhere(['status' => 'published']); } - + public function byCategory(string $categorySlug): self { return $this->joinWith('category') ->andWhere(['category.slug' => $categorySlug]); } - + public function recent(): self { return $this->orderBy('created_at DESC'); @@ -210,10 +210,10 @@ class PostController ->recent() ->limit(10) ->all(); // ✅ Returns Post[] - + return $this->render('index', ['posts' => $posts]); } - + public function actionAsArray(): array { // ✅ Array results are typed @@ -247,41 +247,41 @@ class SiteController extends Controller $response = Yii::$app->response; // Response $session = Yii::$app->session; // Session $user = Yii::$app->user; // User - + if ($request->isPost) { $postData = $request->post(); - + if ($user->login($identity)) { $session->setFlash('success', 'Login successful'); return $this->goHome(); } } - + return $this->render('login'); } - + public function actionSendEmail(): bool { // ✅ PHPStan knows mailer interface $mailer = Yii::$app->mailer; // MailerInterface - + $message = $mailer->compose() ->setFrom('noreply@example.com') ->setTo('user@example.com') ->setSubject('Test Email') ->setTextBody('This is a test email'); - + // ✅ PHPStan knows send() returns bool return $message->send(); } - + public function actionDatabaseQuery(): array { // ✅ PHPStan knows db component type $db = Yii::$app->db; // Connection - + $command = $db->createCommand('SELECT * FROM users WHERE active = :active')->bindValue(':active', 1); - + // ✅ PHPStan knows queryAll() returns array return $command->queryAll(); } @@ -305,40 +305,40 @@ class UserService if (Yii::$app->user->isGuest) { return null; } - + // ✅ PHPStan knows identity is User (from configuration) $identity = Yii::$app->user->identity; // User - + return $identity; } - + public function getUserId(): int|string|null { // ✅ PHPStan knows getId() returns int|string|null return Yii::$app->user->getId(); } - + public function checkAccess(string $permission): bool { if (Yii::$app->user->isGuest) { return false; } - + // ✅ PHPStan knows the identity type $user = Yii::$app->user->identity; - + // ✅ Method calls are typed return $user->hasPermission($permission); } - + public function getUserPreferences(): array { $user = $this->getCurrentUser(); - + if ($user === null) { return []; } - + // ✅ PHPStan tracks the User type through null checks return $user->getPreferences(); // Returns array } @@ -378,7 +378,7 @@ parameters: component_generics: userRepository: modelClass postRepository: modelClass -``` +``` Usage in controllers and services: @@ -396,7 +396,7 @@ class PaymentController extends Controller { // ✅ PHPStan knows this is PaymentService (non-generic component) $paymentService = Yii::$app->paymentService; - + $result = $paymentService->processPayment( [ 'amount' => 100.00, @@ -404,7 +404,7 @@ class PaymentController extends Controller 'token' => $this->request->post('token'), ], ); - + // ✅ PHPStan knows the return type based on method signature return $result; // array } @@ -424,37 +424,37 @@ class UserController extends Controller { // ✅ PHPStan knows this is Repository (generic component) $userRepository = Yii::$app->userRepository; - + // ✅ PHPStan knows findAll() returns app\models\User[] $users = $userRepository->findAll(); - + // ✅ PHPStan knows this is Repository (generic component) $postRepository = Yii::$app->postRepository; - + // ✅ PHPStan knows findOne() returns app\models\Post|null $post = $postRepository->findOne(1); - + return $this->render( - 'index', + 'index', [ 'users' => $users, 'post' => $post, ], ); } - + public function actionUserProfile(int $id): string { // ✅ PHPStan knows this is Repository (generic component) $repository = Yii::$app->userRepository; - + // ✅ PHPStan knows findOne() returns app\models\User|null $user = $repository->findOne($id); // app\models\User|null - + if ($user === null) { throw new \yii\web\NotFoundHttpException('User not found'); } - + // ✅ PHPStan knows $user is app\models\User (not null) return $this->render( 'profile', @@ -481,34 +481,34 @@ use yii\di\Container; class ServiceManager { private Container $container; - + public function __construct() { $this->container = new Container(); } - + public function getPaymentService(): PaymentService { // ✅ PHPStan knows this return PaymentService return $this->container->get(PaymentService::class); } - + public function processOrder(array $orderData): bool { // ✅ Type-safe service resolution $paymentService = $this->container->get(PaymentService::class); // PaymentService $emailService = $this->container->get(EmailService::class); // EmailService $cache = $this->container->get('cache'); // CacheService (if configured) or mixed - + $paymentResult = $paymentService->charge($orderData['total']); - + if ($paymentResult->isSuccessful()) { $emailService->sendOrderConfirmation($orderData); $cache->delete("cart_{$orderData['user_id']}"); - + return true; } - + return false; } } @@ -532,19 +532,19 @@ class CustomServiceManager extends ServiceLocator $email = $this->get('emailService'); // EmailService $logger = $this->get('loggerService'); // LoggerService $cache = $this->get('cacheService'); // CacheService - + try { $result = $email->send($message); $logger->info('Notification sent successfully'); $cache->delete('pending_notifications'); - + return $result; } catch (\Exception $e) { $logger->error('Failed to send notification: ' . $e->getMessage()); return false; } } - + public function getServicesByType(): array { // ✅ Different ways to resolve services @@ -571,27 +571,27 @@ return [ 'definitions' => [ // Interface to implementation mapping \Psr\Log\LoggerInterface::class => \Monolog\Logger::class, - + // Service with configuration 'logger' => [ 'class' => \Monolog\Logger::class, ], - + // Closure definition with a return type hint 'eventDispatcher' => function(): \app\services\EventDispatcher { return new \app\services\EventDispatcher(); }, - + // Service factory 'cacheManager' => [ 'class' => \app\services\CacheManager::class, ], ], - + 'singletons' => [ // Singleton services \app\services\MetricsCollector::class => \app\services\MetricsCollector::class, - + 'database' => [ 'class' => \app\services\DatabaseManager::class, ], @@ -605,23 +605,23 @@ class ApplicationService public function logActivity(string $message): void { $container = new Container(); - + // ✅ PHPStan knows this is LoggerInterface $logger = $container->get(\Psr\Log\LoggerInterface::class); $logger->info($message); - + // ✅ PHPStan knows this is EventDispatcher $dispatcher = $container->get('eventDispatcher'); $dispatcher->dispatch(new ActivityEvent($message)); } - + public function getMetrics(): array { $container = new Container(); - + // ✅ PHPStan knows this is MetricsCollector (singleton) $metrics = $container->get(\app\services\MetricsCollector::class); - + return $metrics->getAllMetrics(); // array } } @@ -641,7 +641,7 @@ class ServiceFactory public function createPaymentProcessor(string $provider): PaymentProcessorInterface { $container = new Container(); - + // ✅ Dynamic service resolution with proper typing switch ($provider) { case 'stripe': @@ -652,11 +652,11 @@ class ServiceFactory throw new \InvalidArgumentException("Unknown provider: $provider"); } } - + public function configureServices(): void { $container = new Container(); - + // ✅ Runtime service configuration $container->set( EmailServiceInterface::class, function() { @@ -666,7 +666,7 @@ class ServiceFactory return new SmtpEmailService(); } ); - + // ✅ PHPStan understands the interface type $emailService = $container->get(EmailServiceInterface::class); $emailService->send('test@example.com', 'Subject', 'Body'); @@ -688,7 +688,7 @@ use yii\db\ActiveRecord; /** * Behavior with PHPDoc property definitions. - * + * * @template T of ActiveRecord * @extends Behavior * @@ -701,20 +701,20 @@ class NestedSetsBehavior extends Behavior { /** @phpstan-var 'lft' */ public string $leftAttribute = 'lft'; - + /** @phpstan-var 'rgt' */ public string $rightAttribute = 'rgt'; - + /** @phpstan-var 'depth' */ public string $depthAttribute = 'depth'; - + public function moveAsRoot(): bool { // ✅ PHPStan now knows these are int types $leftValue = $this->getOwner()->getAttribute($this->leftAttribute); // int $rightValue = $this->getOwner()->getAttribute($this->rightAttribute); // int $depthValue = $this->getOwner()->getAttribute($this->depthAttribute); // int - + // No more manual casting needed! return $this->performMove($leftValue, $rightValue, $depthValue); } @@ -776,34 +776,34 @@ class UserService { $user = new User(); $user->setAttributes($userData); - + // ✅ PHPStan knows about behavior properties // TimestampBehavior adds these automatically // $user->created_at and $user->updated_at are typed - + if ($user->save()) { // ✅ PHPStan knows about behavior methods // SoftDeleteBehavior adds these methods $user->restore(); // Method from SoftDeleteBehavior - + return $user; } - + throw new \RuntimeException('Failed to create user'); } - + public function softDeleteUser(int $userId): bool { $user = User::findOne($userId); - + if ($user === null) { return false; } - + // ✅ PHPStan knows about behavior methods return $user->softDelete(); // Method from SoftDeleteBehavior } - + public function getDeletedUsers(): array { // ✅ PHPStan knows about behavior scopes @@ -817,21 +817,21 @@ class PostService { $post = new Post(); $post->setAttributes($postData); - + // ✅ PHPStan knows about SluggableBehavior properties // The slug property is automatically generated - + if ($post->save()) { // ✅ PHPStan knows about SeoOptimizedBehavior methods $post->generateMetaDescription(); // Method from SeoOptimizedBehavior $post->optimizeForSeo(); // Method from SeoOptimizedBehavior - + return $post; } - + throw new \RuntimeException('Failed to create post'); } - + public function updateSeoData(Post $post): void { // ✅ PHPStan knows about behavior properties @@ -858,22 +858,22 @@ class ApiController extends \yii\web\Controller public function actionHeaders(): array { $headers = $this->response->headers; // HeaderCollection - + // ✅ PHPStan knows get() return types based on third parameter - + // Returns string (default behavior) $contentType = $headers->get('Content-Type'); // string - + // Returns string (explicit true for first match) $acceptLanguage = $headers->get('Accept-Language', null, true); // string - + // Returns array (explicit false for all matches) $acceptEncodings = $headers->get('Accept-Encoding', null, false); // array - + // Dynamic behavior - returns string|array $firstOnly = $_GET['first_only'] ?? true; $cacheControl = $headers->get('Cache-Control', null, $firstOnly); // string|array - + return [ 'content_type' => $contentType, 'accept_language' => $acceptLanguage, @@ -881,21 +881,21 @@ class ApiController extends \yii\web\Controller 'cache_control' => $cacheControl, ]; } - + public function actionProcessHeaders(): void { $headers = $this->request->headers; - + // ✅ Proper type inference for different scenarios $authHeader = $headers->get('Authorization'); // string - + if ($authHeader !== null) { $this->processAuth($authHeader); // string parameter } - + // ✅ Array result handling $acceptHeaders = $headers->get('Accept', null, false); // array - + foreach ($acceptHeaders as $accept) { // ✅ $accept is typed as string $this->processAcceptType($accept); diff --git a/docs/installation.md b/docs/installation.md index 436adc4..3d2ccd0 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -62,7 +62,7 @@ Add the plugin configuration to your `composer.json`. } ``` -With this setup, the extension will be automatically registered, and you only need to configure the Yii specific +With this setup, the extension will be automatically registered, and you only need to configure the Yii specific settings. ### Manual extension registration @@ -89,7 +89,7 @@ parameters: - src - controllers - models - + tmpDir: %currentWorkingDirectory%/runtime yii2: @@ -182,9 +182,9 @@ vendor/bin/phpstan analyse You should see output similar to. -``` +```bash PHPStan - PHP Static Analysis Tool - [OK] No errors + [OK] No errors ``` ### Test type inference diff --git a/docs/svgs/features-mobile.svg b/docs/svgs/features-mobile.svg new file mode 100644 index 0000000..4eb98e1 --- /dev/null +++ b/docs/svgs/features-mobile.svg @@ -0,0 +1,75 @@ + + + +
+ +
+
+

ActiveRecord & ActiveQuery Analysis

+

Type inference • Generic support • Property resolution • Relation methods

+
+
+

Application Component Resolution

+

Auto type inference • Behavior reflection • Custom configurations • User component

+
+
+

Behavior Integration

+

ServiceMap configuration • Hierarchical resolution • Property & method types

+
+
+

Dependency Injection Container

+

Service map integration • Type-safe resolution • Closures & singletons

+
+
+

Framework Integration

+

Header collection types • Stub files • Yii2 constants support

+
+
+

Service Locator Resolution

+

Dynamic type inference • Priority-based resolution • Fallback support

+
+
+
+
+
diff --git a/docs/svgs/features.svg b/docs/svgs/features.svg new file mode 100644 index 0000000..0bb31f8 --- /dev/null +++ b/docs/svgs/features.svg @@ -0,0 +1,72 @@ + + +
+ +
+
+

ActiveRecord & ActiveQuery Analysis

+

Type inference • Generic support • Property resolution • Relation methods

+
+
+

Application Component Resolution

+

Auto type inference • Behavior reflection • Custom configurations • User component

+
+
+

Behavior Integration

+

ServiceMap configuration • Hierarchical resolution • Property & method types

+
+
+

Dependency Injection Container

+

Service map integration • Type-safe resolution • Closures & singletons

+
+
+

Framework Integration

+

Header collection types • Stub files • Yii2 constants support

+
+
+

Service Locator Resolution

+

Dynamic type inference • Priority-based resolution • Fallback support

+
+
+
+
+
diff --git a/docs/testing.md b/docs/testing.md index 6c4d33e..d768903 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -31,6 +31,6 @@ composer run static The code is tested with [PHPUnit](https://phpunit.de/). To run tests. -``` +```shell composer run test ``` diff --git a/extension.neon b/extension.neon index 76e3099..4c3f099 100644 --- a/extension.neon +++ b/extension.neon @@ -12,11 +12,11 @@ parameters: user: identityClass parametersSchema: - yii2: structure( + yii2: structure( [ - config_path: schema(string()), + config_path: schema(string()), component_generics: schema(arrayOf(string(), string())) - ] + ] ) services: diff --git a/phpstan-console.neon b/phpstan-console.neon index c52a7e1..46043ad 100644 --- a/phpstan-console.neon +++ b/phpstan-console.neon @@ -5,7 +5,7 @@ includes: parameters: bootstrapFiles: - - tests/bootstrap.php + - tests/support/bootstrap.php ignoreErrors: - '#Calling PHPStan\\Reflection\\Annotations\\AnnotationsPropertiesClassReflectionExtension\:\:(has|get)Property\(\) is not covered.+#' diff --git a/phpstan.neon b/phpstan.neon index 27d2692..1b9d82d 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -5,7 +5,7 @@ includes: parameters: bootstrapFiles: - - tests/bootstrap.php + - tests/support/bootstrap.php excludePaths: analyse: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index c6aac56..528c5b0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,29 +1,29 @@ - - - tests - - - - - ./src - - - ./src/method - ./src/property - ./src/reflection - ./src/type - - + + + tests + + + + + ./src + + + ./src/method + ./src/property + ./src/reflection + ./src/type + + diff --git a/tests/ServiceMapBehaviorTest.php b/tests/ServiceMapBehaviorTest.php index d5b8445..15d8ae9 100644 --- a/tests/ServiceMapBehaviorTest.php +++ b/tests/ServiceMapBehaviorTest.php @@ -8,7 +8,7 @@ use ReflectionException; use RuntimeException; use yii2\extensions\phpstan\ServiceMap; -use yii2\extensions\phpstan\tests\stub\{BehaviorOne, BehaviorTwo, MyComponent}; +use yii2\extensions\phpstan\tests\support\stub\{BehaviorOne, BehaviorTwo, MyComponent}; /** * Test suite for {@see ServiceMap} behavior resolution and validation logic. @@ -62,12 +62,12 @@ public function testReturnBehaviorsWhenValidClassIsString(): void { $serviceMap = new ServiceMap(self::BASE_PATH . 'phpstan-config.php'); - $behaviors = $serviceMap->getBehaviorsByClassName('yii2\extensions\phpstan\tests\stub\MyComponent'); + $behaviors = $serviceMap->getBehaviorsByClassName('yii2\extensions\phpstan\tests\support\stub\MyComponent'); self::assertSame( [ - 'yii2\extensions\phpstan\tests\stub\BehaviorOne', - 'yii2\extensions\phpstan\tests\stub\BehaviorTwo', + 'yii2\extensions\phpstan\tests\support\stub\BehaviorOne', + 'yii2\extensions\phpstan\tests\support\stub\BehaviorTwo', ], $behaviors, 'ServiceMap should return behaviors for MyComponent class.', diff --git a/tests/ServiceMapComponentTest.php b/tests/ServiceMapComponentTest.php index 478f811..5312ade 100644 --- a/tests/ServiceMapComponentTest.php +++ b/tests/ServiceMapComponentTest.php @@ -8,8 +8,7 @@ use ReflectionException; use RuntimeException; use yii2\extensions\phpstan\ServiceMap; -use yii2\extensions\phpstan\tests\stub\MyActiveRecord; -use yii2\extensions\phpstan\tests\stub\User; +use yii2\extensions\phpstan\tests\support\stub\{MyActiveRecord, User}; /** * Test suite for {@see ServiceMap} component resolution and definition behavior. @@ -73,7 +72,7 @@ public function testReturnComponentDefinitionWhenClassNameValid(): void $serviceMap = new ServiceMap(self::BASE_PATH . 'phpstan-config.php'); self::assertSame( - ['identityClass' => 'yii2\extensions\phpstan\tests\stub\User'], + ['identityClass' => 'yii2\extensions\phpstan\tests\support\stub\User'], $serviceMap->getComponentDefinitionByClassName('yii\web\User'), 'ServiceMap should return the component definition for \'yii\web\User\'.', ); diff --git a/tests/ServiceMapServiceTest.php b/tests/ServiceMapServiceTest.php index c2c6dfa..be39c03 100644 --- a/tests/ServiceMapServiceTest.php +++ b/tests/ServiceMapServiceTest.php @@ -12,7 +12,7 @@ use SplStack; use yii\base\InvalidArgumentException; use yii2\extensions\phpstan\ServiceMap; -use yii2\extensions\phpstan\tests\stub\MyActiveRecord; +use yii2\extensions\phpstan\tests\support\stub\MyActiveRecord; /** * Test suite for {@see ServiceMap} service resolution and container definition behavior. diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index 6833c48..0000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,11 +0,0 @@ - [ diff --git a/tests/config/definitions-unsupported-id-not-string.php b/tests/config/definitions-unsupported-id-not-string.php index 1c0462b..725bbac 100644 --- a/tests/config/definitions-unsupported-id-not-string.php +++ b/tests/config/definitions-unsupported-id-not-string.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use yii2\extensions\phpstan\tests\stub\MyActiveRecord; +use yii2\extensions\phpstan\tests\support\stub\MyActiveRecord; return [ 'container' => [ diff --git a/tests/config/phpstan-config.php b/tests/config/phpstan-config.php index 1f58dd6..7cb881f 100644 --- a/tests/config/phpstan-config.php +++ b/tests/config/phpstan-config.php @@ -3,7 +3,7 @@ declare(strict_types=1); use yii\web\View; -use yii2\extensions\phpstan\tests\stub\{ +use yii2\extensions\phpstan\tests\support\stub\{ BehaviorOne, BehaviorTwo, ModelWithConflictingProperty, diff --git a/tests/config/singletons-unsupported-id-not-string.php b/tests/config/singletons-unsupported-id-not-string.php index 50df872..4a3ab43 100644 --- a/tests/config/singletons-unsupported-id-not-string.php +++ b/tests/config/singletons-unsupported-id-not-string.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use yii2\extensions\phpstan\tests\stub\MyActiveRecord; +use yii2\extensions\phpstan\tests\support\stub\MyActiveRecord; return [ 'container' => [ diff --git a/tests/data/method/BehaviorMethodsClassReflectionType.php b/tests/data/method/BehaviorMethodsClassReflectionType.php index 4fb3a00..cdb6438 100644 --- a/tests/data/method/BehaviorMethodsClassReflectionType.php +++ b/tests/data/method/BehaviorMethodsClassReflectionType.php @@ -4,7 +4,7 @@ namespace yii2\extensions\phpstan\tests\data\method; -use yii2\extensions\phpstan\tests\stub\MyComponent; +use yii2\extensions\phpstan\tests\support\stub\MyComponent; use function PHPStan\Testing\assertType; diff --git a/tests/data/property/BehaviorPropertiesClassReflectionType.php b/tests/data/property/BehaviorPropertiesClassReflectionType.php index 2e9c31f..c37c663 100644 --- a/tests/data/property/BehaviorPropertiesClassReflectionType.php +++ b/tests/data/property/BehaviorPropertiesClassReflectionType.php @@ -4,7 +4,7 @@ namespace yii2\extensions\phpstan\tests\data\property; -use yii2\extensions\phpstan\tests\stub\MyComponent; +use yii2\extensions\phpstan\tests\support\stub\MyComponent; use function PHPStan\Testing\assertType; diff --git a/tests/data/property/UserPropertiesClassReflectionType.php b/tests/data/property/UserPropertiesClassReflectionType.php index 7400a3c..cd9ca35 100644 --- a/tests/data/property/UserPropertiesClassReflectionType.php +++ b/tests/data/property/UserPropertiesClassReflectionType.php @@ -40,7 +40,7 @@ public function testReturnBooleanOrNullFromValidateAuthKeyMethod(): void public function testReturnIdentityFromIdentityProperty(): void { - assertType('yii2\extensions\phpstan\tests\stub\User|null', Yii::$app->user->identity); + assertType('yii2\extensions\phpstan\tests\support\stub\User|null', Yii::$app->user->identity); } public function testReturnStringFromEmailProperty(): void diff --git a/tests/data/type/ActiveQueryDynamicMethodReturnType.php b/tests/data/type/ActiveQueryDynamicMethodReturnType.php index 725417e..5ac8ae3 100644 --- a/tests/data/type/ActiveQueryDynamicMethodReturnType.php +++ b/tests/data/type/ActiveQueryDynamicMethodReturnType.php @@ -5,8 +5,7 @@ namespace yii2\extensions\phpstan\tests\data\type; use yii\db\{ActiveQuery, ActiveRecord, Exception}; -use yii2\extensions\phpstan\tests\stub\MyActiveRecord; -use yii2\extensions\phpstan\tests\stub\Post; +use yii2\extensions\phpstan\tests\support\stub\{MyActiveRecord, Post}; use function PHPStan\Testing\assertType; @@ -41,7 +40,7 @@ public function testReturnActiveQueryWhenAsArrayWithVariableArgument(): void $useArrayFormat = ($userPreference === 'json'); assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', MyActiveRecord::find()->asArray($useArrayFormat), ); } @@ -51,30 +50,33 @@ public function testReturnActiveQueryWhenCustomQuerySubclass(): void $customQuery = Post::find(); assertType( - 'yii2\extensions\phpstan\tests\stub\PostQuery', + 'yii2\extensions\phpstan\tests\support\stub\PostQuery', $customQuery, ); assertType( - 'yii2\extensions\phpstan\tests\stub\PostQuery', + 'yii2\extensions\phpstan\tests\support\stub\PostQuery', $customQuery->asArray(), ); assertType( - 'yii2\extensions\phpstan\tests\stub\Post|null', + 'yii2\extensions\phpstan\tests\support\stub\Post|null', $customQuery->one(), ); assertType( - 'array', + 'array', $customQuery->all(), ); assertType( - 'yii2\extensions\phpstan\tests\stub\PostQuery', + 'yii2\extensions\phpstan\tests\support\stub\PostQuery', $customQuery->published(), ); } public function testReturnMyActiveRecordArrayQueryWhenAsArrayExplicitTrue(): void { - assertType('yii\db\ActiveQuery', MyActiveRecord::find()->asArray(true)); + assertType( + 'yii\db\ActiveQuery', + MyActiveRecord::find()->asArray(true), + ); } public function testReturnMyActiveRecordArrayQueryWhenChainedWithAsArray(): void @@ -85,19 +87,34 @@ public function testReturnMyActiveRecordArrayQueryWhenChainedWithAsArray(): void ->orderBy('created_at DESC') ->limit(10); - assertType('yii\db\ActiveQuery', $complexQuery); - assertType('array', $complexQuery->all()); + assertType( + 'yii\db\ActiveQuery', + $complexQuery, + ); + assertType( + 'array', + $complexQuery->all(), + ); } public function testReturnMyActiveRecordArrayWhenArraysWithCondition(): void { $arrayRecords = MyActiveRecord::find()->asArray()->where(['flag' => true])->all(); - assertType('array', $arrayRecords); + assertType( + 'array', + $arrayRecords, + ); foreach ($arrayRecords as $record) { - assertType('array{flag: bool}', $record); - assertType('bool', $record['flag']); + assertType( + 'array{flag: bool}', + $record, + ); + assertType( + 'bool', + $record['flag'], + ); } } @@ -105,18 +122,27 @@ public function testReturnMyActiveRecordArrayWhenAsArrayWithAll(): void { $arrayQuery = MyActiveRecord::find()->asArray(); - assertType('yii\db\ActiveQuery', $arrayQuery); - assertType('array', $arrayQuery->all()); + assertType( + 'yii\db\ActiveQuery', + $arrayQuery, + ); + assertType( + 'array', + $arrayQuery->all(), + ); } public function testReturnMyActiveRecordArrayWhenFindAllWithCondition(): void { $modelRecords = MyActiveRecord::findAll('condition'); - assertType('array', $modelRecords); + assertType( + 'array', + $modelRecords, + ); foreach ($modelRecords as $record) { - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', $record); + assertType('yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', $record); assertType('bool', $record->flag); } } @@ -125,12 +151,24 @@ public function testReturnMyActiveRecordArrayWhenObjectsWithCondition(): void { $objectRecords = MyActiveRecord::find()->asArray(false)->where(['condition'])->all(); - assertType('array', $objectRecords); + assertType( + 'array', + $objectRecords, + ); foreach ($objectRecords as $record) { - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', $record); - assertType('bool', $record->flag); - assertType('mixed', $record['flag']); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + $record, + ); + assertType( + 'bool', + $record->flag, + ); + assertType( + 'mixed', + $record['flag'], + ); } } @@ -147,13 +185,28 @@ public function testReturnMyActiveRecordOrNullWhenChainedWithOne(): void $records = MyActiveRecord::find()->where(['flag' => true])->one(); - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord|null', $records); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord|null', + $records, + ); if ($records !== null) { - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', $records); - assertType('mixed', $records[$offsetProp]); - assertType('bool', $records->flag); - assertType('bool', $records->save()); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + $records, + ); + assertType( + 'mixed', + $records[$offsetProp], + ); + assertType( + 'bool', + $records->flag, + ); + assertType( + 'bool', + $records->save(), + ); } } @@ -161,15 +214,27 @@ public function testReturnMyActiveRecordOrNullWhenFindBySqlWithOne(): void { $queryFromSql = MyActiveRecord::findBySql('SELECT * FROM table'); - assertType('yii\db\ActiveQuery', $queryFromSql); + assertType( + 'yii\db\ActiveQuery', + $queryFromSql, + ); $recordOne = $queryFromSql->one(); - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord|null', $recordOne); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord|null', + $recordOne, + ); if ($recordOne !== null) { - assertType('bool', $recordOne->flag); - assertType('mixed', $recordOne['flag']); + assertType( + 'bool', + $recordOne->flag, + ); + assertType( + 'mixed', + $recordOne['flag'], + ); } } @@ -177,18 +242,27 @@ public function testReturnMyActiveRecordOrNullWhenFindOneWithCondition(): void { $records = MyActiveRecord::findOne(['condition']); - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord|null', $records); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord|null', + $records, + ); if ($records !== null) { - assertType('bool', $records->flag); - assertType('mixed', $records['flag']); + assertType( + 'bool', + $records->flag, + ); + assertType( + 'mixed', + $records['flag'], + ); } } public function testReturnMyActiveRecordQueryWhenAsArrayExplicitFalse(): void { assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', MyActiveRecord::find()->asArray(false), ); } @@ -198,11 +272,11 @@ public function testReturnMyActiveRecordQueryWhenChainedWithConditions(): void $query = MyActiveRecord::find(); assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', $query, ); assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', $query->where(['active' => 1]) -> andWhere(['status' => 'published']), ); } @@ -214,10 +288,16 @@ public function testReturnUnionResultsWhenAsArrayWithVariableArgument(): void $results = MyActiveRecord::find()->asArray($asArray)->all(); - assertType('array', $results); + assertType( + 'array', + $results, + ); foreach ($results as $result) { - assertType('array{flag: bool}|yii2\extensions\phpstan\tests\stub\MyActiveRecord', $result); + assertType( + 'array{flag: bool}|yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + $result, + ); } } } diff --git a/tests/data/type/ActiveRecordDynamicMethodReturnType.php b/tests/data/type/ActiveRecordDynamicMethodReturnType.php index 706c987..c48e0f4 100644 --- a/tests/data/type/ActiveRecordDynamicMethodReturnType.php +++ b/tests/data/type/ActiveRecordDynamicMethodReturnType.php @@ -5,7 +5,7 @@ namespace yii2\extensions\phpstan\tests\data\type; use yii\db\{ActiveQuery, ActiveRecord}; -use yii2\extensions\phpstan\tests\stub\{Category, MyActiveRecord, User}; +use yii2\extensions\phpstan\tests\support\stub\{Category, MyActiveRecord, User}; use function PHPStan\Testing\assertType; @@ -58,7 +58,7 @@ public function testReturnCategoryArrayWhenHasManyWithAll(): void $model = new MyActiveRecord(); assertType( - 'array', + 'array', $model->hasMany(Category::class, ['parent_id' => 'id'])->all(), ); } @@ -68,7 +68,7 @@ public function testReturnCategoryQueryWhenHasManyChainedWithOrderAndLimit(): vo $model = new MyActiveRecord(); assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', $model->hasMany(Category::class, ['parent_id' => 'id'])->orderBy('name ASC')->limit(10), ); } @@ -78,7 +78,7 @@ public function testReturnCategoryQueryWhenHasManyWithCategoryClass(): void $model = new MyActiveRecord(); assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', $model->hasMany(Category::class, ['parent_id' => 'id']), ); } @@ -88,8 +88,8 @@ public function testReturnCategoryQueryWhenHasManyWithStringClass(): void $model = new User(); assertType( - 'yii\db\ActiveQuery', - $model->hasMany('yii2\extensions\phpstan\tests\stub\Category', ['user_id' => 'id']), + 'yii\db\ActiveQuery', + $model->hasMany('yii2\extensions\phpstan\tests\support\stub\Category', ['user_id' => 'id']), ); } @@ -118,7 +118,7 @@ public function testReturnUserOrNullWhenHasOneWithOne(): void $model = new MyActiveRecord(); assertType( - 'yii2\extensions\phpstan\tests\stub\User|null', + 'yii2\extensions\phpstan\tests\support\stub\User|null', $model->hasOne(User::class, ['id' => 'user_id'])->one(), ); } @@ -128,7 +128,7 @@ public function testReturnUserQueryWhenHasOneChainedWithWhereConditions(): void $model = new MyActiveRecord(); assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', $model ->hasOne(User::class, ['id' => 'user_id']) ->where(['active' => 1]) @@ -141,8 +141,8 @@ public function testReturnUserQueryWhenHasOneWithStringClass(): void $model = new Category(); assertType( - 'yii\db\ActiveQuery', - $model->hasOne('yii2\extensions\phpstan\tests\stub\User', ['id' => 'user_id']), + 'yii\db\ActiveQuery', + $model->hasOne('yii2\extensions\phpstan\tests\support\stub\User', ['id' => 'user_id']), ); } @@ -151,7 +151,7 @@ public function testReturnUserQueryWhenHasOneWithUserClass(): void $model = new MyActiveRecord(); assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', $model->hasOne(User::class, ['id' => 'user_id']), ); } diff --git a/tests/data/type/ActiveRecordDynamicStaticMethodReturnType.php b/tests/data/type/ActiveRecordDynamicStaticMethodReturnType.php index 8cd6332..7366100 100644 --- a/tests/data/type/ActiveRecordDynamicStaticMethodReturnType.php +++ b/tests/data/type/ActiveRecordDynamicStaticMethodReturnType.php @@ -5,7 +5,7 @@ namespace yii2\extensions\phpstan\tests\data\type; use yii\db\{ActiveQuery, ActiveRecord}; -use yii2\extensions\phpstan\tests\stub\{Category, MyActiveRecord, User}; +use yii2\extensions\phpstan\tests\support\stub\{Category, MyActiveRecord, User}; use function PHPStan\Testing\assertType; @@ -43,41 +43,56 @@ public function testReturnCategoryArrayQueryWhenFindBySqlWithAsArray(): void public function testReturnCategoryQueryWhenFindOnCategory(): void { - assertType('yii\db\ActiveQuery', Category::find()); + assertType( + 'yii\db\ActiveQuery', + Category::find(), + ); } public function testReturnMyActiveRecordArrayQueryWhenFindAsArray(): void { - assertType('yii\db\ActiveQuery', MyActiveRecord::find()->asArray()); + assertType( + 'yii\db\ActiveQuery', + MyActiveRecord::find()->asArray(), + ); } public function testReturnMyActiveRecordArrayWhenFindAllWithIds(): void { - assertType('array', MyActiveRecord::findAll([1, 2, 3])); + assertType( + 'array', + MyActiveRecord::findAll([1, 2, 3]), + ); } public function testReturnMyActiveRecordOrNullWhenFindOneAfterChaining(): void { assertType( - 'yii2\extensions\phpstan\tests\stub\MyActiveRecord|null', + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord|null', MyActiveRecord::find()->where(['status' => 'published'])->one(), ); } public function testReturnMyActiveRecordOrNullWhenFindOneById(): void { - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord|null', MyActiveRecord::findOne(1)); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord|null', + MyActiveRecord::findOne(1), + ); } public function testReturnMyActiveRecordQueryWhenFind(): void { - assertType('yii\db\ActiveQuery', MyActiveRecord::find()); + assertType( + 'yii\db\ActiveQuery', + MyActiveRecord::find(), + ); } public function testReturnMyActiveRecordQueryWhenFindBySqlWithParameters(): void { assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', MyActiveRecord::findBySql('SELECT * FROM my_table WHERE id = :id', [':id' => 1]), ); } @@ -85,43 +100,55 @@ public function testReturnMyActiveRecordQueryWhenFindBySqlWithParameters(): void public function testReturnMyActiveRecordQueryWhenFindWithChaining(): void { assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', MyActiveRecord::find()->where(['status' => 'active'])->orderBy('created_at DESC'), ); } public function testReturnMyActiveRecordWhenInstantiating(): void { - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', new MyActiveRecord()); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + new MyActiveRecord(), + ); } public function testReturnUserArrayQueryWhenFindAsArray(): void { - assertType('yii\db\ActiveQuery', User::find()->asArray()); + assertType( + 'yii\db\ActiveQuery', + User::find()->asArray(), + ); } public function testReturnUserArrayWhenFindAllAfterChaining(): void { assertType( - 'array', + 'array', User::find()->where(['active' => 1])->orderBy('name ASC')->all(), ); } public function testReturnUserArrayWhenFindAllWithCondition(): void { - assertType('array', User::findAll(['status' => 'active'])); + assertType( + 'array', + User::findAll(['status' => 'active']), + ); } public function testReturnUserOrNullWhenFindOneByCondition(): void { - assertType('yii2\extensions\phpstan\tests\stub\User|null', User::findOne(['id' => 1])); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\User|null', + User::findOne(['id' => 1]), + ); } public function testReturnUserQueryWhenFindBySql(): void { assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', User::findBySql('SELECT * FROM users'), ); } @@ -129,18 +156,24 @@ public function testReturnUserQueryWhenFindBySql(): void public function testReturnUserQueryWhenFindBySqlWithChaining(): void { assertType( - 'yii\db\ActiveQuery', + 'yii\db\ActiveQuery', User::findBySql('SELECT * FROM users')->andWhere(['active' => 1])->limit(10), ); } public function testReturnUserQueryWhenFindOnUser(): void { - assertType('yii\db\ActiveQuery', User::find()); + assertType( + 'yii\db\ActiveQuery', + User::find(), + ); } public function testReturnUserWhenInstantiating(): void { - assertType('yii2\extensions\phpstan\tests\stub\User', new User()); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\User', + new User(), + ); } } diff --git a/tests/data/type/ActiveRecordGetAttributeDynamicMethodReturnType.php b/tests/data/type/ActiveRecordGetAttributeDynamicMethodReturnType.php index 8c0c3fd..7f9c3d8 100644 --- a/tests/data/type/ActiveRecordGetAttributeDynamicMethodReturnType.php +++ b/tests/data/type/ActiveRecordGetAttributeDynamicMethodReturnType.php @@ -5,7 +5,7 @@ namespace yii2\extensions\phpstan\tests\data\type; use yii\db\ActiveRecord; -use yii2\extensions\phpstan\tests\stub\{ +use yii2\extensions\phpstan\tests\support\stub\{ ModelWithConflictingProperty, ModelWithMultipleBehaviors, NestedSetsModel, diff --git a/tests/data/type/ContainerDynamicMethodReturnType.php b/tests/data/type/ContainerDynamicMethodReturnType.php index 754fd3f..9ceedaf 100644 --- a/tests/data/type/ContainerDynamicMethodReturnType.php +++ b/tests/data/type/ContainerDynamicMethodReturnType.php @@ -7,7 +7,7 @@ use Exception; use yii\base\InvalidConfigException; use yii\di\{Container, NotInstantiableException}; -use yii2\extensions\phpstan\tests\stub\MyActiveRecord; +use yii2\extensions\phpstan\tests\support\stub\MyActiveRecord; use function PHPStan\Testing\assertType; use function random_int; @@ -45,8 +45,14 @@ public function testReturnClassWhenGetByClassName(): void $activeRecord = $container->get(MyActiveRecord::class); - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', $activeRecord); - assertType('bool', $activeRecord->flag); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + $activeRecord, + ); + assertType( + 'bool', + $activeRecord->flag, + ); } /** @@ -56,9 +62,12 @@ public function testReturnClassWhenGetByClassName(): void public function testReturnClassWhenGetByClassNameString(): void { $container = new Container(); - $className = 'yii2\extensions\phpstan\tests\stub\MyActiveRecord'; + $className = 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord'; - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', $container->get($className)); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + $container->get($className), + ); } /** @@ -69,7 +78,10 @@ public function testReturnMixedWhenGetWithUnknownId(): void { $container = new Container(); - assertType('mixed', $container->get('unknown-service')); + assertType( + 'mixed', + $container->get('unknown-service'), + ); } /** @@ -80,7 +92,10 @@ public function testReturnServiceWhenGetDefinitionClosure(): void { $container = new Container(); - assertType('SplStack', $container->get('closure')); + assertType( + 'SplStack', + $container->get('closure'), + ); } /** @@ -91,7 +106,10 @@ public function testReturnServiceWhenGetDefinitionService(): void { $container = new Container(); - assertType('SplObjectStorage', $container->get('service')); + assertType( + 'SplObjectStorage', + $container->get('service'), + ); } /** @@ -102,7 +120,10 @@ public function testReturnServiceWhenGetNestedService(): void { $container = new Container(); - assertType('SplFileInfo', $container->get('nested-service-class')); + assertType( + 'SplFileInfo', + $container->get('nested-service-class'), + ); } /** @@ -113,7 +134,10 @@ public function testReturnServiceWhenGetNestedSingleton(): void { $container = new Container(); - assertType('SplFileInfo', $container->get('singleton-nested-service-class')); + assertType( + 'SplFileInfo', + $container->get('singleton-nested-service-class'), + ); } /** @@ -124,7 +148,10 @@ public function testReturnServiceWhenGetRealClassNotInServiceMap(): void { $container = new Container(); - assertType('Exception', $container->get(Exception::class)); + assertType( + 'Exception', + $container->get(Exception::class), + ); } /** @@ -136,8 +163,8 @@ public function testReturnServiceWhenGetServiceMapWithStringConstant(): void $container = new Container(); assertType( - 'yii2\extensions\phpstan\tests\stub\MyActiveRecord', - $container->get('yii2\extensions\phpstan\tests\stub\MyActiveRecord'), + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + $container->get('yii2\extensions\phpstan\tests\support\stub\MyActiveRecord'), ); } @@ -149,7 +176,10 @@ public function testReturnServiceWhenGetSingletonClosure(): void { $container = new Container(); - assertType('SplStack', $container->get('singleton-closure')); + assertType( + 'SplStack', + $container->get('singleton-closure'), + ); } /** @@ -160,7 +190,10 @@ public function testReturnServiceWhenGetSingletonService(): void { $container = new Container(); - assertType('SplObjectStorage', $container->get('singleton-service')); + assertType( + 'SplObjectStorage', + $container->get('singleton-service'), + ); } /** @@ -171,7 +204,10 @@ public function testReturnServiceWhenGetSingletonString(): void { $container = new Container(); - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', $container->get('singleton-string')); + assertType( + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', + $container->get('singleton-string'), + ); } /** @@ -185,7 +221,10 @@ public function testReturnServiceWhenGetWithConditional(): void $useService = (bool) random_int(0, 1); $result = $useService ? $container->get('singleton-service') : $container->get('closure'); - assertType('SplObjectStorage|SplStack', $result); + assertType( + 'SplObjectStorage|SplStack', + $result, + ); } /** @@ -199,7 +238,7 @@ public function testReturnServiceWhenGetWithParameters(): void $params = ['flag' => true]; assertType( - 'yii2\extensions\phpstan\tests\stub\MyActiveRecord', + 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', $container->get(MyActiveRecord::class, $params), ); } diff --git a/tests/data/type/ServiceLocatorDynamicMethodReturnType.php b/tests/data/type/ServiceLocatorDynamicMethodReturnType.php index 43627b8..865f980 100644 --- a/tests/data/type/ServiceLocatorDynamicMethodReturnType.php +++ b/tests/data/type/ServiceLocatorDynamicMethodReturnType.php @@ -8,7 +8,7 @@ use yii\base\Module; use yii\di\ServiceLocator; use yii\web\{Application, Request, Response, Session, User}; -use yii2\extensions\phpstan\tests\stub\MyActiveRecord; +use yii2\extensions\phpstan\tests\support\stub\MyActiveRecord; use function PHPStan\Testing\assertType; @@ -41,7 +41,7 @@ public function testReturnClassWhenGetByClassName(): void { $locator = new ServiceLocator(); - assertType('yii2\extensions\phpstan\tests\stub\MyActiveRecord', $locator->get(MyActiveRecord::class)); + assertType('yii2\extensions\phpstan\tests\support\stub\MyActiveRecord', $locator->get(MyActiveRecord::class)); } /** @@ -51,7 +51,7 @@ public function testReturnClassWhenGetByClassNameString(): void { $locator = new ServiceLocator(); - $className = 'yii2\extensions\phpstan\tests\stub\MyActiveRecord'; + $className = 'yii2\extensions\phpstan\tests\support\stub\MyActiveRecord'; assertType(MyActiveRecord::class, $locator->get($className)); } diff --git a/tests/method/BehaviorMethodsClassReflectionExtensionTest.php b/tests/method/BehaviorMethodsClassReflectionExtensionTest.php index 3111fd8..6363295 100644 --- a/tests/method/BehaviorMethodsClassReflectionExtensionTest.php +++ b/tests/method/BehaviorMethodsClassReflectionExtensionTest.php @@ -42,7 +42,7 @@ public static function dataFileAsserts(): iterable public static function getAdditionalConfigFiles(): array { - return [dirname(__DIR__) . '/extension-test.neon']; + return [dirname(__DIR__) . '/support/extension-test.neon']; } #[DataProvider('dataFileAsserts')] diff --git a/tests/property/BehaviorPropertiesClassReflectionExtensionTest.php b/tests/property/BehaviorPropertiesClassReflectionExtensionTest.php index ef41f2a..7016f91 100644 --- a/tests/property/BehaviorPropertiesClassReflectionExtensionTest.php +++ b/tests/property/BehaviorPropertiesClassReflectionExtensionTest.php @@ -42,7 +42,7 @@ public static function dataFileAsserts(): iterable public static function getAdditionalConfigFiles(): array { - return [dirname(__DIR__) . '/extension-test.neon']; + return [dirname(__DIR__) . '/support/extension-test.neon']; } #[DataProvider('dataFileAsserts')] diff --git a/tests/property/UserPropertiesClassReflectionExtensionTest.php b/tests/property/UserPropertiesClassReflectionExtensionTest.php index 633d617..ffd35bf 100644 --- a/tests/property/UserPropertiesClassReflectionExtensionTest.php +++ b/tests/property/UserPropertiesClassReflectionExtensionTest.php @@ -42,7 +42,7 @@ public static function dataFileAsserts(): iterable public static function getAdditionalConfigFiles(): array { - return [dirname(__DIR__) . '/extension-test.neon']; + return [dirname(__DIR__) . '/support/extension-test.neon']; } #[DataProvider('dataFileAsserts')] diff --git a/tests/support/bootstrap.php b/tests/support/bootstrap.php new file mode 100644 index 0000000..a0295d2 --- /dev/null +++ b/tests/support/bootstrap.php @@ -0,0 +1,16 @@ +', Yii::$app->user); + assertType('yii\web\User', Yii::$app->user); } public function testReturnViewFromComponent(): void diff --git a/tests/web/property/ApplicationPropertiesClassReflectionExtensionTest.php b/tests/web/property/ApplicationPropertiesClassReflectionExtensionTest.php index 24f06aa..20d7ca1 100644 --- a/tests/web/property/ApplicationPropertiesClassReflectionExtensionTest.php +++ b/tests/web/property/ApplicationPropertiesClassReflectionExtensionTest.php @@ -42,7 +42,7 @@ public static function dataFileAsserts(): iterable public static function getAdditionalConfigFiles(): array { - return [dirname(__DIR__, 2) . '/extension-test.neon']; + return [dirname(__DIR__, 2) . '/support/extension-test.neon']; } #[DataProvider('dataFileAsserts')]