-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.
+
+
+
+
### 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
+[](https://www.php.net/releases/8.1/en.php)
+[](https://github.com/yiisoft/yii2/tree/2.0.53)
+[](https://github.com/yiisoft/yii2/tree/22.0)
[](https://packagist.org/packages/yii2-extensions/phpstan)
-[](https://packagist.org/packages/yii2-extensions/phpstan)
+[](https://packagist.org/packages/yii2-extensions/phpstan)
## Quality code
[](https://codecov.io/github/yii2-extensions/phpstan)
[](https://github.com/yii2-extensions/phpstan/actions/workflows/static.yml)
+[](https://github.com/yii2-extensions/phpstan/actions/workflows/linter.yml)
[](https://github.styleci.io/repos/701347895?branch=main)
## Our social networks
@@ -273,4 +240,4 @@ For detailed configuration options and advanced usage.
## License
-[](LICENSE.md)
+[](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 @@
+
+
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 @@
+
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')]