1
0
mirror of https://github.com/flarum/core.git synced 2025-07-23 17:51:24 +02:00
Files
php-flarum/php-packages/phpstan/src/Properties/ModelRelationsExtension.php
2021-12-28 20:45:22 -05:00

117 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Flarum\PHPStan\Properties;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Str;
use Flarum\PHPStan\Concerns;
use Flarum\PHPStan\Methods\BuilderHelper;
use Flarum\PHPStan\Reflection\ReflectionHelper;
use Flarum\PHPStan\Types\RelationParserHelper;
use PHPStan\Analyser\OutOfClassScope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\PropertiesClassReflectionExtension;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
/**
* @internal
*/
final class ModelRelationsExtension implements PropertiesClassReflectionExtension
{
use Concerns\HasContainer;
/** @var RelationParserHelper */
private $relationParserHelper;
/** @var BuilderHelper */
private $builderHelper;
public function __construct(
RelationParserHelper $relationParserHelper,
BuilderHelper $builderHelper)
{
$this->relationParserHelper = $relationParserHelper;
$this->builderHelper = $builderHelper;
}
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool
{
if (! $classReflection->isSubclassOf(Model::class)) {
return false;
}
if (ReflectionHelper::hasPropertyTag($classReflection, $propertyName)) {
return false;
}
$hasNativeMethod = $classReflection->hasNativeMethod($propertyName);
if (! $hasNativeMethod) {
return false;
}
$returnType = ParametersAcceptorSelector::selectSingle($classReflection->getNativeMethod($propertyName)->getVariants())->getReturnType();
if (! (new ObjectType(Relation::class))->isSuperTypeOf($returnType)->yes()) {
return false;
}
return true;
}
public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection
{
$method = $classReflection->getMethod($propertyName, new OutOfClassScope());
/** @var ObjectType $returnType */
$returnType = ParametersAcceptorSelector::selectSingle($method->getVariants())->getReturnType();
if ($returnType instanceof GenericObjectType) {
/** @var ObjectType $relatedModelType */
$relatedModelType = $returnType->getTypes()[0];
$relatedModelClassName = $relatedModelType->getClassName();
} else {
$relatedModelClassName = $this
->relationParserHelper
->findRelatedModelInRelationMethod($method);
}
if ($relatedModelClassName === null) {
$relatedModelClassName = Model::class;
}
$relatedModel = new ObjectType($relatedModelClassName);
$collectionClass = $this->builderHelper->determineCollectionClassName($relatedModelClassName);
if (Str::contains($returnType->getClassName(), 'Many')) {
return new ModelProperty(
$classReflection,
new GenericObjectType($collectionClass, [$relatedModel]),
new NeverType(), false
);
}
if (Str::endsWith($returnType->getClassName(), 'MorphTo')) {
return new ModelProperty($classReflection, new UnionType([
new ObjectType(Model::class),
new MixedType(),
]), new NeverType(), false);
}
return new ModelProperty($classReflection, new UnionType([
$relatedModel,
new NullType(),
]), new NeverType(), false);
}
}