mirror of
https://github.com/flarum/framework.git
synced 2024-11-25 06:07:44 +08:00
chore: Setup PHPStan Level 5 (#3553)
This commit is contained in:
parent
b2fa28e4b5
commit
fc4d5e3d43
|
@ -20,3 +20,6 @@ indent_size = 4
|
|||
|
||||
[tsconfig.json]
|
||||
indent_size = 2
|
||||
|
||||
[*.neon]
|
||||
indent_style = tab
|
||||
|
|
38
.github/workflows/REUSABLE_backend.yml
vendored
38
.github/workflows/REUSABLE_backend.yml
vendored
|
@ -9,6 +9,12 @@ on:
|
|||
default: true
|
||||
required: false
|
||||
|
||||
enable_phpstan:
|
||||
description: "Enable PHPStan Static Analysis?"
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
|
||||
backend_directory:
|
||||
description: The directory of the project where backend code is located. This should contain a `composer.json` file, and is generally the root directory of the repo.
|
||||
type: string
|
||||
|
@ -130,3 +136,35 @@ jobs:
|
|||
working-directory: ${{ inputs.backend_directory }}
|
||||
env:
|
||||
COMPOSER_PROCESS_TIMEOUT: 600
|
||||
|
||||
phpstan:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php: ${{ fromJSON(inputs.php_versions) }}
|
||||
|
||||
name: 'PHPStan PHP ${{ matrix.php }}'
|
||||
|
||||
if: >-
|
||||
inputs.enable_phpstan &&
|
||||
((github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) || github.event_name != 'pull_request')
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: xdebug
|
||||
extensions: curl, dom, gd, json, mbstring, openssl, pdo_mysql, tokenizer, zip
|
||||
tools: phpunit, composer:v2
|
||||
ini-values: ${{ inputs.php_ini_values }}
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install
|
||||
working-directory: ${{ inputs.backend_directory }}
|
||||
|
||||
- name: Run PHPStan
|
||||
run: composer analyse:phpstan
|
||||
|
|
12
.github/workflows/phpstan.yml
vendored
Normal file
12
.github/workflows/phpstan.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
name: Framework PHP
|
||||
|
||||
on: [workflow_dispatch, push, pull_request]
|
||||
|
||||
jobs:
|
||||
run:
|
||||
uses: ./.github/workflows/REUSABLE_backend.yml
|
||||
with:
|
||||
enable_backend_testing: false
|
||||
enable_phpstan: true
|
||||
|
||||
backend_directory: .
|
|
@ -140,8 +140,8 @@
|
|||
"require-dev": {
|
||||
"mockery/mockery": "^1.4",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"phpstan/phpstan-php-parser": "^1.0",
|
||||
"phpstan/phpstan": "^1.2"
|
||||
"phpstan/phpstan": "^1.2",
|
||||
"nunomaduro/larastan": "^1.0"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
|
@ -178,5 +178,11 @@
|
|||
"extension.neon"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"analyse:phpstan": "phpstan analyse"
|
||||
},
|
||||
"scripts-descriptions": {
|
||||
"analyse:phpstan": "Run static analysis"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace Flarum\Api;
|
|||
|
||||
use Flarum\Http\RequestUtil;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Laminas\Diactoros\Uri;
|
||||
use Laminas\Stratigility\MiddlewarePipeInterface;
|
||||
|
@ -26,12 +25,12 @@ class Client
|
|||
protected $pipe;
|
||||
|
||||
/**
|
||||
* @var User
|
||||
* @var User|null
|
||||
*/
|
||||
protected $actor;
|
||||
|
||||
/**
|
||||
* @var ServerRequestInterface
|
||||
* @var ServerRequestInterface|null
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
|
@ -45,9 +44,6 @@ class Client
|
|||
*/
|
||||
protected $body = [];
|
||||
|
||||
/**
|
||||
* @param Container $container
|
||||
*/
|
||||
public function __construct(MiddlewarePipeInterface $pipe)
|
||||
{
|
||||
$this->pipe = $pipe;
|
||||
|
|
|
@ -88,7 +88,7 @@ abstract class AbstractSerializeController implements RequestHandlerInterface
|
|||
protected static $beforeSerializationCallbacks = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @var string[][]
|
||||
*/
|
||||
protected static $loadRelations = [];
|
||||
|
||||
|
|
|
@ -113,15 +113,15 @@ class ListNotificationsController extends AbstractListController
|
|||
$ids = [];
|
||||
|
||||
foreach ($notifications as $notification) {
|
||||
if ($notification->subject && $notification->subject->discussion_id) {
|
||||
if ($notification->subject && isset($notification->subject->discussion_id)) {
|
||||
$ids[] = $notification->subject->discussion_id;
|
||||
}
|
||||
}
|
||||
|
||||
$discussions = Discussion::find(array_unique($ids));
|
||||
$discussions = Discussion::query()->find(array_unique($ids));
|
||||
|
||||
foreach ($notifications as $notification) {
|
||||
if ($notification->subject && $notification->subject->discussion_id) {
|
||||
if ($notification->subject && isset($notification->subject->discussion_id)) {
|
||||
$notification->subject->setRelation('discussion', $discussions->find($notification->subject->discussion_id));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,12 +42,12 @@ abstract class AbstractSerializer extends BaseAbstractSerializer
|
|||
protected static $container;
|
||||
|
||||
/**
|
||||
* @var callable[]
|
||||
* @var array<string, callable[]>
|
||||
*/
|
||||
protected static $attributeMutators = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var array<string, array<string, callable>>
|
||||
*/
|
||||
protected static $customRelations = [];
|
||||
|
||||
|
@ -189,12 +189,12 @@ abstract class AbstractSerializer extends BaseAbstractSerializer
|
|||
* @param string|Closure|\Tobscure\JsonApi\SerializerInterface $serializer
|
||||
* @param string|null $relation
|
||||
* @param bool $many
|
||||
* @return Relationship
|
||||
* @return Relationship|null
|
||||
*/
|
||||
protected function buildRelationship($model, $serializer, $relation = null, $many = false)
|
||||
{
|
||||
if (is_null($relation)) {
|
||||
list(, , $caller) = debug_backtrace(false, 3);
|
||||
list(, , $caller) = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3);
|
||||
|
||||
$relation = $caller['function'];
|
||||
}
|
||||
|
@ -210,6 +210,8 @@ abstract class AbstractSerializer extends BaseAbstractSerializer
|
|||
|
||||
return new Relationship($element);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,7 +12,8 @@ namespace Flarum\Api\Serializer;
|
|||
class ExtensionReadmeSerializer extends AbstractSerializer
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param \Flarum\Extension\Extension $extension
|
||||
* @return array
|
||||
*/
|
||||
protected function getDefaultAttributes($extension)
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ class ForumSerializer extends AbstractSerializer
|
|||
*/
|
||||
public function getId($model)
|
||||
{
|
||||
return 1;
|
||||
return '1';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,17 +18,20 @@ class Schedule extends LaravelSchedule
|
|||
public function dueEvents($container)
|
||||
{
|
||||
return (new Collection($this->events))->filter->isDue(new class($container) {
|
||||
/** @var Config */
|
||||
protected $config;
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$this->config = $container->make(Config::class);
|
||||
}
|
||||
|
||||
public function isDownForMaintenance()
|
||||
public function isDownForMaintenance(): bool
|
||||
{
|
||||
return $this->config->inMaintenanceMode();
|
||||
}
|
||||
|
||||
public function environment()
|
||||
public function environment(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ use LogicException;
|
|||
* Adds the ability for custom relations to be added to a model during runtime.
|
||||
* These relations behave in the same way that you would expect; they can be
|
||||
* queried, eager loaded, and accessed as an attribute.
|
||||
*
|
||||
* @property-read int|null $id
|
||||
*/
|
||||
abstract class AbstractModel extends Eloquent
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Flarum\Database\Console;
|
|||
use Flarum\Console\AbstractCommand;
|
||||
use Flarum\Foundation\Paths;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\MySqlConnection;
|
||||
|
||||
class GenerateDumpCommand extends AbstractCommand
|
||||
{
|
||||
|
@ -53,7 +54,7 @@ class GenerateDumpCommand extends AbstractCommand
|
|||
protected function fire()
|
||||
{
|
||||
$dumpPath = __DIR__.'/../../../migrations/install.dump';
|
||||
/** @var Connection */
|
||||
/** @var Connection&MySqlConnection */
|
||||
$connection = resolve('db.connection');
|
||||
|
||||
$connection
|
||||
|
|
|
@ -30,8 +30,8 @@ class DatabaseMigrationRepository implements MigrationRepositoryInterface
|
|||
/**
|
||||
* Create a new database migration repository instance.
|
||||
*
|
||||
* @param \Illuminate\Database\ConnectionInterface $connection
|
||||
* @param string $table
|
||||
* @param ConnectionInterface $connection
|
||||
* @param string $table
|
||||
*/
|
||||
public function __construct(ConnectionInterface $connection, $table)
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
namespace Flarum\Database;
|
||||
|
||||
use Flarum\Foundation\AbstractServiceProvider;
|
||||
use Illuminate\Container\Container as ContainerImplementation;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Database\Capsule\Manager;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
|
@ -22,7 +23,7 @@ class DatabaseServiceProvider extends AbstractServiceProvider
|
|||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->container->singleton(Manager::class, function (Container $container) {
|
||||
$this->container->singleton(Manager::class, function (ContainerImplementation $container) {
|
||||
$manager = new Manager($container);
|
||||
|
||||
$config = $container['flarum']->config('database');
|
||||
|
|
|
@ -39,20 +39,17 @@ class Migrator
|
|||
/**
|
||||
* The output interface implementation.
|
||||
*
|
||||
* @var OutputInterface
|
||||
* @var OutputInterface|null
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @var ConnectionInterface|MySqlConnection
|
||||
* @var ConnectionInterface
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* Create a new migrator instance.
|
||||
*
|
||||
* @param MigrationRepositoryInterface $repository
|
||||
* @param ConnectionInterface $connection
|
||||
* @param Filesystem $files
|
||||
*/
|
||||
public function __construct(
|
||||
MigrationRepositoryInterface $repository,
|
||||
|
@ -76,7 +73,7 @@ class Migrator
|
|||
* Run the outstanding migrations at a given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param Extension $extension
|
||||
* @param Extension|null $extension
|
||||
* @return void
|
||||
*/
|
||||
public function run($path, Extension $extension = null)
|
||||
|
@ -95,7 +92,7 @@ class Migrator
|
|||
*
|
||||
* @param string $path
|
||||
* @param array $migrations
|
||||
* @param Extension $extension
|
||||
* @param Extension|null $extension
|
||||
* @return void
|
||||
*/
|
||||
public function runMigrationList($path, $migrations, Extension $extension = null)
|
||||
|
@ -122,8 +119,7 @@ class Migrator
|
|||
*
|
||||
* @param string $path
|
||||
* @param string $file
|
||||
* @param string $path
|
||||
* @param Extension $extension
|
||||
* @param Extension|null $extension
|
||||
* @return void
|
||||
*/
|
||||
protected function runUp($path, $file, Extension $extension = null)
|
||||
|
@ -144,7 +140,7 @@ class Migrator
|
|||
* Rolls all of the currently applied migrations back.
|
||||
*
|
||||
* @param string $path
|
||||
* @param Extension $extension
|
||||
* @param Extension|null $extension
|
||||
* @return int
|
||||
*/
|
||||
public function reset($path, Extension $extension = null)
|
||||
|
@ -245,6 +241,8 @@ class Migrator
|
|||
if ($this->files->exists($migration)) {
|
||||
return $this->files->getRequire($migration);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,6 @@ use Flarum\Discussion\Discussion;
|
|||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\User\Access\AbstractPolicy;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
|
||||
class DiscussionPolicy extends AbstractPolicy
|
||||
{
|
||||
|
@ -22,10 +21,6 @@ class DiscussionPolicy extends AbstractPolicy
|
|||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @param SettingsRepositoryInterface $settings
|
||||
* @param Dispatcher $events
|
||||
*/
|
||||
public function __construct(SettingsRepositoryInterface $settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
|
@ -34,7 +29,7 @@ class DiscussionPolicy extends AbstractPolicy
|
|||
/**
|
||||
* @param User $actor
|
||||
* @param string $ability
|
||||
* @return bool|null
|
||||
* @return string|void
|
||||
*/
|
||||
public function can(User $actor, $ability)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ use Flarum\Post\MergeableInterface;
|
|||
use Flarum\Post\Post;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
|
@ -83,7 +84,7 @@ class Discussion extends AbstractModel
|
|||
/**
|
||||
* The user for which the state relationship should be loaded.
|
||||
*
|
||||
* @var User
|
||||
* @var User|null
|
||||
*/
|
||||
protected static $stateUser;
|
||||
|
||||
|
@ -224,8 +225,8 @@ class Discussion extends AbstractModel
|
|||
*/
|
||||
public function refreshLastPost()
|
||||
{
|
||||
/** @var Post $lastPost */
|
||||
if ($lastPost = $this->comments()->latest()->first()) {
|
||||
/** @var Post $lastPost */
|
||||
$this->setLastPost($lastPost);
|
||||
}
|
||||
|
||||
|
@ -264,8 +265,9 @@ class Discussion extends AbstractModel
|
|||
* DiscussionRenamedPost, and delete if the title has been reverted
|
||||
* completely.)
|
||||
*
|
||||
* @param \Flarum\Post\MergeableInterface $post The post to save.
|
||||
* @return Post The resulting post. It may or may not be the same post as
|
||||
* @template T of \Flarum\Post\MergeableInterface
|
||||
* @param T $post The post to save.
|
||||
* @return T The resulting post. It may or may not be the same post as
|
||||
* was originally intended to be saved. It also may not exist, if the
|
||||
* merge logic resulted in deletion.
|
||||
*/
|
||||
|
@ -301,7 +303,7 @@ class Discussion extends AbstractModel
|
|||
/**
|
||||
* Define the relationship with the discussion's publicly-visible comments.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany<Post>
|
||||
*/
|
||||
public function comments()
|
||||
{
|
||||
|
@ -394,12 +396,12 @@ class Discussion extends AbstractModel
|
|||
* If no user is passed (i.e. in the case of eager loading the 'state'
|
||||
* relation), then the static `$stateUser` property is used.
|
||||
*
|
||||
* @see Discussion::setStateUser()
|
||||
*
|
||||
* @param User|null $user
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
* @return HasOne
|
||||
*
|
||||
* @see Discussion::setStateUser()
|
||||
*/
|
||||
public function state(User $user = null)
|
||||
public function state(User $user = null): HasOne
|
||||
{
|
||||
$user = $user ?: static::$stateUser;
|
||||
|
||||
|
@ -409,12 +411,10 @@ class Discussion extends AbstractModel
|
|||
/**
|
||||
* Get the state model for a user, or instantiate a new one if it does not
|
||||
* exist.
|
||||
*
|
||||
* @param User $user
|
||||
* @return \Flarum\Discussion\UserState
|
||||
*/
|
||||
public function stateFor(User $user)
|
||||
public function stateFor(User $user): UserState
|
||||
{
|
||||
/** @var UserState|null $state */
|
||||
$state = $this->state($user)->first();
|
||||
|
||||
if (! $state) {
|
||||
|
@ -428,8 +428,6 @@ class Discussion extends AbstractModel
|
|||
|
||||
/**
|
||||
* Set the user for which the state relationship should be loaded.
|
||||
*
|
||||
* @param User $user
|
||||
*/
|
||||
public static function setStateUser(User $user)
|
||||
{
|
||||
|
@ -440,11 +438,8 @@ class Discussion extends AbstractModel
|
|||
* Set the discussion title.
|
||||
*
|
||||
* This automatically creates a matching slug for the discussion.
|
||||
*
|
||||
* @todo slug should be set by the slugger, drop slug column entirely?
|
||||
* @param string $title
|
||||
*/
|
||||
protected function setTitleAttribute($title)
|
||||
protected function setTitleAttribute(string $title)
|
||||
{
|
||||
$this->attributes['title'] = $title;
|
||||
$this->slug = Str::slug(
|
||||
|
|
|
@ -17,7 +17,7 @@ class DiscussionRepository
|
|||
/**
|
||||
* Get a new query builder for the discussions table.
|
||||
*
|
||||
* @return Builder
|
||||
* @return Builder<Discussion>
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
|
@ -28,13 +28,13 @@ class DiscussionRepository
|
|||
* Find a discussion by ID, optionally making sure it is visible to a
|
||||
* certain user, or throw an exception.
|
||||
*
|
||||
* @param int $id
|
||||
* @param User $user
|
||||
* @param int|string $id
|
||||
* @param User|null $user
|
||||
* @return \Flarum\Discussion\Discussion
|
||||
*/
|
||||
public function findOrFail($id, User $user = null)
|
||||
{
|
||||
$query = Discussion::where('id', $id);
|
||||
$query = $this->query()->where('id', $id);
|
||||
|
||||
return $this->scopeVisibleTo($query, $user)->firstOrFail();
|
||||
}
|
||||
|
@ -42,26 +42,25 @@ class DiscussionRepository
|
|||
/**
|
||||
* Get the IDs of discussions which a user has read completely.
|
||||
*
|
||||
* @deprecated 1.3 Use `getReadIdsQuery` instead
|
||||
*
|
||||
* @param User $user
|
||||
* @return array
|
||||
* @return \Illuminate\Database\Eloquent\Collection<Discussion>
|
||||
* @deprecated 1.3 Use `getReadIdsQuery` instead
|
||||
*/
|
||||
public function getReadIds(User $user)
|
||||
{
|
||||
return $this->getReadIdsQuery($user)
|
||||
->all();
|
||||
return $this->getReadIdsQuery($user)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a query containing the IDs of discussions which a user has read completely.
|
||||
*
|
||||
* @param User $user
|
||||
* @return Builder
|
||||
* @return Builder<Discussion>
|
||||
*/
|
||||
public function getReadIdsQuery(User $user): Builder
|
||||
{
|
||||
return Discussion::leftJoin('discussion_user', 'discussion_user.discussion_id', '=', 'discussions.id')
|
||||
return $this->query()
|
||||
->leftJoin('discussion_user', 'discussion_user.discussion_id', '=', 'discussions.id')
|
||||
->where('discussion_user.user_id', $user->id)
|
||||
->whereColumn('last_read_post_number', '>=', 'last_post_number')
|
||||
->select('id');
|
||||
|
@ -70,9 +69,9 @@ class DiscussionRepository
|
|||
/**
|
||||
* Scope a query to only include records that are visible to a user.
|
||||
*
|
||||
* @param Builder $query
|
||||
* @param User $user
|
||||
* @return Builder
|
||||
* @param Builder<Discussion> $query
|
||||
* @param User|null $user
|
||||
* @return Builder<Discussion>
|
||||
*/
|
||||
protected function scopeVisibleTo(Builder $query, User $user = null)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,9 @@ use Flarum\Database\AbstractModel;
|
|||
use Flarum\Http\SlugDriverInterface;
|
||||
use Flarum\User\User;
|
||||
|
||||
/**
|
||||
* @implements SlugDriverInterface<Discussion>
|
||||
*/
|
||||
class IdWithTransliteratedSlugDriver implements SlugDriverInterface
|
||||
{
|
||||
/**
|
||||
|
@ -25,6 +28,9 @@ class IdWithTransliteratedSlugDriver implements SlugDriverInterface
|
|||
$this->discussions = $discussions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Discussion $instance
|
||||
*/
|
||||
public function toSlug(AbstractModel $instance): string
|
||||
{
|
||||
return $instance->id.(trim($instance->slug) ? '-'.$instance->slug : '');
|
||||
|
|
|
@ -65,5 +65,7 @@ class FulltextGambit implements GambitInterface
|
|||
$query->orderByRaw('MATCH('.$grammar->wrap('discussions.title').') AGAINST (?) desc', [$bit]);
|
||||
$query->orderBy('posts_ft.score', 'desc');
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ use Flarum\Database\AbstractModel;
|
|||
use Flarum\Http\SlugDriverInterface;
|
||||
use Flarum\User\User;
|
||||
|
||||
/**
|
||||
* @implements SlugDriverInterface<Discussion>
|
||||
*/
|
||||
class Utf8SlugDriver implements SlugDriverInterface
|
||||
{
|
||||
/**
|
||||
|
@ -25,6 +28,10 @@ class Utf8SlugDriver implements SlugDriverInterface
|
|||
$this->discussions = $discussions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Discussion $instance
|
||||
* @return string
|
||||
*/
|
||||
public function toSlug(AbstractModel $instance): string
|
||||
{
|
||||
$slug = preg_replace('/[-\s]+/u', '-', $instance->title);
|
||||
|
@ -34,6 +41,11 @@ class Utf8SlugDriver implements SlugDriverInterface
|
|||
return $instance->id.(trim($slug) ? '-'.$slug : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $slug
|
||||
* @param User $actor
|
||||
* @return Discussion
|
||||
*/
|
||||
public function fromSlug(string $slug, User $actor): AbstractModel
|
||||
{
|
||||
if (strpos($slug, '-')) {
|
||||
|
|
|
@ -76,7 +76,7 @@ class ErrorHandling implements ExtenderInterface
|
|||
* contain "details" - arbitrary data with more context for to the error.
|
||||
*
|
||||
* @param string $exceptionClass: The ::class attribute of the exception class.
|
||||
* @param string $errorType: The ::class attribute of the handler class.
|
||||
* @param string $handlerClass: The ::class attribute of the handler class.
|
||||
* @return self
|
||||
*/
|
||||
public function handler(string $exceptionClass, string $handlerClass): self
|
||||
|
|
|
@ -110,7 +110,7 @@ class Frontend implements ExtenderInterface
|
|||
/**
|
||||
* Modify the content of the frontend.
|
||||
*
|
||||
* @param callable|string|null $content
|
||||
* @param callable|string|null $callback
|
||||
*
|
||||
* The content can be a closure or an invokable class, and should accept:
|
||||
* - \Flarum\Frontend\Document $document
|
||||
|
|
|
@ -31,7 +31,7 @@ class LanguagePack implements ExtenderInterface, LifecycleInterface
|
|||
/**
|
||||
* LanguagePack constructor.
|
||||
*
|
||||
* @param string|null $path: Path to yaml language files.
|
||||
* @param string $path: Path to yaml language files.
|
||||
*/
|
||||
public function __construct(string $path = '/locale')
|
||||
{
|
||||
|
@ -115,7 +115,7 @@ class LanguagePack implements ExtenderInterface, LifecycleInterface
|
|||
return true;
|
||||
}
|
||||
|
||||
/** @var ExtensionManager $extensions */
|
||||
/** @var ExtensionManager|null $extensions */
|
||||
static $extensions;
|
||||
$extensions = $extensions ?? $container->make(ExtensionManager::class);
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class Middleware implements ExtenderInterface
|
|||
*
|
||||
* @param string $originalMiddleware: ::class attribute of the original middleware class.
|
||||
* Or container binding name.
|
||||
* @param string $middleware: ::class attribute of the middleware class.
|
||||
* @param string $newMiddleware: ::class attribute of the middleware class.
|
||||
* Must implement \Psr\Http\Server\MiddlewareInterface.
|
||||
* @return self
|
||||
*/
|
||||
|
@ -77,7 +77,7 @@ class Middleware implements ExtenderInterface
|
|||
*
|
||||
* @param string $originalMiddleware: ::class attribute of the original middleware class.
|
||||
* Or container binding name.
|
||||
* @param string $middleware: ::class attribute of the middleware class.
|
||||
* @param string $newMiddleware: ::class attribute of the middleware class.
|
||||
* Must implement \Psr\Http\Server\MiddlewareInterface.
|
||||
* @return self
|
||||
*/
|
||||
|
@ -93,7 +93,7 @@ class Middleware implements ExtenderInterface
|
|||
*
|
||||
* @param string $originalMiddleware: ::class attribute of the original middleware class.
|
||||
* Or container binding name.
|
||||
* @param string $middleware: ::class attribute of the middleware class.
|
||||
* @param string $newMiddleware: ::class attribute of the middleware class.
|
||||
* Must implement \Psr\Http\Server\MiddlewareInterface.
|
||||
* @return self
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,7 @@ use Flarum\Extension\Extension;
|
|||
use Flarum\Foundation\Paths;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\View\Factory as FactoryImplementation;
|
||||
|
||||
/**
|
||||
* Views are PHP files that use the Laravel Blade syntax for creation of server-side generated HTML.
|
||||
|
@ -65,7 +66,7 @@ class View implements ExtenderInterface, LifecycleInterface
|
|||
|
||||
public function extend(Container $container, Extension $extension = null)
|
||||
{
|
||||
$container->resolving(Factory::class, function (Factory $view) {
|
||||
$container->resolving(Factory::class, function (FactoryImplementation $view) {
|
||||
foreach ($this->namespaces as $namespace => $hints) {
|
||||
$view->addNamespace($namespace, $hints);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,6 @@ class ExtensionBootError extends Exception
|
|||
|
||||
$extenderClass = get_class($extender);
|
||||
|
||||
parent::__construct("Experienced an error while booting extension: {$extension->getTitle()}.\n\nError occurred while applying an extender of type: $extenderClass.", null, $previous);
|
||||
parent::__construct("Experienced an error while booting extension: {$extension->getTitle()}.\n\nError occurred while applying an extender of type: $extenderClass.", 0, $previous);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -214,9 +214,6 @@ class Extension implements Arrayable
|
|||
* @param array $extensionSet: An associative array where keys are the composer package names
|
||||
* of installed extensions. Used to figure out which dependencies
|
||||
* are flarum extensions.
|
||||
* @param array $enabledIds: An associative array where keys are the composer package names
|
||||
* of enabled extensions. Used to figure out optional dependencies.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function calculateDependencies($extensionSet)
|
||||
|
@ -489,6 +486,7 @@ class Extension implements Arrayable
|
|||
}
|
||||
|
||||
/**
|
||||
* @return int|void
|
||||
* @internal
|
||||
*/
|
||||
public function migrate(Migrator $migrator, $direction = 'up')
|
||||
|
@ -498,7 +496,7 @@ class Extension implements Arrayable
|
|||
}
|
||||
|
||||
if ($direction == 'up') {
|
||||
return $migrator->run($this->getPath().'/migrations', $this);
|
||||
$migrator->run($this->getPath().'/migrations', $this);
|
||||
} else {
|
||||
return $migrator->reset($this->getPath().'/migrations', $this);
|
||||
}
|
||||
|
|
|
@ -316,7 +316,7 @@ class ExtensionManager
|
|||
*
|
||||
* @param Extension $extension
|
||||
* @param string $direction
|
||||
* @return void
|
||||
* @return int
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
|
@ -326,20 +326,20 @@ class ExtensionManager
|
|||
return $container->make(ConnectionInterface::class)->getSchemaBuilder();
|
||||
});
|
||||
|
||||
$extension->migrate($this->migrator, $direction);
|
||||
return $extension->migrate($this->migrator, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the database migrations to reset the database to its old state.
|
||||
*
|
||||
* @param Extension $extension
|
||||
* @return array Notes from the migrator.
|
||||
* @return void
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function migrateDown(Extension $extension)
|
||||
{
|
||||
return $this->migrate($extension, 'down');
|
||||
$this->migrate($extension, 'down');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,7 +39,7 @@ abstract class AbstractFilterer
|
|||
|
||||
/**
|
||||
* @param QueryCriteria $criteria
|
||||
* @param mixed|null $limit
|
||||
* @param int|null $limit
|
||||
* @param int $offset
|
||||
*
|
||||
* @return QueryResults
|
||||
|
|
|
@ -18,9 +18,6 @@ interface FilterInterface
|
|||
|
||||
/**
|
||||
* Filters a query.
|
||||
*
|
||||
* @param FilterState $filter
|
||||
* @param string $value The value of the requested filter
|
||||
*/
|
||||
public function filter(FilterState $filterState, string $filterValue, bool $negate);
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
namespace Flarum\Formatter;
|
||||
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use Illuminate\Contracts\Cache\Repository;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use s9e\TextFormatter\Configurator;
|
||||
|
@ -152,8 +150,8 @@ class Formatter
|
|||
|
||||
$configurator->rootRules->enableAutoLineBreaks();
|
||||
|
||||
$configurator->rendering->engine = 'PHP';
|
||||
$configurator->rendering->engine->cacheDir = $this->cacheDir;
|
||||
$configurator->rendering->setEngine('PHP');
|
||||
$configurator->rendering->getEngine()->cacheDir = $this->cacheDir; // @phpstan-ignore-line
|
||||
|
||||
$configurator->enableJavaScript();
|
||||
$configurator->javascript->exports = ['preview'];
|
||||
|
@ -161,9 +159,9 @@ class Formatter
|
|||
$configurator->javascript->setMinifier('MatthiasMullieMinify')
|
||||
->keepGoing = true;
|
||||
|
||||
$configurator->Escaper;
|
||||
$configurator->Autoemail;
|
||||
$configurator->Autolink;
|
||||
$configurator->Escaper; /** @phpstan-ignore-line */
|
||||
$configurator->Autoemail; /** @phpstan-ignore-line */
|
||||
$configurator->Autolink; /** @phpstan-ignore-line */
|
||||
$configurator->tags->onDuplicate('replace');
|
||||
|
||||
foreach ($this->configurationCallbacks as $callback) {
|
||||
|
@ -180,11 +178,13 @@ class Formatter
|
|||
*/
|
||||
protected function configureExternalLinks(Configurator $configurator)
|
||||
{
|
||||
/** @var DOMDocument $dom */
|
||||
/**
|
||||
* @var Configurator\Items\TemplateDocument $dom
|
||||
*/
|
||||
$dom = $configurator->tags['URL']->template->asDOM();
|
||||
|
||||
/** @var DOMElement $a */
|
||||
foreach ($dom->getElementsByTagName('a') as $a) {
|
||||
/** @var \s9e\SweetDOM\Element $a */
|
||||
$a->prependXslCopyOf('@target');
|
||||
$a->prependXslCopyOf('@rel');
|
||||
}
|
||||
|
|
|
@ -140,10 +140,10 @@ class Application
|
|||
* Use container inside flarum instead.
|
||||
*/
|
||||
$this->container->instance('app', $this->container);
|
||||
$this->container->alias('app', \Illluminate\Container\Container::class);
|
||||
$this->container->alias('app', \Illuminate\Container\Container::class);
|
||||
|
||||
$this->container->instance('container', $this->container);
|
||||
$this->container->alias('container', \Illluminate\Container\Container::class);
|
||||
$this->container->alias('container', \Illuminate\Container\Container::class);
|
||||
|
||||
$this->container->instance('flarum', $this);
|
||||
$this->container->alias('flarum', self::class);
|
||||
|
@ -170,7 +170,7 @@ class Application
|
|||
*/
|
||||
public function register($provider, $options = [], $force = false)
|
||||
{
|
||||
if ($registered = $this->getProvider($provider) && ! $force) {
|
||||
if (($registered = $this->getProvider($provider)) && ! $force) {
|
||||
return $registered;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ class InfoCommand extends AbstractCommand
|
|||
* @var ConnectionInterface
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* @var Queue
|
||||
*/
|
||||
|
|
|
@ -104,7 +104,7 @@ class InstalledSite implements SiteInterface
|
|||
$container->instance('flarum.config', $this->config);
|
||||
$container->alias('flarum.config', Config::class);
|
||||
$container->instance('flarum.debug', $this->config->inDebugMode());
|
||||
$container->instance('config', $config = $this->getIlluminateConfig($laravel));
|
||||
$container->instance('config', $config = $this->getIlluminateConfig());
|
||||
$container->instance('flarum.maintenance.handler', new MaintenanceModeHandler);
|
||||
|
||||
$this->registerLogger($container);
|
||||
|
|
|
@ -12,10 +12,10 @@ namespace Flarum\Foundation;
|
|||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @property-read string base
|
||||
* @property-read string public
|
||||
* @property-read string storage
|
||||
* @property-read string vendor
|
||||
* @property-read string $base
|
||||
* @property-read string $public
|
||||
* @property-read string $storage
|
||||
* @property-read string $vendor
|
||||
*/
|
||||
class Paths
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ use Flarum\Frontend\Compiler\CompilerInterface;
|
|||
use Flarum\Frontend\Compiler\JsCompiler;
|
||||
use Flarum\Frontend\Compiler\LessCompiler;
|
||||
use Flarum\Frontend\Compiler\Source\SourceCollector;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Contracts\Filesystem\Cloud;
|
||||
|
||||
/**
|
||||
* A factory class for creating frontend asset compilers.
|
||||
|
@ -38,7 +38,7 @@ class Assets
|
|||
protected $name;
|
||||
|
||||
/**
|
||||
* @var Filesystem
|
||||
* @var Cloud
|
||||
*/
|
||||
protected $assetsDir;
|
||||
|
||||
|
@ -67,7 +67,7 @@ class Assets
|
|||
*/
|
||||
protected $customFunctions = [];
|
||||
|
||||
public function __construct(string $name, Filesystem $assetsDir, string $cacheDir = null, array $lessImportDirs = null, array $customFunctions = [])
|
||||
public function __construct(string $name, Cloud $assetsDir, string $cacheDir = null, array $lessImportDirs = null, array $customFunctions = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->assetsDir = $assetsDir;
|
||||
|
@ -200,12 +200,12 @@ class Assets
|
|||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getAssetsDir(): Filesystem
|
||||
public function getAssetsDir(): Cloud
|
||||
{
|
||||
return $this->assetsDir;
|
||||
}
|
||||
|
||||
public function setAssetsDir(Filesystem $assetsDir)
|
||||
public function setAssetsDir(Cloud $assetsDir)
|
||||
{
|
||||
$this->assetsDir = $assetsDir;
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@ class FileVersioner implements VersionerInterface
|
|||
|
||||
public function putRevision(string $file, ?string $revision)
|
||||
{
|
||||
if ($this->filesystem->has(static::REV_MANIFEST)) {
|
||||
$manifest = json_decode($this->filesystem->read(static::REV_MANIFEST), true);
|
||||
if ($this->filesystem->exists(static::REV_MANIFEST)) {
|
||||
$manifest = json_decode($this->filesystem->get(static::REV_MANIFEST), true);
|
||||
} else {
|
||||
$manifest = [];
|
||||
}
|
||||
|
@ -44,8 +44,8 @@ class FileVersioner implements VersionerInterface
|
|||
|
||||
public function getRevision(string $file): ?string
|
||||
{
|
||||
if ($this->filesystem->has(static::REV_MANIFEST)) {
|
||||
$manifest = json_decode($this->filesystem->read(static::REV_MANIFEST), true);
|
||||
if ($this->filesystem->exists(static::REV_MANIFEST)) {
|
||||
$manifest = json_decode($this->filesystem->get(static::REV_MANIFEST), true);
|
||||
|
||||
return Arr::get($manifest, $file);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ class JsCompiler extends RevisionCompiler
|
|||
{
|
||||
parent::delete($file);
|
||||
|
||||
if ($this->assetsDir->has($mapFile = $file.'.map')) {
|
||||
if ($this->assetsDir->exists($mapFile = $file.'.map')) {
|
||||
$this->assetsDir->delete($mapFile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,12 +35,12 @@ class LessCompiler extends RevisionCompiler
|
|||
protected $customFunctions = [];
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
* @var Collection|null
|
||||
*/
|
||||
protected $lessImportOverrides;
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
* @var Collection|null
|
||||
*/
|
||||
protected $fileSourceOverrides;
|
||||
|
||||
|
@ -88,7 +88,7 @@ class LessCompiler extends RevisionCompiler
|
|||
return '';
|
||||
}
|
||||
|
||||
ini_set('xdebug.max_nesting_level', 200);
|
||||
ini_set('xdebug.max_nesting_level', '200');
|
||||
|
||||
$parser = new Less_Parser([
|
||||
'compress' => true,
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Flarum\Frontend\Compiler;
|
|||
|
||||
use Flarum\Frontend\Compiler\Source\SourceCollector;
|
||||
use Flarum\Frontend\Compiler\Source\SourceInterface;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Contracts\Filesystem\Cloud;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
@ -21,9 +21,10 @@ class RevisionCompiler implements CompilerInterface
|
|||
const EMPTY_REVISION = 'empty';
|
||||
|
||||
/**
|
||||
* @var Filesystem
|
||||
* @var Cloud
|
||||
*/
|
||||
protected $assetsDir;
|
||||
|
||||
/**
|
||||
* @var VersionerInterface
|
||||
*/
|
||||
|
@ -40,11 +41,11 @@ class RevisionCompiler implements CompilerInterface
|
|||
protected $sourcesCallbacks = [];
|
||||
|
||||
/**
|
||||
* @param Filesystem $assetsDir
|
||||
* @param Cloud $assetsDir
|
||||
* @param string $filename
|
||||
* @param VersionerInterface|null $versioner @deprecated nullable will be removed at v2.0
|
||||
*/
|
||||
public function __construct(Filesystem $assetsDir, string $filename, VersionerInterface $versioner = null)
|
||||
public function __construct(Cloud $assetsDir, string $filename, VersionerInterface $versioner = null)
|
||||
{
|
||||
$this->assetsDir = $assetsDir;
|
||||
$this->filename = $filename;
|
||||
|
@ -71,7 +72,7 @@ class RevisionCompiler implements CompilerInterface
|
|||
|
||||
// In case the previous and current revisions do not match
|
||||
// Or no file was written yet, let's save the file to disk.
|
||||
if ($force || $oldRevision !== $newRevision || ! $this->assetsDir->has($this->filename)) {
|
||||
if ($force || $oldRevision !== $newRevision || ! $this->assetsDir->exists($this->filename)) {
|
||||
if (! $this->save($this->filename, $sources)) {
|
||||
// If no file was written (because the sources were empty), we
|
||||
// will set the revision to a special value so that we can tell
|
||||
|
@ -145,7 +146,6 @@ class RevisionCompiler implements CompilerInterface
|
|||
|
||||
/**
|
||||
* @param SourceInterface[] $sources
|
||||
* @return string
|
||||
*/
|
||||
protected function compile(array $sources): string
|
||||
{
|
||||
|
@ -158,10 +158,6 @@ class RevisionCompiler implements CompilerInterface
|
|||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
protected function format(string $string): string
|
||||
{
|
||||
return $string;
|
||||
|
@ -169,7 +165,6 @@ class RevisionCompiler implements CompilerInterface
|
|||
|
||||
/**
|
||||
* @param SourceInterface[] $sources
|
||||
* @return string
|
||||
*/
|
||||
protected function calculateRevision(array $sources): string
|
||||
{
|
||||
|
@ -196,12 +191,9 @@ class RevisionCompiler implements CompilerInterface
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
*/
|
||||
protected function delete(string $file)
|
||||
{
|
||||
if ($this->assetsDir->has($file)) {
|
||||
if ($this->assetsDir->exists($file)) {
|
||||
$this->assetsDir->delete($file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,14 +221,13 @@ class Document implements Renderable
|
|||
return resolve(TitleDriverInterface::class)->makeTitle($this, $this->request, $this->forumApiDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return View
|
||||
*/
|
||||
protected function makeLayout(): View
|
||||
protected function makeLayout(): ?View
|
||||
{
|
||||
if ($this->layoutView) {
|
||||
return $this->view->make($this->layoutView)->with('content', $this->makeContent());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,7 +17,7 @@ class GroupRepository
|
|||
/**
|
||||
* Get a new query builder for the groups table.
|
||||
*
|
||||
* @return Builder
|
||||
* @return Builder<Group>
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
|
@ -29,14 +29,14 @@ class GroupRepository
|
|||
* user, or throw an exception.
|
||||
*
|
||||
* @param int $id
|
||||
* @param User $actor
|
||||
* @return \Flarum\Group\Group
|
||||
* @param User|null $actor
|
||||
* @return Group
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
||||
*/
|
||||
public function findOrFail($id, User $actor = null)
|
||||
{
|
||||
$query = Group::where('id', $id);
|
||||
$query = $this->query()->where('id', $id);
|
||||
|
||||
return $this->scopeVisibleTo($query, $actor)->firstOrFail();
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ class GroupRepository
|
|||
/**
|
||||
* Scope a query to only include records that are visible to a user.
|
||||
*
|
||||
* @param Builder $query
|
||||
* @param User $actor
|
||||
* @return Builder
|
||||
* @param Builder<Group> $query
|
||||
* @param User|null $actor
|
||||
* @return Builder<Group>
|
||||
*/
|
||||
protected function scopeVisibleTo(Builder $query, User $actor = null)
|
||||
{
|
||||
|
|
|
@ -25,8 +25,8 @@ use Psr\Http\Message\ServerRequestInterface;
|
|||
* @property Carbon|null $last_activity_at
|
||||
* @property string $type
|
||||
* @property string $title
|
||||
* @property string $last_ip_address
|
||||
* @property string $last_user_agent
|
||||
* @property string|null $last_ip_address
|
||||
* @property string|null $last_user_agent
|
||||
* @property \Flarum\User\User|null $user
|
||||
*/
|
||||
class AccessToken extends AbstractModel
|
||||
|
|
|
@ -46,7 +46,7 @@ class CookieFactory
|
|||
/**
|
||||
* Same Site cookie value.
|
||||
*
|
||||
* @var string
|
||||
* @var string|null
|
||||
*/
|
||||
protected $samesite;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class ResolveRoute implements Middleware
|
|||
protected $routes;
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
* @var Dispatcher|null
|
||||
*/
|
||||
protected $dispatcher;
|
||||
|
||||
|
@ -43,6 +43,8 @@ class ResolveRoute implements Middleware
|
|||
/**
|
||||
* Resolve the given request from our route collection.
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws MethodNotAllowedException
|
||||
* @throws RouteNotFoundException
|
||||
*/
|
||||
|
@ -58,7 +60,7 @@ class ResolveRoute implements Middleware
|
|||
throw new RouteNotFoundException($uri);
|
||||
case Dispatcher::METHOD_NOT_ALLOWED:
|
||||
throw new MethodNotAllowedException($method);
|
||||
case Dispatcher::FOUND:
|
||||
default:
|
||||
$request = $request
|
||||
->withAttribute('routeName', $routeInfo[1]['name'])
|
||||
->withAttribute('routeHandler', $routeInfo[1]['handler'])
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Flarum\Http;
|
|||
|
||||
use Flarum\Foundation\ErrorHandling\LogReporter;
|
||||
use Flarum\Foundation\SiteInterface;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Laminas\Diactoros\Response;
|
||||
use Laminas\Diactoros\ServerRequest;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
|
@ -50,7 +51,7 @@ class Server
|
|||
* We catch all exceptions happening during this process and format them to
|
||||
* prevent exposure of sensitive information.
|
||||
*
|
||||
* @return \Psr\Http\Server\RequestHandlerInterface
|
||||
* @return \Psr\Http\Server\RequestHandlerInterface|void
|
||||
*/
|
||||
private function safelyBootAndGetHandler()
|
||||
{
|
||||
|
@ -80,7 +81,9 @@ class Server
|
|||
*/
|
||||
private function cleanBootExceptionLog(Throwable $error)
|
||||
{
|
||||
if (app()->has('flarum.config') && app('flarum.config')->inDebugMode()) {
|
||||
$container = resolve(Container::class);
|
||||
|
||||
if ($container->has('flarum.config') && resolve('flarum.config')->inDebugMode()) {
|
||||
// If the application booted far enough for the config to be available, we will check for debug mode
|
||||
// Since the config is loaded very early, it is very likely to be available from the container
|
||||
$message = $error->getMessage();
|
||||
|
@ -96,12 +99,12 @@ class Server
|
|||
<pre>$error</pre>
|
||||
ERROR;
|
||||
exit(1);
|
||||
} elseif (app()->has(LoggerInterface::class)) {
|
||||
} elseif ($container->has(LoggerInterface::class)) {
|
||||
// If the application booted far enough for the logger to be available, we will log the error there
|
||||
// Considering most boot errors are related to database or extensions, the logger should already be loaded
|
||||
// We check for LoggerInterface binding because it's a constructor dependency of LogReporter,
|
||||
// then instantiate LogReporter through the container for automatic dependency injection
|
||||
app(LogReporter::class)->report($error);
|
||||
resolve(LogReporter::class)->report($error);
|
||||
|
||||
echo 'Flarum encountered a boot error. Details have been logged to the Flarum log file.';
|
||||
exit(1);
|
||||
|
|
|
@ -12,9 +12,18 @@ namespace Flarum\Http;
|
|||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\User\User;
|
||||
|
||||
/**
|
||||
* @template T of AbstractModel
|
||||
*/
|
||||
interface SlugDriverInterface
|
||||
{
|
||||
/**
|
||||
* @param T $instance
|
||||
*/
|
||||
public function toSlug(AbstractModel $instance): string;
|
||||
|
||||
/**
|
||||
* @return T
|
||||
*/
|
||||
public function fromSlug(string $slug, User $actor): AbstractModel;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,11 @@ class SlugManager
|
|||
$this->drivers = $drivers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of \Flarum\Database\AbstractModel
|
||||
* @param class-string<T> $resourceName
|
||||
* @return SlugDriverInterface<T>
|
||||
*/
|
||||
public function forResource(string $resourceName): SlugDriverInterface
|
||||
{
|
||||
return Arr::get($this->drivers, $resourceName, null);
|
||||
|
|
|
@ -13,6 +13,7 @@ use Flarum\Console\AbstractCommand;
|
|||
use Flarum\Install\Installation;
|
||||
use Flarum\Install\Pipeline;
|
||||
use Flarum\Install\Step;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
class InstallCommand extends AbstractCommand
|
||||
|
@ -83,7 +84,9 @@ class InstallCommand extends AbstractCommand
|
|||
if ($this->input->getOption('file')) {
|
||||
$this->dataSource = new FileDataProvider($this->input);
|
||||
} else {
|
||||
$this->dataSource = new UserDataProvider($this->input, $this->output, $this->getHelperSet()->get('question'));
|
||||
/** @var QuestionHelper $questionHelper */
|
||||
$questionHelper = $this->getHelperSet()->get('question');
|
||||
$this->dataSource = new UserDataProvider($this->input, $this->output, $questionHelper);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,6 @@ class IndexController extends AbstractHtmlController
|
|||
*/
|
||||
protected $installation;
|
||||
|
||||
/**
|
||||
* @param Factory $view
|
||||
* @param Installation $installation
|
||||
*/
|
||||
public function __construct(Factory $view, Installation $installation)
|
||||
{
|
||||
$this->view = $view;
|
||||
|
@ -37,7 +33,6 @@ class IndexController extends AbstractHtmlController
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Support\Renderable
|
||||
*/
|
||||
public function render(Request $request)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace Flarum\Install;
|
||||
|
||||
interface ReversibleStep
|
||||
interface ReversibleStep extends Step
|
||||
{
|
||||
public function revert();
|
||||
}
|
||||
|
|
|
@ -60,6 +60,11 @@ class EnableBundledExtensions implements Step
|
|||
*/
|
||||
private $enabledExtensions;
|
||||
|
||||
/**
|
||||
* @var Migrator|null
|
||||
*/
|
||||
private $migrator;
|
||||
|
||||
public function __construct(ConnectionInterface $database, $vendorPath, $assetPath, $enabledExtensions = null)
|
||||
{
|
||||
$this->database = $database;
|
||||
|
@ -124,7 +129,7 @@ class EnableBundledExtensions implements Step
|
|||
});
|
||||
}
|
||||
|
||||
private function getMigrator()
|
||||
private function getMigrator(): Migrator
|
||||
{
|
||||
return $this->migrator = $this->migrator ?? new Migrator(
|
||||
new DatabaseMigrationRepository($this->database, 'migrations'),
|
||||
|
|
|
@ -10,10 +10,9 @@
|
|||
namespace Flarum\Install\Steps;
|
||||
|
||||
use Flarum\Install\ReversibleStep;
|
||||
use Flarum\Install\Step;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
class PublishAssets implements Step, ReversibleStep
|
||||
class PublishAssets implements ReversibleStep
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
|
|
|
@ -12,9 +12,8 @@ namespace Flarum\Install\Steps;
|
|||
use Flarum\Install\BaseUrl;
|
||||
use Flarum\Install\DatabaseConfig;
|
||||
use Flarum\Install\ReversibleStep;
|
||||
use Flarum\Install\Step;
|
||||
|
||||
class StoreConfig implements Step, ReversibleStep
|
||||
class StoreConfig implements ReversibleStep
|
||||
{
|
||||
private $debugMode;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class EmailNotificationDriver implements NotificationDriverInterface
|
|||
/**
|
||||
* Mail a notification to a list of users.
|
||||
*
|
||||
* @param MailableInterface $blueprint
|
||||
* @param MailableInterface&BlueprintInterface $blueprint
|
||||
* @param User[] $recipients
|
||||
*/
|
||||
protected function mailNotifications(MailableInterface $blueprint, array $recipients)
|
||||
|
|
|
@ -26,7 +26,7 @@ class DeletedAll
|
|||
|
||||
public function __construct(User $user, DateTime $timestamp)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->actor = $user;
|
||||
$this->timestamp = $timestamp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class Read
|
|||
|
||||
public function __construct(User $user, Notification $notification, DateTime $timestamp)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->actor = $user;
|
||||
$this->notification = $notification;
|
||||
$this->timestamp = $timestamp;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class ReadAll
|
|||
|
||||
public function __construct(User $user, DateTime $timestamp)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->actor = $user;
|
||||
$this->timestamp = $timestamp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ use Illuminate\Support\Arr;
|
|||
* @property \Carbon\Carbon $deleted_at
|
||||
* @property \Flarum\User\User|null $user
|
||||
* @property \Flarum\User\User|null $fromUser
|
||||
* @property \Flarum\Database\AbstractModel|null $subject
|
||||
* @property \Flarum\Database\AbstractModel|\Flarum\Post\Post|\Flarum\Discussion\Discussion|null $subject
|
||||
*/
|
||||
class Notification extends AbstractModel
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ class Notification extends AbstractModel
|
|||
* When getting the data attribute, unserialize the JSON stored in the
|
||||
* database into a plain array.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string|null $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDataAttribute($value)
|
||||
|
@ -258,7 +258,7 @@ class Notification extends AbstractModel
|
|||
static::$subjectModels[$type] = $subjectModel;
|
||||
}
|
||||
|
||||
private static function getBlueprintAttributes(BlueprintInterface $blueprint): array
|
||||
protected static function getBlueprintAttributes(BlueprintInterface $blueprint): array
|
||||
{
|
||||
return [
|
||||
'type' => $blueprint::getType(),
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Flarum\Notification;
|
|||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Contracts\Mail\Mailer;
|
||||
use Illuminate\Contracts\Translation\Translator;
|
||||
use Illuminate\Mail\Message;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
|
@ -23,7 +24,7 @@ class NotificationMailer
|
|||
protected $mailer;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface
|
||||
* @var TranslatorInterface&Translator
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
|
@ -33,9 +34,7 @@ class NotificationMailer
|
|||
protected $settings;
|
||||
|
||||
/**
|
||||
* @param Mailer $mailer
|
||||
* @param TranslatorInterface $translator
|
||||
* @param SettingsRepositoryInterface $settings
|
||||
* @param TranslatorInterface&Translator $translator
|
||||
*/
|
||||
public function __construct(Mailer $mailer, TranslatorInterface $translator, SettingsRepositoryInterface $settings)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,8 @@ class NotificationRepository
|
|||
*/
|
||||
public function findByUser(User $user, $limit = null, $offset = 0)
|
||||
{
|
||||
$primaries = Notification::selectRaw('MAX(id) AS id')
|
||||
$primaries = Notification::query()
|
||||
->selectRaw('MAX(id) AS id')
|
||||
->selectRaw('SUM(read_at IS NULL) AS unread_count')
|
||||
->where('user_id', $user->id)
|
||||
->whereIn('type', $user->getAlertableNotificationTypes())
|
||||
|
@ -35,7 +36,8 @@ class NotificationRepository
|
|||
->skip($offset)
|
||||
->take($limit);
|
||||
|
||||
return Notification::select('notifications.*', 'p.unread_count')
|
||||
return Notification::query()
|
||||
->select('notifications.*', 'p.unread_count')
|
||||
->joinSub($primaries, 'p', 'notifications.id', '=', 'p.id')
|
||||
->latest()
|
||||
->get();
|
||||
|
|
|
@ -23,7 +23,7 @@ interface MergeableInterface
|
|||
* passed model.
|
||||
*
|
||||
* @param \Flarum\Post\Post|null $previous
|
||||
* @return Post The model resulting after the merge. If the merge is
|
||||
* @return static The model resulting after the merge. If the merge is
|
||||
* unsuccessful, this should be the current model instance. Otherwise,
|
||||
* it should be the model that was merged into.
|
||||
*/
|
||||
|
|
|
@ -16,14 +16,13 @@ use Flarum\Foundation\EventGeneratorTrait;
|
|||
use Flarum\Notification\Notification;
|
||||
use Flarum\Post\Event\Deleted;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $discussion_id
|
||||
* @property int $number
|
||||
* @property int|Expression $number
|
||||
* @property \Carbon\Carbon $created_at
|
||||
* @property int|null $user_id
|
||||
* @property string|null $type
|
||||
|
@ -94,8 +93,8 @@ class Post extends AbstractModel
|
|||
static::creating(function (self $post) {
|
||||
$post->type = $post::$type;
|
||||
|
||||
/** @var ConnectionInterface $db */
|
||||
$db = static::getConnectionResolver();
|
||||
$db = static::getConnectionResolver()->connection();
|
||||
|
||||
$post->number = new Expression('('.
|
||||
$db->table('posts', 'pn')
|
||||
->whereRaw($db->getTablePrefix().'pn.discussion_id = '.intval($post->discussion_id))
|
||||
|
|
|
@ -18,7 +18,7 @@ class PostRepository
|
|||
/**
|
||||
* Get a new query builder for the posts table.
|
||||
*
|
||||
* @return Builder
|
||||
* @return Builder<Post>
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ class PostRepository
|
|||
|
||||
/**
|
||||
* @param User|null $user
|
||||
* @return Builder
|
||||
* @return Builder<Post>
|
||||
*/
|
||||
protected function queryVisibleTo(User $user = null)
|
||||
{
|
||||
|
@ -45,8 +45,8 @@ class PostRepository
|
|||
* user, or throw an exception.
|
||||
*
|
||||
* @param int $id
|
||||
* @param \Flarum\User\User $actor
|
||||
* @return \Flarum\Post\Post
|
||||
* @param \Flarum\User\User|null $actor
|
||||
* @return Post
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
||||
*/
|
||||
|
@ -126,7 +126,7 @@ class PostRepository
|
|||
/**
|
||||
* @param array $ids
|
||||
* @param User|null $actor
|
||||
* @return Builder
|
||||
* @return Builder<Post>
|
||||
*/
|
||||
protected function queryIds(array $ids, User $actor = null)
|
||||
{
|
||||
|
|
|
@ -42,9 +42,9 @@ class ExceptionHandler implements ExceptionHandling
|
|||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param Throwable $e
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @return void
|
||||
*/
|
||||
public function render($request, Throwable $e)
|
||||
public function render($request, Throwable $e) /** @phpstan-ignore-line */
|
||||
{
|
||||
// TODO: Implement render() method.
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class QueueFactory implements Factory
|
|||
/**
|
||||
* The cached queue instance.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Queue\Queue
|
||||
* @var \Illuminate\Contracts\Queue\Queue|null
|
||||
*/
|
||||
private $queue;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ use Flarum\Foundation\Config;
|
|||
use Flarum\Foundation\ErrorHandling\Registry;
|
||||
use Flarum\Foundation\ErrorHandling\Reporter;
|
||||
use Flarum\Foundation\Paths;
|
||||
use Illuminate\Container\Container as ContainerImplementation;
|
||||
use Illuminate\Contracts\Cache\Factory as CacheFactory;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandling;
|
||||
|
@ -52,7 +53,7 @@ class QueueServiceProvider extends AbstractServiceProvider
|
|||
|
||||
// Extensions can override this binding if they want to make Flarum use
|
||||
// a different queuing backend.
|
||||
$this->container->singleton('flarum.queue.connection', function (Container $container) {
|
||||
$this->container->singleton('flarum.queue.connection', function (ContainerImplementation $container) {
|
||||
$queue = new SyncQueue;
|
||||
$queue->setContainer($container);
|
||||
|
||||
|
@ -90,7 +91,12 @@ class QueueServiceProvider extends AbstractServiceProvider
|
|||
// Bind a simple cache manager that returns the cache store.
|
||||
$this->container->singleton('cache', function (Container $container) {
|
||||
return new class($container) implements CacheFactory {
|
||||
public function __construct($container)
|
||||
/**
|
||||
* @var Container
|
||||
*/
|
||||
private $container;
|
||||
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
|
|
@ -34,13 +34,15 @@ abstract class AbstractRegexGambit implements GambitInterface
|
|||
* Match the bit against this gambit.
|
||||
*
|
||||
* @param string $bit
|
||||
* @return array
|
||||
* @return array|null
|
||||
*/
|
||||
protected function match($bit)
|
||||
{
|
||||
if (preg_match('/^(-?)'.$this->getGambitPattern().'$/i', $bit, $matches)) {
|
||||
return $matches;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -43,7 +43,6 @@ abstract class AbstractSearcher
|
|||
* @param int $offset
|
||||
*
|
||||
* @return QueryResults
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function search(QueryCriteria $criteria, $limit = null, $offset = 0): QueryResults
|
||||
{
|
||||
|
|
|
@ -26,9 +26,6 @@ class GambitManager
|
|||
*/
|
||||
protected $fulltextGambit;
|
||||
|
||||
/**
|
||||
* @param GambitInterface $gambit
|
||||
*/
|
||||
public function __construct(GambitInterface $fulltextGambit)
|
||||
{
|
||||
$this->fulltextGambit = $fulltextGambit;
|
||||
|
|
|
@ -28,10 +28,6 @@ class IndexController extends AbstractHtmlController
|
|||
$this->view = $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function render(Request $request)
|
||||
{
|
||||
$view = $this->view->make('flarum.update::app')->with('title', 'Update Flarum');
|
||||
|
|
|
@ -40,13 +40,11 @@ abstract class AbstractPolicy
|
|||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param string $ability
|
||||
* @param $instance
|
||||
* @return string|void
|
||||
*/
|
||||
public function checkAbility(User $actor, string $ability, $instance)
|
||||
{ // If a specific method for this ability is defined,
|
||||
{
|
||||
// If a specific method for this ability is defined,
|
||||
// call that and return any non-null results
|
||||
if (method_exists($this, $ability)) {
|
||||
$result = $this->sanitizeResult(call_user_func_array([$this, $ability], [$actor, $instance]));
|
||||
|
@ -73,7 +71,7 @@ abstract class AbstractPolicy
|
|||
* `return SOME_BOOLEAN_LOGIC;
|
||||
*
|
||||
* @param mixed $result
|
||||
* @return string|void
|
||||
* @return string|void|null
|
||||
*/
|
||||
public function sanitizeResult($result)
|
||||
{
|
||||
|
|
|
@ -54,12 +54,6 @@ class RegisterUserHandler
|
|||
*/
|
||||
protected $imageManager;
|
||||
|
||||
/**
|
||||
* @param Dispatcher $events
|
||||
* @param SettingsRepositoryInterface $settings
|
||||
* @param UserValidator $validator
|
||||
* @param AvatarUploader $avatarUploader
|
||||
*/
|
||||
public function __construct(Dispatcher $events, SettingsRepositoryInterface $settings, UserValidator $userValidator, AvatarUploader $avatarUploader, Factory $validator, ImageManager $imageManager)
|
||||
{
|
||||
$this->events = $events;
|
||||
|
@ -91,6 +85,7 @@ class RegisterUserHandler
|
|||
// If a valid authentication token was provided as an attribute,
|
||||
// then we won't require the user to choose a password.
|
||||
if (isset($data['attributes']['token'])) {
|
||||
/** @var RegistrationToken $token */
|
||||
$token = RegistrationToken::validOrFail($data['attributes']['token']);
|
||||
|
||||
$password = $password ?: Str::random(20);
|
||||
|
|
|
@ -81,7 +81,7 @@ class EmailToken extends AbstractModel
|
|||
*/
|
||||
public function scopeValidOrFail($query, $id)
|
||||
{
|
||||
/** @var EmailToken $token */
|
||||
/** @var static|null $token */
|
||||
$token = $query->find($id);
|
||||
|
||||
if (! $token || $token->created_at->diffInDays() >= 1) {
|
||||
|
|
|
@ -12,6 +12,9 @@ namespace Flarum\User;
|
|||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Http\SlugDriverInterface;
|
||||
|
||||
/**
|
||||
* @implements SlugDriverInterface<User>
|
||||
*/
|
||||
class IdSlugDriver implements SlugDriverInterface
|
||||
{
|
||||
/**
|
||||
|
@ -24,11 +27,17 @@ class IdSlugDriver implements SlugDriverInterface
|
|||
$this->users = $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $instance
|
||||
*/
|
||||
public function toSlug(AbstractModel $instance): string
|
||||
{
|
||||
return $instance->id;
|
||||
return (string) $instance->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function fromSlug(string $slug, User $actor): AbstractModel
|
||||
{
|
||||
return $this->users->findOrFail($slug, $actor);
|
||||
|
|
|
@ -21,6 +21,8 @@ use Illuminate\Support\Str;
|
|||
* @property array $user_attributes
|
||||
* @property array $payload
|
||||
* @property \Carbon\Carbon $created_at
|
||||
*
|
||||
* @method static self validOrFail(string $token)
|
||||
*/
|
||||
class RegistrationToken extends AbstractModel
|
||||
{
|
||||
|
@ -74,7 +76,7 @@ class RegistrationToken extends AbstractModel
|
|||
/**
|
||||
* Find the token with the given ID, and assert that it has not expired.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param \Illuminate\Database\Eloquent\Builder<self> $query
|
||||
* @param string $token
|
||||
*
|
||||
* @throws InvalidConfirmationTokenException
|
||||
|
@ -83,7 +85,7 @@ class RegistrationToken extends AbstractModel
|
|||
*/
|
||||
public function scopeValidOrFail($query, string $token)
|
||||
{
|
||||
/** @var RegistrationToken $token */
|
||||
/** @var RegistrationToken|null $token */
|
||||
$token = $query->find($token);
|
||||
|
||||
if (! $token || $token->created_at->lessThan(Carbon::now()->subDay())) {
|
||||
|
|
|
@ -50,5 +50,7 @@ class FulltextGambit implements GambitInterface
|
|||
'id',
|
||||
$this->getUserSearchSubQuery($searchValue)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ class User extends AbstractModel
|
|||
/**
|
||||
* The access gate.
|
||||
*
|
||||
* @var Gate
|
||||
* @var Access\Gate
|
||||
*/
|
||||
protected static $gate;
|
||||
|
||||
|
@ -172,7 +172,7 @@ class User extends AbstractModel
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Gate $gate
|
||||
* @param Access\Gate $gate
|
||||
*/
|
||||
public static function setGate($gate)
|
||||
{
|
||||
|
@ -296,7 +296,7 @@ class User extends AbstractModel
|
|||
/**
|
||||
* Change the path of the user avatar.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string|null $path
|
||||
* @return $this
|
||||
*/
|
||||
public function changeAvatarPath($path)
|
||||
|
@ -311,7 +311,6 @@ class User extends AbstractModel
|
|||
/**
|
||||
* Get the URL of the user's avatar.
|
||||
*
|
||||
* @todo Allow different storage locations to be used
|
||||
* @param string|null $value
|
||||
* @return string
|
||||
*/
|
||||
|
@ -410,15 +409,6 @@ class User extends AbstractModel
|
|||
return false;
|
||||
}
|
||||
|
||||
private function checkForDeprecatedPermissions($permission)
|
||||
{
|
||||
foreach (['viewDiscussions', 'viewUserList'] as $deprecated) {
|
||||
if (strpos($permission, $deprecated) !== false) {
|
||||
trigger_error('The `viewDiscussions` and `viewUserList` permissions have been renamed to `viewForum` and `searchUsers` respectively. Please use those instead.', E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification types that should be alerted to this user, according
|
||||
* to their preferences.
|
||||
|
@ -482,7 +472,7 @@ class User extends AbstractModel
|
|||
* Get the values of all registered preferences for this user, by
|
||||
* transforming their stored preferences and merging them with the defaults.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string|null $value
|
||||
* @return array
|
||||
*/
|
||||
public function getPreferencesAttribute($value)
|
||||
|
@ -679,7 +669,7 @@ class User extends AbstractModel
|
|||
/**
|
||||
* Define the relationship with the user's read discussions.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<Discussion>
|
||||
*/
|
||||
public function read()
|
||||
{
|
||||
|
@ -838,7 +828,7 @@ class User extends AbstractModel
|
|||
* Register a callback that processes a user's list of groups.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @return array $groupIds
|
||||
* @return void
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,7 @@ class UserRepository
|
|||
/**
|
||||
* Get a new query builder for the users table.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
* @return Builder<User>
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
|
@ -27,15 +27,15 @@ class UserRepository
|
|||
* Find a user by ID, optionally making sure it is visible to a certain
|
||||
* user, or throw an exception.
|
||||
*
|
||||
* @param int $id
|
||||
* @param User $actor
|
||||
* @param int|string $id
|
||||
* @param User|null $actor
|
||||
* @return User
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
||||
*/
|
||||
public function findOrFail($id, User $actor = null)
|
||||
{
|
||||
$query = User::where('id', $id);
|
||||
$query = $this->query()->where('id', $id);
|
||||
|
||||
return $this->scopeVisibleTo($query, $actor)->firstOrFail();
|
||||
}
|
||||
|
@ -44,15 +44,15 @@ class UserRepository
|
|||
* Find a user by username, optionally making sure it is visible to a certain
|
||||
* user, or throw an exception.
|
||||
*
|
||||
* @param int $id
|
||||
* @param User $actor
|
||||
* @param string $username
|
||||
* @param User|null $actor
|
||||
* @return User
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
||||
*/
|
||||
public function findOrFailByUsername($username, User $actor = null)
|
||||
{
|
||||
$query = User::where('username', $username);
|
||||
$query = $this->query()->where('username', $username);
|
||||
|
||||
return $this->scopeVisibleTo($query, $actor)->firstOrFail();
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class UserRepository
|
|||
{
|
||||
$field = filter_var($identification, FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
|
||||
|
||||
return User::where($field, $identification)->first();
|
||||
return $this->query()->where($field, $identification)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +78,7 @@ class UserRepository
|
|||
*/
|
||||
public function findByEmail($email)
|
||||
{
|
||||
return User::where('email', $email)->first();
|
||||
return $this->query()->where('email', $email)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,7 +90,7 @@ class UserRepository
|
|||
*/
|
||||
public function getIdForUsername($username, User $actor = null)
|
||||
{
|
||||
$query = User::where('username', $username);
|
||||
$query = $this->query()->where('username', $username);
|
||||
|
||||
return $this->scopeVisibleTo($query, $actor)->value('id');
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ class UserRepository
|
|||
{
|
||||
$string = $this->escapeLikeString($string);
|
||||
|
||||
$query = User::where('username', 'like', '%'.$string.'%')
|
||||
$query = $this->query()->where('username', 'like', '%'.$string.'%')
|
||||
->orderByRaw('username = ? desc', [$string])
|
||||
->orderByRaw('username like ? desc', [$string.'%']);
|
||||
|
||||
|
@ -117,9 +117,9 @@ class UserRepository
|
|||
/**
|
||||
* Scope a query to only include records that are visible to a user.
|
||||
*
|
||||
* @param Builder $query
|
||||
* @param User $actor
|
||||
* @return Builder
|
||||
* @param Builder<User> $query
|
||||
* @param User|null $actor
|
||||
* @return Builder<User>
|
||||
*/
|
||||
protected function scopeVisibleTo(Builder $query, User $actor = null)
|
||||
{
|
||||
|
|
|
@ -109,6 +109,9 @@ class UserServiceProvider extends AbstractServiceProvider
|
|||
User::addGroupProcessor(ContainerUtil::wrapCallback($callback, $container));
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Container\Container $container
|
||||
*/
|
||||
User::setHasher($container->make('hash'));
|
||||
User::setPasswordCheckers($container->make('flarum.user.password_checkers'));
|
||||
User::setGate($container->makeWith(Access\Gate::class, ['policyClasses' => $container->make('flarum.policies')]));
|
||||
|
|
|
@ -14,7 +14,7 @@ use Flarum\Foundation\AbstractValidator;
|
|||
class UserValidator extends AbstractValidator
|
||||
{
|
||||
/**
|
||||
* @var User
|
||||
* @var User|null
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@ namespace Flarum\User;
|
|||
use Flarum\Database\AbstractModel;
|
||||
use Flarum\Http\SlugDriverInterface;
|
||||
|
||||
/**
|
||||
* @implements SlugDriverInterface<User>
|
||||
*/
|
||||
class UsernameSlugDriver implements SlugDriverInterface
|
||||
{
|
||||
/**
|
||||
|
@ -24,11 +27,17 @@ class UsernameSlugDriver implements SlugDriverInterface
|
|||
$this->users = $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $instance
|
||||
*/
|
||||
public function toSlug(AbstractModel $instance): string
|
||||
{
|
||||
return $instance->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function fromSlug(string $slug, User $actor): AbstractModel
|
||||
{
|
||||
return $this->users->findOrFailByUsername($slug, $actor);
|
||||
|
|
|
@ -16,11 +16,11 @@ if (! function_exists('resolve')) {
|
|||
* Resolve a service from the container.
|
||||
*
|
||||
* @template T
|
||||
* @param class-string<T>|string $name
|
||||
* @param array $parameters
|
||||
* @param string|class-string<T> $name
|
||||
* @param array $parameters
|
||||
* @return T|mixed
|
||||
*/
|
||||
function resolve($name, $parameters = [])
|
||||
function resolve(string $name, array $parameters = [])
|
||||
{
|
||||
return Container::getInstance()->make($name, $parameters);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
"minimum-stability": "dev",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"phpstan/phpstan-php-parser": "^1.0",
|
||||
"phpstan/phpstan": "^1.2"
|
||||
"phpstan/phpstan": "^1.2",
|
||||
"nunomaduro/larastan": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
@ -1,291 +1,17 @@
|
|||
includes:
|
||||
- vendor/phpstan/phpstan-php-parser/extension.neon
|
||||
- larastan-extension.neon
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
stubFiles:
|
||||
- stubs/Illuminate/Enumerable.stub
|
||||
- stubs/Illuminate/Database/EloquentBuilder.stub
|
||||
- stubs/Illuminate/Collection.stub
|
||||
- stubs/Illuminate/Database/EloquentCollection.stub
|
||||
- stubs/Illuminate/Database/Factory.stub
|
||||
- stubs/Illuminate/Database/Model.stub
|
||||
- stubs/Illuminate/Database/Gate.stub
|
||||
- stubs/Illuminate/Database/Relation.stub
|
||||
- stubs/Illuminate/Database/BelongsTo.stub
|
||||
- stubs/Illuminate/Database/BelongsToMany.stub
|
||||
- stubs/Illuminate/Database/HasOneOrMany.stub
|
||||
- stubs/Illuminate/Database/HasMany.stub
|
||||
- stubs/Illuminate/Database/HasOne.stub
|
||||
- stubs/Illuminate/Database/HasOneThrough.stub
|
||||
- stubs/Illuminate/Database/HasManyThrough.stub
|
||||
- stubs/Illuminate/Database/MorphTo.stub
|
||||
- stubs/Illuminate/Database/MorphToMany.stub
|
||||
- stubs/Illuminate/Database/MorphMany.stub
|
||||
- stubs/Illuminate/Database/MorphOne.stub
|
||||
- stubs/Illuminate/Database/MorphOneOrMany.stub
|
||||
- stubs/Illuminate/HigherOrderProxies.stub
|
||||
- stubs/Illuminate/Database/QueryBuilder.stub
|
||||
- stubs/Illuminate/EnumeratesValues.stub
|
||||
- stubs/Contracts/Support.stub
|
||||
universalObjectCratesClasses:
|
||||
- Illuminate\Http\Request
|
||||
mixinExcludeClasses:
|
||||
- Eloquent
|
||||
earlyTerminatingFunctionCalls:
|
||||
- abort
|
||||
- dd
|
||||
excludePaths:
|
||||
- *.blade.php
|
||||
checkGenericClassInNonGenericObjectType: false
|
||||
checkModelProperties: false
|
||||
databaseMigrationsPath: []
|
||||
stubFiles:
|
||||
- stubs/Illuminate/Contracts/Container/Container.stub
|
||||
- stubs/Illuminate/Queue/ListenerOptions.stub
|
||||
- stubs/Illuminate/Support/ServiceProvider.stub
|
||||
- stubs/Illuminate/Filesystem/Filesystem.stub
|
||||
- stubs/Illuminate/Filesystem/FilesystemManager.stub
|
||||
|
||||
parametersSchema:
|
||||
databaseMigrationsPath: listOf(string())
|
||||
checkModelProperties: bool()
|
||||
|
||||
services:
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\RelationForwardsCallsExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\ModelForwardsCallsExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\EloquentBuilderForwardsCallsExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\HigherOrderTapProxyExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\HigherOrderCollectionProxyExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\StorageMethodsClassReflectionExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\Extension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\ModelFactoryMethodsClassReflectionExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Properties\ModelAccessorExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Properties\ModelPropertyExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Properties\HigherOrderCollectionProxyPropertyExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\RelationDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\ModelRelationsDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\HigherOrderTapProxyExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Contracts\Container\Container
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Container\Container
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Foundation\Application
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Contracts\Foundation\Application
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Properties\ModelRelationsExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\ModelFactoryDynamicStaticMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\ModelExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\RequestExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\EloquentBuilderExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\RelationFindExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\RelationCollectionExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\ModelFindExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\BuilderModelFindExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\TestCaseExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\CollectionMakeDynamicStaticMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Support\CollectionHelper
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\Helpers\CollectExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\Helpers\TransExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\Helpers\ValidatorExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\CollectionFilterDynamicReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: 'abort'
|
||||
negate: false
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: 'abort'
|
||||
negate: true
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: throw
|
||||
negate: false
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: throw
|
||||
negate: true
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\Helpers\AppExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\Helpers\ValueExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\Helpers\TapExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\ReturnTypes\StorageDynamicStaticMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\GenericEloquentCollectionTypeNodeResolverExtension
|
||||
tags:
|
||||
- phpstan.phpDoc.typeNodeResolverExtension
|
||||
|
||||
-
|
||||
class: Flarum\PHPStan\Types\ViewStringTypeNodeResolverExtension
|
||||
tags:
|
||||
- phpstan.phpDoc.typeNodeResolverExtension
|
||||
-
|
||||
class: Flarum\PHPStan\Methods\BuilderHelper
|
||||
arguments:
|
||||
checkProperties: %checkModelProperties%
|
||||
-
|
||||
class: Flarum\PHPStan\Properties\MigrationHelper
|
||||
arguments:
|
||||
databaseMigrationPath: %databaseMigrationsPath%
|
||||
parser: @currentPhpVersionSimpleDirectParser
|
||||
-
|
||||
class: Flarum\PHPStan\Types\RelationParserHelper
|
||||
arguments:
|
||||
parser: @currentPhpVersionSimpleDirectParser
|
||||
# We're changing the disk return type from Filesystem to Cloud,
|
||||
# rather than hacking every bit of the codebase with a phpdoc @var.
|
||||
- stubs/Illuminate/Contracts/Filesystem/Factory.stub
|
||||
- stubs/Illuminate/Contracts/Filesystem/Cloud.stub
|
||||
- stubs/Illuminate/Contracts/Filesystem/Filesystem.stub
|
||||
|
|
439
php-packages/phpstan/larastan-extension.neon
Normal file
439
php-packages/phpstan/larastan-extension.neon
Normal file
|
@ -0,0 +1,439 @@
|
|||
parameters:
|
||||
stubFiles:
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Enumerable.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/EloquentBuilder.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Collection.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/EloquentCollection.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Factory.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Model.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Gate.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Relation.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/BelongsTo.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/BelongsToMany.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/HasOneOrMany.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/HasMany.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/HasOne.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/HasOneThrough.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/HasManyThrough.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Mailable.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/MorphOne.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/MorphOneOrMany.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/MorphTo.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/MorphToMany.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/MorphMany.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Helpers.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/HigherOrderProxies.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/QueryBuilder.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Facades.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Pagination.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Contracts/Pagination.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Contracts/Support.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Redis/Connection.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/Logger.stub
|
||||
- ../../vendor/nunomaduro/larastan/stubs/EnumeratesValues.stub
|
||||
universalObjectCratesClasses:
|
||||
- Illuminate\Http\Request
|
||||
earlyTerminatingFunctionCalls:
|
||||
- abort
|
||||
- dd
|
||||
excludePaths:
|
||||
- *.blade.php
|
||||
mixinExcludeClasses:
|
||||
- Eloquent
|
||||
# bootstrapFiles:
|
||||
# - bootstrap.php
|
||||
checkGenericClassInNonGenericObjectType: false
|
||||
checkOctaneCompatibility: false
|
||||
noModelMake: true
|
||||
noUnnecessaryCollectionCall: true
|
||||
noUnnecessaryCollectionCallOnly: []
|
||||
noUnnecessaryCollectionCallExcept: []
|
||||
databaseMigrationsPath: []
|
||||
checkModelProperties: false
|
||||
checkPhpDocMissingReturn: false
|
||||
|
||||
parametersSchema:
|
||||
checkOctaneCompatibility: bool()
|
||||
noModelMake: bool()
|
||||
noUnnecessaryCollectionCall: bool()
|
||||
noUnnecessaryCollectionCallOnly: listOf(string())
|
||||
noUnnecessaryCollectionCallExcept: listOf(string())
|
||||
databaseMigrationsPath: listOf(string())
|
||||
checkModelProperties: bool()
|
||||
|
||||
conditionalTags:
|
||||
NunoMaduro\Larastan\Rules\NoModelMakeRule:
|
||||
phpstan.rules.rule: %noModelMake%
|
||||
NunoMaduro\Larastan\Rules\NoUnnecessaryCollectionCallRule:
|
||||
phpstan.rules.rule: %noUnnecessaryCollectionCall%
|
||||
NunoMaduro\Larastan\Rules\OctaneCompatibilityRule:
|
||||
phpstan.rules.rule: %checkOctaneCompatibility%
|
||||
NunoMaduro\Larastan\Rules\ModelProperties\ModelPropertyRule:
|
||||
phpstan.rules.rule: %checkModelProperties%
|
||||
NunoMaduro\Larastan\Rules\ModelProperties\ModelPropertyStaticCallRule:
|
||||
phpstan.rules.rule: %checkModelProperties%
|
||||
|
||||
services:
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\RelationForwardsCallsExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\ModelForwardsCallsExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\EloquentBuilderForwardsCallsExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\HigherOrderTapProxyExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\HigherOrderCollectionProxyExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\StorageMethodsClassReflectionExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\Extension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\ModelFactoryMethodsClassReflectionExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\RedirectResponseMethodsClassReflectionExtension
|
||||
tags:
|
||||
- phpstan.broker.methodsClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Properties\ModelAccessorExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Properties\ModelPropertyExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Properties\HigherOrderCollectionProxyPropertyExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\RelationDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\ModelRelationsDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\HigherOrderTapProxyExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Contracts\Container\Container
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Container\Container
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Foundation\Application
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\ContainerArrayAccessDynamicMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
arguments:
|
||||
className: Illuminate\Contracts\Foundation\Application
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Properties\ModelRelationsExtension
|
||||
tags:
|
||||
- phpstan.broker.propertiesClassReflectionExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\ModelFactoryDynamicStaticMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\ModelExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\AuthExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\GuardDynamicStaticMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\AuthManagerExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\GuardExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\RequestExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\EloquentBuilderExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\RelationFindExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\RelationCollectionExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\ModelFindExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\BuilderModelFindExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\TestCaseExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\CollectionMakeDynamicStaticMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Support\CollectionHelper
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\AuthExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\CollectExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\CookieExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\ResponseExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\RequestExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\RedirectExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\UrlExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\ViewExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\TransExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\ValidatorExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\CollectionFilterDynamicReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: 'abort'
|
||||
negate: false
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: 'abort'
|
||||
negate: true
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: throw
|
||||
negate: false
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\AbortIfFunctionTypeSpecifyingExtension
|
||||
tags:
|
||||
- phpstan.typeSpecifier.functionTypeSpecifyingExtension
|
||||
arguments:
|
||||
methodName: throw
|
||||
negate: true
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\AppExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\ValueExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\Helpers\TapExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicFunctionReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\ReturnTypes\StorageDynamicStaticMethodReturnTypeExtension
|
||||
tags:
|
||||
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\GenericEloquentCollectionTypeNodeResolverExtension
|
||||
tags:
|
||||
- phpstan.phpDoc.typeNodeResolverExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\ViewStringTypeNodeResolverExtension
|
||||
tags:
|
||||
- phpstan.phpDoc.typeNodeResolverExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\OctaneCompatibilityRule
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\NoModelMakeRule
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\NoUnnecessaryCollectionCallRule
|
||||
arguments:
|
||||
onlyMethods: %noUnnecessaryCollectionCallOnly%
|
||||
excludeMethods: %noUnnecessaryCollectionCallExcept%
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\ModelProperties\ModelPropertyRule
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\ModelProperties\ModelPropertyStaticCallRule
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\GenericEloquentBuilderTypeNodeResolverExtension
|
||||
tags:
|
||||
- phpstan.phpDoc.typeNodeResolverExtension
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\ModelProperty\ModelPropertyTypeNodeResolverExtension
|
||||
tags:
|
||||
- phpstan.phpDoc.typeNodeResolverExtension
|
||||
arguments:
|
||||
active: %checkModelProperties%
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Types\RelationParserHelper
|
||||
arguments:
|
||||
parser: @currentPhpVersionSimpleDirectParser
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Properties\MigrationHelper
|
||||
arguments:
|
||||
databaseMigrationPath: %databaseMigrationsPath%
|
||||
parser: @currentPhpVersionSimpleDirectParser
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\ModelProperties\ModelPropertiesRuleHelper
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\ModelRuleHelper
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Methods\BuilderHelper
|
||||
arguments:
|
||||
checkProperties: %checkModelProperties%
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\RelationExistenceRule
|
||||
tags:
|
||||
- phpstan.rule
|
||||
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\CheckDispatchArgumentTypesCompatibleWithClassConstructorRule
|
||||
arguments:
|
||||
dispatchableClass: Illuminate\Foundation\Bus\Dispatchable
|
||||
tags:
|
||||
- phpstan.rules.rule
|
||||
-
|
||||
class: NunoMaduro\Larastan\Rules\CheckDispatchArgumentTypesCompatibleWithClassConstructorRule
|
||||
arguments:
|
||||
dispatchableClass: Illuminate\Foundation\Events\Dispatchable
|
||||
tags:
|
||||
- phpstan.rules.rule
|
||||
rules:
|
||||
- NunoMaduro\Larastan\Rules\RelationExistenceRule
|
17
php-packages/phpstan/phpstan-baseline.neon
Normal file
17
php-packages/phpstan/phpstan-baseline.neon
Normal file
|
@ -0,0 +1,17 @@
|
|||
parameters:
|
||||
ignoreErrors:
|
||||
# Remove this group below with larastan 2.0 (i.e Flarum 2.0)
|
||||
- "#Relation '[A-z_-]+' is not found in [A-z\_]+ model.#"
|
||||
- '#^Parameter \#1 \$query of method [A-z_<>\\]+\:\:union\(\) expects [A-z_<> .,|\\]+ given\.$#'
|
||||
- '#^Parameter \#1 \$query of method [A-z_<>\\]+\:\:joinSub\(\) expects [A-z_<> .,|\\]+ given\.$#'
|
||||
|
||||
# We ignore this because resolve can either take a class name as the generic return type or just a binding name.
|
||||
- "#Template type T of function resolve[()]{2} is not referenced in a parameter.#"
|
||||
|
||||
# We ignore new static errors because we want extensibility.
|
||||
# @TODO: needs discussion.
|
||||
- "#^Unsafe usage of new static[()]{2}.$#"
|
||||
|
||||
# ConnectionInterface lacks methods that exist in the implementation,
|
||||
# yet we don't want to inject the implementation.
|
||||
- '#^Call to an undefined method Illuminate\\Database\\ConnectionInterface\:\:[A-z0-9_]+\(\)\.$#'
|
|
@ -1,72 +0,0 @@
|
|||
<?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\Concerns;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Contracts\Container\Container as ContainerContract;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use ReflectionException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait HasContainer
|
||||
{
|
||||
/**
|
||||
* @var ?\Illuminate\Contracts\Container\Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Contracts\Container\Container $container
|
||||
* @return void
|
||||
*/
|
||||
public function setContainer(ContainerContract $container): void
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current broker.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Container\Container
|
||||
*/
|
||||
public function getContainer(): ContainerContract
|
||||
{
|
||||
return $this->container ?? Container::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given type from the container.
|
||||
*
|
||||
* @param string $abstract
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(string $abstract)
|
||||
{
|
||||
$concrete = null;
|
||||
|
||||
try {
|
||||
$concrete = $this->getContainer()
|
||||
->make($abstract);
|
||||
} catch (ReflectionException $exception) {
|
||||
// ..
|
||||
} catch (BindingResolutionException $exception) {
|
||||
// ..
|
||||
} catch (NotFoundExceptionInterface $exception) {
|
||||
// ..
|
||||
}
|
||||
|
||||
return $concrete;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?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\Concerns;
|
||||
|
||||
use Illuminate\Config\Repository as ConfigRepository;
|
||||
|
||||
trait LoadsAuthModel
|
||||
{
|
||||
/** @phpstan-return class-string|null */
|
||||
private function getAuthModel(ConfigRepository $config, ?string $guard = null): ?string
|
||||
{
|
||||
if (
|
||||
($guard === null && ! ($guard = $config->get('auth.defaults.guard'))) ||
|
||||
! ($provider = $config->get('auth.guards.'.$guard.'.provider')) ||
|
||||
! ($authModel = $config->get('auth.providers.'.$provider.'.model'))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $authModel;
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* 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\Contracts\Methods;
|
||||
|
||||
use Illuminate\Contracts\Container\Container as ContainerContract;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\Php\PhpMethodReflectionFactory;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface PassableContract
|
||||
{
|
||||
/**
|
||||
* @param \Illuminate\Contracts\Container\Container $container
|
||||
* @return void
|
||||
*/
|
||||
public function setContainer(ContainerContract $container): void;
|
||||
|
||||
/**
|
||||
* @return \PHPStan\Reflection\ClassReflection
|
||||
*/
|
||||
public function getClassReflection(): ClassReflection;
|
||||
|
||||
/**
|
||||
* @param \PHPStan\Reflection\ClassReflection $classReflection
|
||||
* @return PassableContract
|
||||
*/
|
||||
public function setClassReflection(ClassReflection $classReflection): PassableContract;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMethodName(): string;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasFound(): bool;
|
||||
|
||||
/**
|
||||
* @param string $class
|
||||
* @return bool
|
||||
*/
|
||||
public function searchOn(string $class): bool;
|
||||
|
||||
/**
|
||||
* @return \PHPStan\Reflection\MethodReflection
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function getMethodReflection(): MethodReflection;
|
||||
|
||||
/**
|
||||
* @param \PHPStan\Reflection\MethodReflection $methodReflection
|
||||
*/
|
||||
public function setMethodReflection(MethodReflection $methodReflection): void;
|
||||
|
||||
/**
|
||||
* Declares that the provided method can be called statically.
|
||||
*
|
||||
* @param bool $staticAllowed
|
||||
* @return void
|
||||
*/
|
||||
public function setStaticAllowed(bool $staticAllowed): void;
|
||||
|
||||
/**
|
||||
* Returns whether the method can be called statically.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isStaticAllowed(): bool;
|
||||
|
||||
/**
|
||||
* @param class-string $class
|
||||
* @param bool $staticAllowed
|
||||
* @return bool
|
||||
*/
|
||||
public function sendToPipeline(string $class, $staticAllowed = false): bool;
|
||||
|
||||
public function getReflectionProvider(): ReflectionProvider;
|
||||
|
||||
/**
|
||||
* @return \PHPStan\Reflection\Php\PhpMethodReflectionFactory
|
||||
*/
|
||||
public function getMethodReflectionFactory(): PhpMethodReflectionFactory;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<?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\Contracts\Methods\Pipes;
|
||||
|
||||
use Closure;
|
||||
use Flarum\PHPStan\Contracts\Methods\PassableContract;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface PipeContract
|
||||
{
|
||||
/**
|
||||
* @param \Flarum\PHPStan\Contracts\Methods\PassableContract $passable
|
||||
* @param \Closure $next
|
||||
* @return void
|
||||
*/
|
||||
public function handle(PassableContract $passable, Closure $next): void;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* 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\Contracts\Types;
|
||||
|
||||
use PHPStan\Type\Type;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface PassableContract
|
||||
{
|
||||
/**
|
||||
* @return \PHPStan\Type\Type
|
||||
*/
|
||||
public function getType(): Type;
|
||||
|
||||
/**
|
||||
* @param \PHPStan\Type\Type $type
|
||||
* @return void
|
||||
*/
|
||||
public function setType(Type $type): void;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<?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\Contracts\Types\Pipes;
|
||||
|
||||
use Closure;
|
||||
use Flarum\PHPStan\Contracts\Types\PassableContract;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface PipeContract
|
||||
{
|
||||
/**
|
||||
* @param \Flarum\PHPStan\Contracts\Types\PassableContract $passable
|
||||
* @param \Closure $next
|
||||
* @return void
|
||||
*/
|
||||
public function handle(PassableContract $passable, Closure $next): void;
|
||||
}
|
|
@ -1,241 +0,0 @@
|
|||
<?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\AnnotationScopeMethodParameterReflection;
|
||||
use Flarum\PHPStan\Reflection\AnnotationScopeMethodReflection;
|
||||
use Flarum\PHPStan\Reflection\DynamicWhereParameterReflection;
|
||||
use Flarum\PHPStan\Reflection\EloquentBuilderMethodReflection;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Support\Str;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\MissingMethodFromReflectionException;
|
||||
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PHPStan\ShouldNotHappenException;
|
||||
use PHPStan\TrinaryLogic;
|
||||
use PHPStan\Type\Generic\GenericObjectType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\VerbosityLevel;
|
||||
|
||||
class BuilderHelper
|
||||
{
|
||||
/** @var string[] */
|
||||
public const MODEL_RETRIEVAL_METHODS = ['first', 'find', 'findMany', 'findOrFail', 'firstOrFail', 'sole'];
|
||||
|
||||
/** @var string[] */
|
||||
public const MODEL_CREATION_METHODS = ['make', 'create', 'forceCreate', 'findOrNew', 'firstOrNew', 'updateOrCreate', 'firstOrCreate'];
|
||||
|
||||
/**
|
||||
* The methods that should be returned from query builder.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $passthru = [
|
||||
'average', 'avg',
|
||||
'count',
|
||||
'dd', 'dump',
|
||||
'doesntExist', 'exists',
|
||||
'getBindings', 'getConnection', 'getGrammar',
|
||||
'insert', 'insertGetId', 'insertOrIgnore', 'insertUsing',
|
||||
'max', 'min',
|
||||
'raw',
|
||||
'sum',
|
||||
'toSql',
|
||||
];
|
||||
|
||||
/** @var ReflectionProvider */
|
||||
private $reflectionProvider;
|
||||
|
||||
/** @var bool */
|
||||
private $checkProperties;
|
||||
|
||||
public function __construct(ReflectionProvider $reflectionProvider, bool $checkProperties)
|
||||
{
|
||||
$this->reflectionProvider = $reflectionProvider;
|
||||
$this->checkProperties = $checkProperties;
|
||||
}
|
||||
|
||||
public function dynamicWhere(
|
||||
string $methodName,
|
||||
Type $returnObject
|
||||
): ?EloquentBuilderMethodReflection {
|
||||
if (! Str::startsWith($methodName, 'where')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($returnObject instanceof GenericObjectType && $this->checkProperties) {
|
||||
$returnClassReflection = $returnObject->getClassReflection();
|
||||
|
||||
if ($returnClassReflection !== null) {
|
||||
$modelType = $returnClassReflection->getActiveTemplateTypeMap()->getType('TModelClass');
|
||||
|
||||
if ($modelType === null) {
|
||||
$modelType = $returnClassReflection->getActiveTemplateTypeMap()->getType('TRelatedModel');
|
||||
}
|
||||
|
||||
if ($modelType !== null) {
|
||||
$finder = substr($methodName, 5);
|
||||
|
||||
$segments = preg_split(
|
||||
'/(And|Or)(?=[A-Z])/',
|
||||
$finder,
|
||||
-1,
|
||||
PREG_SPLIT_DELIM_CAPTURE
|
||||
);
|
||||
|
||||
if ($segments !== false) {
|
||||
$trinaryLogic = TrinaryLogic::createYes();
|
||||
|
||||
foreach ($segments as $segment) {
|
||||
if ($segment !== 'And' && $segment !== 'Or') {
|
||||
$trinaryLogic = $trinaryLogic->and($modelType->hasProperty(Str::snake($segment)));
|
||||
}
|
||||
}
|
||||
|
||||
if (! $trinaryLogic->yes()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$classReflection = $this->reflectionProvider->getClass(QueryBuilder::class);
|
||||
|
||||
$methodReflection = $classReflection->getNativeMethod('dynamicWhere');
|
||||
|
||||
return new EloquentBuilderMethodReflection(
|
||||
$methodName,
|
||||
$classReflection,
|
||||
$methodReflection,
|
||||
[new DynamicWhereParameterReflection],
|
||||
$returnObject,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method mimics the `EloquentBuilder::__call` method.
|
||||
* Does not handle the case where $methodName exists in `EloquentBuilder`,
|
||||
* that should be checked by caller before calling this method.
|
||||
*
|
||||
* @param ClassReflection $eloquentBuilder Can be `EloquentBuilder` or a custom builder extending it.
|
||||
* @param string $methodName
|
||||
* @param ClassReflection $model
|
||||
* @return MethodReflection|null
|
||||
*
|
||||
* @throws MissingMethodFromReflectionException
|
||||
* @throws ShouldNotHappenException
|
||||
*/
|
||||
public function searchOnEloquentBuilder(ClassReflection $eloquentBuilder, string $methodName, ClassReflection $model): ?MethodReflection
|
||||
{
|
||||
// Check for local query scopes
|
||||
if (array_key_exists('scope'.ucfirst($methodName), $model->getMethodTags())) {
|
||||
$methodTag = $model->getMethodTags()['scope'.ucfirst($methodName)];
|
||||
|
||||
$parameters = [];
|
||||
foreach ($methodTag->getParameters() as $parameterName => $parameterTag) {
|
||||
$parameters[] = new AnnotationScopeMethodParameterReflection($parameterName, $parameterTag->getType(), $parameterTag->passedByReference(), $parameterTag->isOptional(), $parameterTag->isVariadic(), $parameterTag->getDefaultValue());
|
||||
}
|
||||
|
||||
// We shift the parameters,
|
||||
// because first parameter is the Builder
|
||||
array_shift($parameters);
|
||||
|
||||
return new EloquentBuilderMethodReflection(
|
||||
'scope'.ucfirst($methodName),
|
||||
$model,
|
||||
new AnnotationScopeMethodReflection('scope'.ucfirst($methodName), $model, $methodTag->getReturnType(), $parameters, $methodTag->isStatic(), false),
|
||||
$parameters,
|
||||
$methodTag->getReturnType()
|
||||
);
|
||||
}
|
||||
|
||||
if ($model->hasNativeMethod('scope'.ucfirst($methodName))) {
|
||||
$methodReflection = $model->getNativeMethod('scope'.ucfirst($methodName));
|
||||
$parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants());
|
||||
|
||||
$parameters = $parametersAcceptor->getParameters();
|
||||
// We shift the parameters,
|
||||
// because first parameter is the Builder
|
||||
array_shift($parameters);
|
||||
|
||||
$returnType = $parametersAcceptor->getReturnType();
|
||||
|
||||
return new EloquentBuilderMethodReflection(
|
||||
'scope'.ucfirst($methodName),
|
||||
$methodReflection->getDeclaringClass(),
|
||||
$methodReflection,
|
||||
$parameters,
|
||||
$returnType,
|
||||
$parametersAcceptor->isVariadic()
|
||||
);
|
||||
}
|
||||
|
||||
$queryBuilderReflection = $this->reflectionProvider->getClass(QueryBuilder::class);
|
||||
|
||||
if (in_array($methodName, $this->passthru, true)) {
|
||||
return $queryBuilderReflection->getNativeMethod($methodName);
|
||||
}
|
||||
|
||||
if ($queryBuilderReflection->hasNativeMethod($methodName)) {
|
||||
return $queryBuilderReflection->getNativeMethod($methodName);
|
||||
}
|
||||
|
||||
return $this->dynamicWhere($methodName, new GenericObjectType($eloquentBuilder->getName(), [new ObjectType($model->getName())]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $modelClassName
|
||||
* @return string
|
||||
*
|
||||
* @throws MissingMethodFromReflectionException
|
||||
* @throws ShouldNotHappenException
|
||||
*/
|
||||
public function determineBuilderName(string $modelClassName): string
|
||||
{
|
||||
$method = $this->reflectionProvider->getClass($modelClassName)->getNativeMethod('newEloquentBuilder');
|
||||
|
||||
$returnType = ParametersAcceptorSelector::selectSingle($method->getVariants())->getReturnType();
|
||||
|
||||
if (in_array(EloquentBuilder::class, $returnType->getReferencedClasses(), true)) {
|
||||
return EloquentBuilder::class;
|
||||
}
|
||||
|
||||
if ($returnType instanceof ObjectType) {
|
||||
return $returnType->getClassName();
|
||||
}
|
||||
|
||||
return $returnType->describe(VerbosityLevel::value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MissingMethodFromReflectionException
|
||||
* @throws ShouldNotHappenException
|
||||
*/
|
||||
public function determineCollectionClassName(string $modelClassName): string
|
||||
{
|
||||
$newCollectionMethod = $this->reflectionProvider->getClass($modelClassName)->getNativeMethod('newCollection');
|
||||
|
||||
$returnType = ParametersAcceptorSelector::selectSingle($newCollectionMethod->getVariants())->getReturnType();
|
||||
|
||||
if ($returnType instanceof ObjectType) {
|
||||
return $returnType->getClassName();
|
||||
}
|
||||
|
||||
return $returnType->describe(VerbosityLevel::value());
|
||||
}
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
<?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()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?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 Illuminate\Database\Eloquent\Model;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\MethodsClassReflectionExtension;
|
||||
use PHPStan\Reflection\Php\PhpMethodReflectionFactory;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Extension implements MethodsClassReflectionExtension
|
||||
{
|
||||
/**
|
||||
* @var Kernel
|
||||
*/
|
||||
private $kernel;
|
||||
|
||||
/** @var MethodReflection[] */
|
||||
private $methodReflections = [];
|
||||
|
||||
public function __construct(PhpMethodReflectionFactory $methodReflectionFactory, ReflectionProvider $reflectionProvider, Kernel $kernel = null)
|
||||
{
|
||||
$this->kernel = $kernel ?? new Kernel($methodReflectionFactory, $reflectionProvider);
|
||||
}
|
||||
|
||||
public function hasMethod(ClassReflection $classReflection, string $methodName): bool
|
||||
{
|
||||
if ($classReflection->getName() === Model::class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (array_key_exists($methodName.'-'.$classReflection->getName(), $this->methodReflections)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$passable = $this->kernel->handle($classReflection, $methodName);
|
||||
|
||||
$found = $passable->hasFound();
|
||||
|
||||
if ($found) {
|
||||
$this->methodReflections[$methodName.'-'.$classReflection->getName()] = $passable->getMethodReflection();
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection
|
||||
{
|
||||
return $this->methodReflections[$methodName.'-'.$classReflection->getName()];
|
||||
}
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
<?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\Support\HigherOrderCollectionProxyHelper;
|
||||
use PHPStan\Analyser\OutOfClassScope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\FunctionVariant;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\MethodsClassReflectionExtension;
|
||||
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||
use PHPStan\TrinaryLogic;
|
||||
use PHPStan\Type;
|
||||
|
||||
final class HigherOrderCollectionProxyExtension implements MethodsClassReflectionExtension
|
||||
{
|
||||
public function hasMethod(ClassReflection $classReflection, string $methodName): bool
|
||||
{
|
||||
return HigherOrderCollectionProxyHelper::hasPropertyOrMethod($classReflection, $methodName, 'method');
|
||||
}
|
||||
|
||||
public function getMethod(
|
||||
ClassReflection $classReflection,
|
||||
string $methodName
|
||||
): MethodReflection {
|
||||
$activeTemplateTypeMap = $classReflection->getActiveTemplateTypeMap();
|
||||
|
||||
/** @var Type\Constant\ConstantStringType $methodType */
|
||||
$methodType = $activeTemplateTypeMap->getType('T');
|
||||
|
||||
/** @var Type\ObjectType $valueType */
|
||||
$valueType = $activeTemplateTypeMap->getType('TValue');
|
||||
|
||||
$modelMethodReflection = $valueType->getMethod($methodName, new OutOfClassScope());
|
||||
|
||||
$modelMethodReturnType = ParametersAcceptorSelector::selectSingle($modelMethodReflection->getVariants())->getReturnType();
|
||||
|
||||
$returnType = HigherOrderCollectionProxyHelper::determineReturnType($methodType->getValue(), $valueType, $modelMethodReturnType);
|
||||
|
||||
return new class($classReflection, $methodName, $modelMethodReflection, $returnType) implements MethodReflection {
|
||||
/** @var ClassReflection */
|
||||
private $classReflection;
|
||||
|
||||
/** @var string */
|
||||
private $methodName;
|
||||
|
||||
/** @var MethodReflection */
|
||||
private $modelMethodReflection;
|
||||
|
||||
/** @var Type\Type */
|
||||
private $returnType;
|
||||
|
||||
public function __construct(ClassReflection $classReflection, string $methodName, MethodReflection $modelMethodReflection, Type\Type $returnType)
|
||||
{
|
||||
$this->classReflection = $classReflection;
|
||||
$this->methodName = $methodName;
|
||||
$this->modelMethodReflection = $modelMethodReflection;
|
||||
$this->returnType = $returnType;
|
||||
}
|
||||
|
||||
public function getDeclaringClass(): \PHPStan\Reflection\ClassReflection
|
||||
{
|
||||
return $this->classReflection;
|
||||
}
|
||||
|
||||
public function isStatic(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isPrivate(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDocComment(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->methodName;
|
||||
}
|
||||
|
||||
public function getPrototype(): \PHPStan\Reflection\ClassMemberReflection
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVariants(): array
|
||||
{
|
||||
return [
|
||||
new FunctionVariant(
|
||||
ParametersAcceptorSelector::selectSingle($this->modelMethodReflection->getVariants())->getTemplateTypeMap(),
|
||||
ParametersAcceptorSelector::selectSingle($this->modelMethodReflection->getVariants())->getResolvedTemplateTypeMap(),
|
||||
ParametersAcceptorSelector::selectSingle($this->modelMethodReflection->getVariants())->getParameters(),
|
||||
ParametersAcceptorSelector::selectSingle($this->modelMethodReflection->getVariants())->isVariadic(),
|
||||
$this->returnType
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
public function isDeprecated(): TrinaryLogic
|
||||
{
|
||||
return TrinaryLogic::createNo();
|
||||
}
|
||||
|
||||
public function getDeprecatedDescription(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isFinal(): TrinaryLogic
|
||||
{
|
||||
return TrinaryLogic::createNo();
|
||||
}
|
||||
|
||||
public function isInternal(): TrinaryLogic
|
||||
{
|
||||
return TrinaryLogic::createNo();
|
||||
}
|
||||
|
||||
public function getThrowType(): ?\PHPStan\Type\Type
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function hasSideEffects(): TrinaryLogic
|
||||
{
|
||||
return TrinaryLogic::createMaybe();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
<?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 Illuminate\Support\HigherOrderTapProxy;
|
||||
use PHPStan\Analyser\OutOfClassScope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\MethodsClassReflectionExtension;
|
||||
use PHPStan\Type\ObjectType;
|
||||
|
||||
final class HigherOrderTapProxyExtension implements MethodsClassReflectionExtension
|
||||
{
|
||||
public function hasMethod(ClassReflection $classReflection, string $methodName): bool
|
||||
{
|
||||
if ($classReflection->getName() !== HigherOrderTapProxy::class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$templateTypeMap = $classReflection->getActiveTemplateTypeMap();
|
||||
|
||||
$templateType = $templateTypeMap->getType('TClass');
|
||||
|
||||
if (! $templateType instanceof ObjectType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($templateType->getClassReflection() === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $templateType->hasMethod($methodName)->yes();
|
||||
}
|
||||
|
||||
public function getMethod(
|
||||
ClassReflection $classReflection,
|
||||
string $methodName
|
||||
): MethodReflection {
|
||||
/** @var ObjectType $templateType */
|
||||
$templateType = $classReflection->getActiveTemplateTypeMap()->getType('TClass');
|
||||
|
||||
/** @var ClassReflection $reflection */
|
||||
$reflection = $templateType->getClassReflection();
|
||||
|
||||
return $reflection->getMethod($methodName, new OutOfClassScope());
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user