1
0
mirror of https://github.com/flarum/core.git synced 2025-07-23 09:41:26 +02:00
Files
php-flarum/php-packages/phpstan/src/Methods/EloquentBuilderForwardsCallsExtension.php
dependabot[bot] 37a882118a chore(deps): bump glob-parent from 3.1.0 to 5.1.2 in /extensions/emoji/js (#3345)
* chore(deps): bump glob-parent in /extensions/emoji/js

Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 3.1.0 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v3.1.0...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Apply fixes from StyleCI

[ci skip] [skip ci]

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: StyleCI Bot <bot@styleci.io>
2022-03-11 18:11:20 -05:00

162 lines
5.5 KiB
PHP

<?php
declare(strict_types=1);
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\PHPStan\Methods;
use Flarum\PHPStan\Reflection\EloquentBuilderMethodReflection;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use PHPStan\Analyser\OutOfClassScope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\MethodsClassReflectionExtension;
use PHPStan\Reflection\MissingMethodFromReflectionException;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\Generic\TemplateMixedType;
use PHPStan\Type\Generic\TemplateObjectType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
final class EloquentBuilderForwardsCallsExtension implements MethodsClassReflectionExtension
{
/** @var array<string, MethodReflection> */
private $cache = [];
/** @var BuilderHelper */
private $builderHelper;
/** @var ReflectionProvider */
private $reflectionProvider;
public function __construct(BuilderHelper $builderHelper, ReflectionProvider $reflectionProvider)
{
$this->builderHelper = $builderHelper;
$this->reflectionProvider = $reflectionProvider;
}
/**
* @throws ShouldNotHappenException
* @throws MissingMethodFromReflectionException
*/
public function hasMethod(ClassReflection $classReflection, string $methodName): bool
{
if (array_key_exists($classReflection->getCacheKey().'-'.$methodName, $this->cache)) {
return true;
}
$methodReflection = $this->findMethod($classReflection, $methodName);
if ($methodReflection !== null && $classReflection->isGeneric()) {
$this->cache[$classReflection->getCacheKey().'-'.$methodName] = $methodReflection;
return true;
}
return false;
}
public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection
{
return $this->cache[$classReflection->getCacheKey().'-'.$methodName];
}
/**
* @throws MissingMethodFromReflectionException
* @throws ShouldNotHappenException
*/
private function findMethod(ClassReflection $classReflection, string $methodName): ?MethodReflection
{
if ($classReflection->getName() !== EloquentBuilder::class && ! $classReflection->isSubclassOf(EloquentBuilder::class)) {
return null;
}
/** @var Type|TemplateMixedType|null $modelType */
$modelType = $classReflection->getActiveTemplateTypeMap()->getType('TModelClass');
// Generic type is not specified
if ($modelType === null) {
return null;
}
if ($modelType instanceof TemplateObjectType) {
$modelType = $modelType->getBound();
if ($modelType->equals(new ObjectType(Model::class))) {
return null;
}
}
if ($modelType instanceof TypeWithClassName) {
$modelReflection = $modelType->getClassReflection();
} else {
$modelReflection = $this->reflectionProvider->getClass(Model::class);
}
if ($modelReflection === null) {
return null;
}
$ref = $this->builderHelper->searchOnEloquentBuilder($classReflection, $methodName, $modelReflection);
if ($ref === null) {
// Special case for `SoftDeletes` trait
if (
in_array($methodName, ['withTrashed', 'onlyTrashed', 'withoutTrashed'], true) &&
in_array(SoftDeletes::class, array_keys($modelReflection->getTraits(true)))
) {
$ref = $this->reflectionProvider->getClass(SoftDeletes::class)->getMethod($methodName, new OutOfClassScope());
return new EloquentBuilderMethodReflection(
$methodName,
$classReflection,
$ref,
ParametersAcceptorSelector::selectSingle($ref->getVariants())->getParameters(),
new GenericObjectType($classReflection->getName(), [$modelType]),
ParametersAcceptorSelector::selectSingle($ref->getVariants())->isVariadic()
);
}
return null;
}
$parametersAcceptor = ParametersAcceptorSelector::selectSingle($ref->getVariants());
if (in_array($methodName, $this->builderHelper->passthru, true)) {
$returnType = $parametersAcceptor->getReturnType();
return new EloquentBuilderMethodReflection(
$methodName,
$classReflection,
$ref,
$parametersAcceptor->getParameters(),
$returnType,
$parametersAcceptor->isVariadic()
);
}
// Returning custom reflection
// to ensure return type is always `EloquentBuilder<Model>`
return new EloquentBuilderMethodReflection(
$methodName,
$classReflection,
$ref,
$parametersAcceptor->getParameters(),
new GenericObjectType($classReflection->getName(), [$modelType]),
$parametersAcceptor->isVariadic()
);
}
}