Analyze the yiiunit\framework\behaviors namespace using PHPStan (#20740)

This commit is contained in:
Maksim Spirkov
2026-02-27 09:15:44 +04:00
committed by GitHub
parent 9d10723978
commit 4440bcfa51
11 changed files with 110 additions and 26 deletions

View File

@@ -49,3 +49,21 @@ parameters:
message: "#^Parameter \\&\\$constraints by\\-ref type of method yii\\\\db\\\\QueryBuilder\\:\\:getTableUniqueColumnNames\\(\\) expects array\\<yii\\\\db\\\\Constraint\\>\\, array\\<string\\, yii\\\\db\\\\Constraint\\>\\|false given\\.$#"
count: 1
path: framework/db/QueryBuilder.php
# PHP 7.4 does not have enums, so we ignore these errors.
-
message: "#^Access to constant Active on an unknown class yiiunit\\\\framework\\\\db\\\\enums\\\\StatusTypeString\\.$#"
count: 3
path: tests/framework/behaviors/AttributeTypecastBehaviorTest.php
# PHP 7.4 does not have enums, so we ignore these errors.
-
message: "#^PHPDoc tag \\@property for property yiiunit\\\\framework\\\\behaviors\\\\ActiveRecordAttributeTypecastWithEnum\\:\\:\\$status contains unknown class yiiunit\\\\framework\\\\db\\\\enums\\\\StatusTypeString\\.$#"
count: 1
path: tests/framework/behaviors/AttributeTypecastBehaviorTest.php
# PHP 7.4 does not have enums, so we ignore these errors.
-
message: "#^Class yiiunit\\\\framework\\\\db\\\\enums\\\\StatusTypeString not found\\.$#"
count: 1
path: tests/framework/behaviors/AttributeTypecastBehaviorTest.php

View File

@@ -15,7 +15,6 @@ parameters:
- tests/data
- tests/framework/base/stub
# TODO: Analyze these directories
- tests/framework/behaviors
- tests/framework/caching
- tests/framework/console
- tests/framework/data

View File

@@ -127,6 +127,8 @@ class AttributeBehaviorTest extends TestCase
* @property string $alias
*
* @property AttributeBehavior $attributeBehavior
*
* @mixin AttributeBehavior
*/
class ActiveRecordWithAttributeBehavior extends ActiveRecord
{
@@ -161,6 +163,9 @@ class ActiveRecordWithAttributeBehavior extends ActiveRecord
*/
public function getAttributeBehavior()
{
return $this->getBehavior('attribute');
/** @var AttributeBehavior */
$result = $this->getBehavior('attribute');
return $result;
}
}

View File

@@ -337,13 +337,15 @@ class AttributeTypecastBehaviorTest extends TestCase
* Test Active Record class with [[AttributeTypecastBehavior]] behavior attached.
*
* @property int $id
* @property string $name
* @property int $amount
* @property float $price
* @property bool $isActive
* @property string $callback
* @property string|int|null $name
* @property int|string|null $amount
* @property float|string|null $price
* @property bool|int|null $isActive
* @property string|null $callback
*
* @property AttributeTypecastBehavior $attributeTypecastBehavior
*
* @mixin AttributeTypecastBehavior
*/
class ActiveRecordAttributeTypecast extends ActiveRecord
{
@@ -391,14 +393,19 @@ class ActiveRecordAttributeTypecast extends ActiveRecord
*/
public function getAttributeTypecastBehavior()
{
return $this->getBehavior('attributeTypecast');
/** @var AttributeTypecastBehavior */
$result = $this->getBehavior('attributeTypecast');
return $result;
}
}
/**
* Test Active Record class with [[AttributeTypecastBehavior]] behavior attached with an enum field.
*
* @property StatusTypeString $status
* @property StatusTypeString|string $status
*
* @mixin AttributeTypecastBehavior
*/
class ActiveRecordAttributeTypecastWithEnum extends ActiveRecord
{
@@ -425,6 +432,9 @@ class ActiveRecordAttributeTypecastWithEnum extends ActiveRecord
*/
public function getAttributeTypecastBehavior()
{
return $this->getBehavior('attributeTypecast');
/** @var AttributeTypecastBehavior */
$result = $this->getBehavior('attributeTypecast');
return $result;
}
}

View File

@@ -172,6 +172,8 @@ class AttributesBehaviorTest extends TestCase
* @property string $alias
*
* @property AttributesBehavior $attributesBehavior
*
* @mixin AttributesBehavior
*/
class ActiveRecordWithAttributesBehavior extends ActiveRecord
{
@@ -212,6 +214,9 @@ class ActiveRecordWithAttributesBehavior extends ActiveRecord
*/
public function getAttributesBehavior()
{
return $this->getBehavior('attributes');
/** @var AttributesBehavior */
$result = $this->getBehavior('attributes');
return $result;
}
}

View File

@@ -106,6 +106,8 @@ class ActiveRecordBlameableConsoleWithDefaultValueClosure extends ActiveRecordBl
* @property int $updated_by
*
* @property BlameableBehavior $blameable
*
* @mixin BlameableBehavior
*/
class ActiveRecordBlameableConsole extends ActiveRecord
{
@@ -128,7 +130,10 @@ class ActiveRecordBlameableConsole extends ActiveRecord
*/
public function getBlameable()
{
return $this->getBehavior('blameable');
/** @var BlameableBehavior */
$result = $this->getBehavior('blameable');
return $result;
}
public static function primaryKey()

View File

@@ -213,6 +213,8 @@ class ActiveRecordBlameableWithDefaultValueClosure extends ActiveRecordBlameable
* @property int $updated_by
*
* @property BlameableBehavior $blameable
*
* @mixin BlameableBehavior
*/
class ActiveRecordBlameable extends ActiveRecord
{
@@ -235,7 +237,10 @@ class ActiveRecordBlameable extends ActiveRecord
*/
public function getBlameable()
{
return $this->getBehavior('blameable');
/** @var BlameableBehavior */
$result = $this->getBehavior('blameable');
return $result;
}
public static function primaryKey()

View File

@@ -3,7 +3,7 @@
namespace yiiunit\framework\behaviors;
use Exception;
use PHPUnit_Framework_MockObject_MockObject;
use PHPUnit\Framework\MockObject\MockObject;
use yii\base\Widget;
use yii\behaviors\CacheableWidgetBehavior;
use yiiunit\TestCase;
@@ -19,14 +19,14 @@ class CacheableWidgetBehaviorTest extends TestCase
/**
* Default-initialized simple cacheable widget mock.
*
* @var PHPUnit_Framework_MockObject_MockObject|SimpleCacheableWidget|CacheableWidgetBehavior
* @var MockObject&SimpleCacheableWidget
*/
private $simpleWidget;
/**
* Default-initialized dynamic cacheable widget mock.
*
* @var PHPUnit_Framework_MockObject_MockObject|DynamicCacheableWidget|CacheableWidgetBehavior
* @var MockObject&DynamicCacheableWidget
*/
private $dynamicWidget;
@@ -114,8 +114,9 @@ class CacheableWidgetBehaviorTest extends TestCase
/**
* Returns a widget mock.
* @param $widgetClass
* @return PHPUnit_Framework_MockObject_MockObject
* @template T of BaseCacheableWidget
* @param class-string<T> $widgetClass
* @return T&MockObject
*/
private function getWidgetMock($widgetClass)
{
@@ -127,6 +128,9 @@ class CacheableWidgetBehaviorTest extends TestCase
}
}
/**
* @mixin CacheableWidgetBehavior
*/
class BaseCacheableWidget extends Widget
{
/**

View File

@@ -78,7 +78,7 @@ class OptimisticLockBehaviorTest extends TestCase
OptimisticLockBehavior::class,
];
$model = new ActiveRecordLockVersion();
$model->version = 0;
$model->version = '0';
$this->assertEquals(true, $model->save(false), 'model is successfully saved');
// upgrade model
@@ -281,8 +281,12 @@ class OptimisticLockBehaviorTest extends TestCase
* Test Active Record class with [[OptimisticLockBehavior]] behavior attached.
*
* @property int $id
* @property string $version
* @property int $created_at
* @property int $updated_at
*
* We use `mixin` here to avoid PHPStan errors.
* @mixin OptimisticLockBehavior
*/
class ActiveRecordLockVersion extends ActiveRecord
{

View File

@@ -86,7 +86,10 @@ class SluggableBehaviorTest extends TestCase
public function testSlugSeveralAttributes(): void
{
$model = new ActiveRecordSluggable();
$model->getBehavior('sluggable')->attribute = ['name', 'category_id'];
/** @var SluggableBehavior */
$sluggableBehavior = $model->getBehavior('sluggable');
$sluggableBehavior->attribute = ['name', 'category_id'];
$model->name = 'test';
$model->category_id = 10;
@@ -101,7 +104,10 @@ class SluggableBehaviorTest extends TestCase
public function testSlugRelatedAttribute(): void
{
$model = new ActiveRecordSluggable();
$model->getBehavior('sluggable')->attribute = 'related.name';
/** @var SluggableBehavior */
$sluggableBehavior = $model->getBehavior('sluggable');
$sluggableBehavior->attribute = 'related.name';
$relatedmodel = new ActiveRecordRelated();
$relatedmodel->name = 'I am an value inside an related activerecord model';
@@ -126,7 +132,7 @@ class SluggableBehaviorTest extends TestCase
$model->save();
$model = new ActiveRecordSluggableUnique();
$model->sluggable->uniqueSlugGenerator = 'increment';
$model->sluggable->uniqueSlugGenerator = null;
$model->name = $name;
$model->save();
@@ -188,6 +194,10 @@ class SluggableBehaviorTest extends TestCase
$model->save();
$this->assertEquals('test-name', $model->slug);
$model->name = '';
$model->save();
$this->assertEquals('test-name', $model->slug);
$model->name = 'test name 2';
$model->save();
$this->assertEquals('test-name-2', $model->slug);
@@ -236,11 +246,14 @@ class SluggableBehaviorTest extends TestCase
* Test Active Record class with [[SluggableBehavior]] behavior attached.
*
* @property int $id
* @property string $name
* @property string $slug
* @property int $category_id
* @property string|null $name
* @property string|null $slug
* @property int|null $category_id
* @property int|null $belongs_to_id
*
* @property SluggableBehavior $sluggable
*
* @mixin SluggableBehavior
*/
class ActiveRecordSluggable extends ActiveRecord
{
@@ -264,7 +277,10 @@ class ActiveRecordSluggable extends ActiveRecord
*/
public function getSluggable()
{
return $this->getBehavior('sluggable');
/** @var SluggableBehavior */
$result = $this->getBehavior('sluggable');
return $result;
}
public function getRelated()
@@ -273,6 +289,10 @@ class ActiveRecordSluggable extends ActiveRecord
}
}
/**
* @property int $id
* @property string|null $name
*/
class ActiveRecordRelated extends ActiveRecord
{
public static function tableName()
@@ -281,6 +301,9 @@ class ActiveRecordRelated extends ActiveRecord
}
}
/**
* @mixin SluggableBehavior
*/
class ActiveRecordSluggableUnique extends ActiveRecordSluggable
{
public function behaviors()
@@ -295,6 +318,9 @@ class ActiveRecordSluggableUnique extends ActiveRecordSluggable
}
}
/**
* @mixin SluggableBehavior
*/
class SkipOnEmptySluggableActiveRecord extends ActiveRecordSluggable
{
public function behaviors()

View File

@@ -249,6 +249,9 @@ class TimestampBehaviorTest extends TestCase
* @property int $id
* @property int $created_at
* @property int $updated_at
*
* We use `mixin` here to avoid PHPStan errors.
* @mixin TimestampBehavior
*/
class ActiveRecordTimestamp extends ActiveRecord
{