forked from cakephp/cakephp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add mixin and template to associations, add PHPStan support for it
- Loading branch information
Showing
6 changed files
with
104 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
tests/PHPStan/PhpDoc/TableAssociationTypeNodeResolverExtension.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Cake\PHPStan\PhpDoc; | ||
|
||
use Cake\ORM\Association; | ||
use Cake\ORM\Association\BelongsTo; | ||
use Cake\ORM\Association\BelongsToMany; | ||
use Cake\ORM\Association\HasMany; | ||
use Cake\ORM\Association\HasOne; | ||
use PHPStan\Analyser\NameScope; | ||
use PHPStan\PhpDoc\TypeNodeResolver; | ||
use PHPStan\PhpDoc\TypeNodeResolverAwareExtension; | ||
use PHPStan\PhpDoc\TypeNodeResolverExtension; | ||
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; | ||
use PHPStan\PhpDocParser\Ast\Type\TypeNode; | ||
use PHPStan\Type\Generic\GenericObjectType; | ||
use PHPStan\Type\ObjectType; | ||
use PHPStan\Type\Type; | ||
|
||
/** | ||
* Fix intersection association phpDoc to correct generic object type, ex: | ||
* | ||
* Change `\Cake\ORM\Association\BelongsTo&\App\Model\Table\UsersTable` to `\Cake\ORM\Association\BelongsTo<\App\Model\Table\UsersTable>` | ||
* | ||
* The type `\Cake\ORM\Association\BelongsTo&\App\Model\Table\UsersTable` is considered invalid (NeverType) by PHPStan | ||
*/ | ||
class TableAssociationTypeNodeResolverExtension implements TypeNodeResolverExtension, TypeNodeResolverAwareExtension | ||
{ | ||
private TypeNodeResolver $typeNodeResolver; | ||
|
||
/** | ||
* @var array<string> | ||
*/ | ||
protected array $associationTypes = [ | ||
BelongsTo::class, | ||
BelongsToMany::class, | ||
HasMany::class, | ||
HasOne::class, | ||
Association::class, | ||
]; | ||
|
||
/** | ||
* @param \PHPStan\PhpDoc\TypeNodeResolver $typeNodeResolver | ||
* @return void | ||
*/ | ||
public function setTypeNodeResolver(TypeNodeResolver $typeNodeResolver): void | ||
{ | ||
$this->typeNodeResolver = $typeNodeResolver; | ||
} | ||
|
||
/** | ||
* @param \PHPStan\PhpDocParser\Ast\Type\TypeNode $typeNode | ||
* @param \PHPStan\Analyser\NameScope $nameScope | ||
* @return \PHPStan\Type\Type|null | ||
*/ | ||
public function resolve(TypeNode $typeNode, NameScope $nameScope): ?Type | ||
{ | ||
if (!$typeNode instanceof IntersectionTypeNode) { | ||
return null; | ||
} | ||
$types = $this->typeNodeResolver->resolveMultiple($typeNode->types, $nameScope); | ||
$config = [ | ||
'association' => null, | ||
'table' => null, | ||
]; | ||
foreach ($types as $type) { | ||
if (!$type instanceof ObjectType) { | ||
continue; | ||
} | ||
$className = $type->getClassName(); | ||
if ($config['association'] === null && in_array($className, $this->associationTypes)) { | ||
$config['association'] = $type; | ||
} elseif ($config['table'] === null && str_ends_with($className, 'Table')) { | ||
$config['table'] = $type; | ||
} | ||
} | ||
if ($config['table'] && $config['association']) { | ||
return new GenericObjectType( | ||
$config['association']->getClassName(), | ||
[$config['table']] | ||
); | ||
} | ||
|
||
return null; | ||
} | ||
} |