Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,14 @@ services:
tags:
- phpstan.broker.expressionTypeResolverExtension
-
factory: CakeDC\PHPStan\Type\BaseTraitExpressionTypeResolverExtension(Cake\ORM\Locator\LocatorAwareTrait, fetchTable, %s\Model\Table\%sTable, defaultTable)
factory: CakeDC\PHPStan\Type\BaseTraitExpressionTypeResolverExtension(Cake\ORM\Locator\LocatorAwareTrait, fetchTable, %s\Model\Table\%sTable, @CakeDC\PHPStan\Utility\CakeNameRegistry, defaultTable)
tags:
- phpstan.broker.expressionTypeResolverExtension
-
class: CakeDC\PHPStan\Type\TypeFactoryBuildDynamicReturnTypeExtension
tags:
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
-
class: CakeDC\PHPStan\Utility\CakeNameRegistry
arguments:
appNamespace: %cakeDC.appNamespace%
2 changes: 2 additions & 0 deletions rules.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
parameters:
cakeDC:
appNamespace: App
addAssociationExistsTableClassRule: true
addAssociationMatchOptionsTypesRule: true
addBehaviorExistsClassRule: true
Expand All @@ -13,6 +14,7 @@ parameters:
disallowDebugStaticCallRule: true
parametersSchema:
cakeDC: structure([
appNamespace: string()
addAssociationExistsTableClassRule: anyOf(bool(), arrayOf(bool()))
addAssociationMatchOptionsTypesRule: anyOf(bool(), arrayOf(bool()))
addBehaviorExistsClassRule: anyOf(bool(), arrayOf(bool()))
Expand Down
12 changes: 11 additions & 1 deletion src/Rule/Controller/LoadComponentExistsClassRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,22 @@ class LoadComponentExistsClassRule extends LoadObjectExistsCakeClassRule
'load',
];

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* @param \CakeDC\PHPStan\Utility\CakeNameRegistry $cakeNameRegistry
*/
public function __construct(?CakeNameRegistry $cakeNameRegistry = null)
{
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
}

/**
* @inheritDoc
*/
protected function getTargetClassName(string $name): ?string
{
return CakeNameRegistry::getComponentClassName($name);
return $this->cakeNameRegistry->getComponentClassName($name);
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/Rule/Mailer/GetMailerExistsClassRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ class GetMailerExistsClassRule implements Rule
*/
protected string $identifier = 'cake.getMailer.existClass';

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* @param \CakeDC\PHPStan\Utility\CakeNameRegistry $cakeNameRegistry
*/
public function __construct(?CakeNameRegistry $cakeNameRegistry = null)
{
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed $this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();? PHPStan should inject CakeNameRegistry

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rochamarcelo this was added for BC (see #66 (comment)). I can revert the change if is not needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Lets keep it for now.

}

/**
* @inheritDoc
*/
Expand Down Expand Up @@ -66,7 +76,7 @@ public function processNode(Node $node, Scope $scope): array
}
$reflection = $callerType->getClassReflection();

if (CakeNameRegistry::getMailerClassName($value->value) !== null) {
if ($this->cakeNameRegistry->getMailerClassName($value->value) !== null) {
return [];
}

Expand Down
12 changes: 11 additions & 1 deletion src/Rule/Model/AddAssociationExistsTableClassRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,22 @@ class AddAssociationExistsTableClassRule extends LoadObjectExistsCakeClassRule
*/
protected array $associationCollectionMethods = ['load'];

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* @param \CakeDC\PHPStan\Utility\CakeNameRegistry $cakeNameRegistry
*/
public function __construct(?CakeNameRegistry $cakeNameRegistry = null)
{
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

}

/**
* @inheritDoc
*/
protected function getTargetClassName(string $name): ?string
{
return CakeNameRegistry::getTableClassName($name);
return $this->cakeNameRegistry->getTableClassName($name);
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/Rule/Model/AddBehaviorExistsClassRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,22 @@ class AddBehaviorExistsClassRule extends LoadObjectExistsCakeClassRule
'load',
];

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* @param \CakeDC\PHPStan\Utility\CakeNameRegistry $cakeNameRegistry
*/
public function __construct(?CakeNameRegistry $cakeNameRegistry = null)
{
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

}

/**
* @inheritDoc
*/
protected function getTargetClassName(string $name): ?string
{
return CakeNameRegistry::getBehaviorClassName($name);
return $this->cakeNameRegistry->getBehaviorClassName($name);
}

/**
Expand Down
3 changes: 1 addition & 2 deletions src/Traits/BaseCakeRegistryReturnTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

namespace CakeDC\PHPStan\Traits;

use CakeDC\PHPStan\Utility\CakeNameRegistry;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
Expand Down Expand Up @@ -75,7 +74,7 @@ public function isMethodSupported(MethodReflection $methodReflection): bool
*/
protected function getCakeType(string $baseName): ObjectType
{
$className = CakeNameRegistry::getClassName($baseName, $this->namespaceFormat);
$className = $this->cakeNameRegistry->getClassName($baseName, $this->namespaceFormat);
if ($className !== null) {
return new ObjectType($className);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Type/BaseTraitExpressionTypeResolverExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function __construct(
protected string $targetTrait,
protected string $methodName,
protected string $namespaceFormat,
protected CakeNameRegistry $cakeNameRegistry,
protected ?string $propertyDefaultValue = null,
) {
}
Expand Down Expand Up @@ -74,7 +75,7 @@ public function getType(Expr $expr, Scope $scope): ?Type
if ($baseName === null) {
return null;
}
$className = CakeNameRegistry::getClassName($baseName, $this->namespaceFormat);
$className = $this->cakeNameRegistry->getClassName($baseName, $this->namespaceFormat);
if ($className !== null) {
return new ObjectType($className);
}
Expand Down
6 changes: 5 additions & 1 deletion src/Type/ComponentLoadDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Cake\Controller\Component;
use Cake\Controller\Controller;
use CakeDC\PHPStan\Traits\BaseCakeRegistryReturnTrait;
use CakeDC\PHPStan\Utility\CakeNameRegistry;
use PHPStan\Type\DynamicMethodReturnTypeExtension;

class ComponentLoadDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
Expand All @@ -40,14 +41,17 @@ class ComponentLoadDynamicReturnTypeExtension implements DynamicMethodReturnType
*/
protected string $namespaceFormat;

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* TableLocatorDynamicReturnTypeExtension constructor.
*/
public function __construct()
public function __construct(?CakeNameRegistry $cakeNameRegistry = null)
{
$this->className = Controller::class;
$this->methodName = 'loadComponent';
$this->defaultClass = Component::class;
$this->namespaceFormat = '%s\\Controller\Component\\%sComponent';
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
}
}
6 changes: 5 additions & 1 deletion src/Type/ConsoleHelperLoadDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Cake\Console\ConsoleIo;
use Cake\Console\Helper;
use CakeDC\PHPStan\Traits\BaseCakeRegistryReturnTrait;
use CakeDC\PHPStan\Utility\CakeNameRegistry;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\Type;

Expand All @@ -42,15 +43,18 @@ class ConsoleHelperLoadDynamicReturnTypeExtension implements DynamicMethodReturn
*/
protected string $namespaceFormat;

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* TableLocatorDynamicReturnTypeExtension constructor.
*/
public function __construct()
public function __construct(?CakeNameRegistry $cakeNameRegistry = null)
{
$this->className = ConsoleIo::class;
$this->methodName = 'helper';
$this->defaultClass = Helper::class;
$this->namespaceFormat = '%s\\Command\Helper\\%sHelper';
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/Type/RepositoryEntityDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Cake\Utility\Inflector;
use CakeDC\PHPStan\Traits\BaseCakeRegistryReturnTrait;
use CakeDC\PHPStan\Traits\RepositoryReferenceTrait;
use CakeDC\PHPStan\Utility\CakeNameRegistry;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
Expand Down Expand Up @@ -56,14 +57,17 @@ class RepositoryEntityDynamicReturnTypeExtension implements DynamicMethodReturnT
*/
protected string $namespaceFormat;

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* @param class-string $className The target className.
*/
public function __construct(string $className)
public function __construct(string $className, ?CakeNameRegistry $cakeNameRegistry = null)
{
$this->className = $className;
$this->defaultClass = EntityInterface::class;
$this->namespaceFormat = '%s\\Model\Entity\\%s';
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here.

}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/Type/RepositoryFirstArgIsTheReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Cake\Datasource\EntityInterface;
use CakeDC\PHPStan\Traits\BaseCakeRegistryReturnTrait;
use CakeDC\PHPStan\Utility\CakeNameRegistry;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
Expand Down Expand Up @@ -56,14 +57,17 @@ class RepositoryFirstArgIsTheReturnTypeExtension implements DynamicMethodReturnT
*/
protected string $namespaceFormat;

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* @param class-string $className The target className.
*/
public function __construct(string $className)
public function __construct(string $className, ?CakeNameRegistry $cakeNameRegistry = null)
{
$this->className = $className;
$this->defaultClass = EntityInterface::class;
$this->namespaceFormat = '%s\\Model\Entity\\%s';
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/Type/TableLocatorDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Cake\ORM\Table;
use CakeDC\PHPStan\Traits\BaseCakeRegistryReturnTrait;
use CakeDC\PHPStan\Utility\CakeNameRegistry;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\Scope;
Expand All @@ -41,18 +42,21 @@ class TableLocatorDynamicReturnTypeExtension implements DynamicMethodReturnTypeE
protected string $defaultClass;
protected string $namespaceFormat;

private readonly CakeNameRegistry $cakeNameRegistry;

/**
* TableLocatorDynamicReturnTypeExtension constructor.
*
* @param class-string $className The target className.
* @param string $methodName The dynamic method to handle.
*/
public function __construct(string $className, string $methodName)
public function __construct(string $className, string $methodName, ?CakeNameRegistry $cakeNameRegistry = null)
{
$this->className = $className;
$this->methodName = $methodName;
$this->defaultClass = Table::class;
$this->namespaceFormat = '%s\\Model\\Table\\%sTable';
$this->cakeNameRegistry = $cakeNameRegistry ?? CakeNameRegistry::instance();
}

/**
Expand Down
35 changes: 25 additions & 10 deletions src/Utility/CakeNameRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@

class CakeNameRegistry
{
/**
* @param string $appNamespace The application's namespace.
*/
public function __construct(private readonly string $appNamespace)
{
}

/**
* @param string $appNamespace The application's namespace.
*/
public static function instance(string $appNamespace = 'App'): self
{
return new self($appNamespace);
}

/**
* @param string $baseName
* @return array{string|null,string}
Expand All @@ -22,14 +37,14 @@ protected static function pluginSplit(string $baseName): array
* @param array<string>|string $namespaceFormat
* @return string|null
*/
public static function getClassName(string $baseName, string|array $namespaceFormat): ?string
public function getClassName(string $baseName, string|array $namespaceFormat): ?string
{
if (str_contains($baseName, '\\')) {
return class_exists($baseName) ? $baseName : null;
}

[$plugin, $name] = static::pluginSplit($baseName);
$prefixes = $plugin !== null ? [$plugin] : ['App', 'Cake'];
$prefixes = $plugin !== null ? [$plugin] : [$this->appNamespace, 'Cake'];
$namespaceFormat = (array)$namespaceFormat;
foreach ($namespaceFormat as $format) {
foreach ($prefixes as $prefix) {
Expand All @@ -48,9 +63,9 @@ public static function getClassName(string $baseName, string|array $namespaceFor
* @param string $name
* @return string|null
*/
public static function getComponentClassName(string $name): ?string
public function getComponentClassName(string $name): ?string
{
return static::getClassName($name, [
return $this->getClassName($name, [
'%s\\Controller\\Component\\%sComponent',
'%s\\Controller\\Component\\%sComponent',
]);
Expand All @@ -60,9 +75,9 @@ public static function getComponentClassName(string $name): ?string
* @param string $name
* @return string|null
*/
public static function getBehaviorClassName(string $name): ?string
public function getBehaviorClassName(string $name): ?string
{
return static::getClassName($name, [
return $this->getClassName($name, [
'%s\\Model\\Behavior\\%sBehavior',
'%s\\ORM\\Behavior\\%sBehavior',
]);
Expand All @@ -72,9 +87,9 @@ public static function getBehaviorClassName(string $name): ?string
* @param string $name
* @return string|null
*/
public static function getTableClassName(string $name): ?string
public function getTableClassName(string $name): ?string
{
return static::getClassName($name, [
return $this->getClassName($name, [
'%s\\Model\\Table\\%sTable',
]);
}
Expand All @@ -83,9 +98,9 @@ public static function getTableClassName(string $name): ?string
* @param string $name
* @return string|null
*/
public static function getMailerClassName(string $name): ?string
public function getMailerClassName(string $name): ?string
{
return static::getClassName($name, [
return $this->getClassName($name, [
'%s\\Mailer\\%sMailer',
]);
}
Expand Down
Loading
Loading