diff --git a/extensions/akismet/src/Akismet.php b/extensions/akismet/src/Akismet.php index a4edef634..0182144ec 100644 --- a/extensions/akismet/src/Akismet.php +++ b/extensions/akismet/src/Akismet.php @@ -15,22 +15,19 @@ use Psr\Http\Message\ResponseInterface; class Akismet { - private $apiKey; - private $apiUrl; - private $flarumVersion; - private $extensionVersion; + private string $apiUrl; + private array $params = []; - private $params = []; - - public function __construct(string $apiKey, string $homeUrl, string $flarumVersion, string $extensionVersion, bool $inDebugMode = false) - { - $this->apiKey = $apiKey; + public function __construct( + private readonly string $apiKey, + string $homeUrl, + private readonly string $flarumVersion, + private readonly string $extensionVersion, + bool $inDebugMode = false + ) { $this->apiUrl = "https://$apiKey.rest.akismet.com/1.1"; $this->params['blog'] = $homeUrl; - $this->flarumVersion = $flarumVersion; - $this->extensionVersion = $extensionVersion; - if ($inDebugMode) { $this->params['is_test'] = true; } @@ -73,7 +70,7 @@ class Akismet /** * @throws GuzzleException */ - public function submitSpam() + public function submitSpam(): void { $this->sendRequest('submit-spam'); } @@ -81,7 +78,7 @@ class Akismet /** * @throws GuzzleException */ - public function submitHam() + public function submitHam(): void { $this->sendRequest('submit-ham'); } @@ -90,7 +87,7 @@ class Akismet * Allows you to set additional parameter * This lets you use Akismet features not supported directly in this util. */ - public function withParam(string $key, $value): Akismet + public function withParam(string $key, mixed $value): Akismet { $new = clone $this; $new->params[$key] = $value; diff --git a/extensions/likes/src/Access/LikePostPolicy.php b/extensions/likes/src/Access/LikePostPolicy.php index e83e686eb..86e4b6e63 100644 --- a/extensions/likes/src/Access/LikePostPolicy.php +++ b/extensions/likes/src/Access/LikePostPolicy.php @@ -21,10 +21,12 @@ class LikePostPolicy extends AbstractPolicy ) { } - public function like(User $actor, Post $post) + public function like(User $actor, Post $post): ?string { if ($actor->id === $post->user_id && ! (bool) $this->settings->get('flarum-likes.like_own_post')) { return $this->deny(); } + + return null; } } diff --git a/extensions/lock/src/Access/DiscussionPolicy.php b/extensions/lock/src/Access/DiscussionPolicy.php index c11acff8d..6b98c2a95 100755 --- a/extensions/lock/src/Access/DiscussionPolicy.php +++ b/extensions/lock/src/Access/DiscussionPolicy.php @@ -15,10 +15,12 @@ use Flarum\User\User; class DiscussionPolicy extends AbstractPolicy { - public function reply(User $actor, Discussion $discussion) + public function reply(User $actor, Discussion $discussion): ?string { if ($discussion->is_locked && $actor->cannot('lock', $discussion)) { return $this->deny(); } + + return null; } } diff --git a/extensions/mentions/src/ConfigureMentions.php b/extensions/mentions/src/ConfigureMentions.php index de8ba797d..2670dbb2e 100644 --- a/extensions/mentions/src/ConfigureMentions.php +++ b/extensions/mentions/src/ConfigureMentions.php @@ -82,9 +82,9 @@ class ConfigureMentions /** * @param FormatterTag $tag * @param array{users: Collection} $mentions - * @return bool|void + * @return bool|null */ - public static function addUserId(FormatterTag $tag, array $mentions) + public static function addUserId(FormatterTag $tag, array $mentions): ?bool { $allow_username_format = (bool) resolve(SettingsRepositoryInterface::class)->get('flarum-mentions.allow_username_format'); @@ -102,6 +102,8 @@ class ConfigureMentions } $tag->invalidate(); + + return null; } private function configurePostMentions(Configurator $config): void @@ -141,9 +143,9 @@ class ConfigureMentions /** * @param FormatterTag $tag * @param array{posts: Collection} $mentions - * @return bool|void + * @return bool|null */ - public static function addPostId(FormatterTag $tag, array $mentions) + public static function addPostId(FormatterTag $tag, array $mentions): ?bool { $post = $mentions['posts']->where('id', $tag->getAttribute('id'))->first(); @@ -157,9 +159,11 @@ class ConfigureMentions return true; } + + return null; } - private function configureGroupMentions(Configurator $config) + private function configureGroupMentions(Configurator $config): void { $tagName = 'GROUPMENTION'; @@ -214,9 +218,9 @@ class ConfigureMentions * @param FormatterTag $tag * @param User $actor * @param array{groups: Collection} $mentions - * @return bool|void + * @return bool|null */ - public static function addGroupId(FormatterTag $tag, User $actor, array $mentions) + public static function addGroupId(FormatterTag $tag, User $actor, array $mentions): ?bool { $id = $tag->getAttribute('id'); @@ -236,9 +240,11 @@ class ConfigureMentions } $tag->invalidate(); + + return null; } - private function configureTagMentions(Configurator $config) + private function configureTagMentions(Configurator $config): void { $config->rendering->parameters['TAG_URL'] = $this->url->to('forum')->route('tag', ['slug' => '']); @@ -303,9 +309,9 @@ class ConfigureMentions /** * @param FormatterTag $tag * @param array{tags: Collection} $mentions - * @return true|void + * @return bool|null */ - public static function addTagId(FormatterTag $tag, array $mentions) + public static function addTagId(FormatterTag $tag, array $mentions): ?bool { /** @var Tag|null $model */ $model = $mentions['tags']->where('slug', $tag->getAttribute('slug'))->first(); @@ -316,6 +322,8 @@ class ConfigureMentions return true; } + + return null; } /** diff --git a/extensions/mentions/src/Formatter/UnparsePostMentions.php b/extensions/mentions/src/Formatter/UnparsePostMentions.php index 3c32dee0b..519c3f4a1 100644 --- a/extensions/mentions/src/Formatter/UnparsePostMentions.php +++ b/extensions/mentions/src/Formatter/UnparsePostMentions.php @@ -29,7 +29,7 @@ class UnparsePostMentions /** * Updates XML post mention tags before unparsing so that unparsing uses new display names. */ - protected function updatePostMentionTags($context, string $xml): string + protected function updatePostMentionTags(mixed $context, string $xml): string { $post = $context; diff --git a/extensions/nicknames/src/Access/UserPolicy.php b/extensions/nicknames/src/Access/UserPolicy.php index c7791beb2..1d827961f 100644 --- a/extensions/nicknames/src/Access/UserPolicy.php +++ b/extensions/nicknames/src/Access/UserPolicy.php @@ -20,7 +20,7 @@ class UserPolicy extends AbstractPolicy ) { } - public function editNickname(User $actor, User $user) + public function editNickname(User $actor, User $user): ?string { if ($actor->isGuest() && ! $user->exists && $this->settings->get('flarum-nicknames.set_on_registration')) { return $this->allow(); @@ -29,5 +29,7 @@ class UserPolicy extends AbstractPolicy } elseif ($actor->can('edit', $user)) { return $this->allow(); } + + return null; } } diff --git a/extensions/suspend/src/Access/UserPolicy.php b/extensions/suspend/src/Access/UserPolicy.php index 5b6299d97..25fd0ca6d 100644 --- a/extensions/suspend/src/Access/UserPolicy.php +++ b/extensions/suspend/src/Access/UserPolicy.php @@ -14,10 +14,12 @@ use Flarum\User\User; class UserPolicy extends AbstractPolicy { - public function suspend(User $actor, User $user) + public function suspend(User $actor, User $user): ?string { if ($user->isAdmin() || $user->id === $actor->id) { return $this->deny(); } + + return null; } } diff --git a/extensions/tags/src/Access/DiscussionPolicy.php b/extensions/tags/src/Access/DiscussionPolicy.php index a84897b77..3790782e9 100755 --- a/extensions/tags/src/Access/DiscussionPolicy.php +++ b/extensions/tags/src/Access/DiscussionPolicy.php @@ -22,7 +22,7 @@ class DiscussionPolicy extends AbstractPolicy ) { } - public function can(User $actor, string $ability, Discussion $discussion) + public function can(User $actor, string $ability, Discussion $discussion): ?string { // Wrap all discussion permission checks with some logic pertaining to // the discussion's tags. If the discussion has a tag that has been @@ -46,13 +46,15 @@ class DiscussionPolicy extends AbstractPolicy return $this->allow(); } } + + return null; } /** * This method checks, if the user is still allowed to edit the tags * based on the configuration item. */ - public function tag(User $actor, Discussion $discussion) + public function tag(User $actor, Discussion $discussion): ?string { if ($discussion->user_id == $actor->id && $actor->can('reply', $discussion)) { $allowEditTags = $this->settings->get('allow_tag_change'); @@ -65,5 +67,7 @@ class DiscussionPolicy extends AbstractPolicy return $this->allow(); } } + + return null; } } diff --git a/extensions/tags/src/Access/GlobalPolicy.php b/extensions/tags/src/Access/GlobalPolicy.php index 7218d1778..b3abfc01e 100644 --- a/extensions/tags/src/Access/GlobalPolicy.php +++ b/extensions/tags/src/Access/GlobalPolicy.php @@ -21,7 +21,7 @@ class GlobalPolicy extends AbstractPolicy ) { } - public function can(User $actor, string $ability) + public function can(User $actor, string $ability): ?string { static $enoughPrimary; static $enoughSecondary; @@ -67,5 +67,7 @@ class GlobalPolicy extends AbstractPolicy return $this->deny(); } } + + return null; } } diff --git a/extensions/tags/src/Access/TagPolicy.php b/extensions/tags/src/Access/TagPolicy.php index b8977b16b..2a9f89d74 100755 --- a/extensions/tags/src/Access/TagPolicy.php +++ b/extensions/tags/src/Access/TagPolicy.php @@ -15,7 +15,7 @@ use Flarum\User\User; class TagPolicy extends AbstractPolicy { - public function can(User $actor, string $ability, Tag $tag) + public function can(User $actor, string $ability, Tag $tag): string|bool|null { if ($tag->parent_id !== null && ! $actor->can($ability, $tag->parent)) { return $this->deny(); @@ -26,6 +26,8 @@ class TagPolicy extends AbstractPolicy return $actor->hasPermission("tag$id.$ability"); } + + return null; } public function addToDiscussion(User $actor, Tag $tag): bool diff --git a/extensions/tags/src/Content/Tag.php b/extensions/tags/src/Content/Tag.php index 33b1855a6..01804fc90 100644 --- a/extensions/tags/src/Content/Tag.php +++ b/extensions/tags/src/Content/Tag.php @@ -89,12 +89,12 @@ class Tag /** * Get the result of an API request to list discussions. */ - protected function getApiDocument(Request $request, array $params) + protected function getApiDocument(Request $request, array $params): object { return json_decode($this->api->withParentRequest($request)->withQueryParams($params)->get('/discussions')->getBody()); } - protected function getTagsDocument(Request $request, string $slug) + protected function getTagsDocument(Request $request, string $slug): object { return json_decode($this->api->withParentRequest($request)->withQueryParams([ 'include' => 'children,children.parent,parent,parent.children.parent,state' diff --git a/extensions/tags/src/Content/Tags.php b/extensions/tags/src/Content/Tags.php index 993f21b7b..b17c5da0b 100644 --- a/extensions/tags/src/Content/Tags.php +++ b/extensions/tags/src/Content/Tags.php @@ -34,14 +34,14 @@ class Tags public function __invoke(Document $document, Request $request): Document { $apiDocument = $this->getTagsDocument($request); - $tags = collect(Arr::get($apiDocument, 'data', [])); + $tags = collect((array) Arr::get($apiDocument, 'data', [])); $childTags = $tags->where('attributes.isChild', true); $primaryTags = $tags->where('attributes.isChild', false)->where('attributes.position', '!==', null)->sortBy('attributes.position'); $secondaryTags = $tags->where('attributes.isChild', false)->where('attributes.position', '===', null)->sortBy('attributes.name'); $children = $primaryTags->mapWithKeys(function ($tag) use ($childTags) { - $childIds = collect(Arr::get($tag, 'relationships.children.data'))->pluck('id'); + $childIds = collect((array) Arr::get($tag, 'relationships.children.data'))->pluck('id'); return [$tag['id'] => $childTags->whereIn('id', $childIds)->sortBy('position')]; }); @@ -56,7 +56,7 @@ class Tags return $document; } - protected function getTagsDocument(Request $request) + protected function getTagsDocument(Request $request): array { return json_decode($this->api->withParentRequest($request)->withQueryParams([ 'include' => 'children,lastPostedDiscussion,parent' diff --git a/extensions/tags/src/Query/TagFilterGambit.php b/extensions/tags/src/Query/TagFilterGambit.php index afa7a46a4..23d2218fb 100644 --- a/extensions/tags/src/Query/TagFilterGambit.php +++ b/extensions/tags/src/Query/TagFilterGambit.php @@ -49,7 +49,7 @@ class TagFilterGambit extends AbstractRegexGambit implements FilterInterface $this->constrain($filterState->getQuery(), $filterValue, $negate, $filterState->getActor()); } - protected function constrain(Builder $query, string|array $rawSlugs, $negate, User $actor): void + protected function constrain(Builder $query, string|array $rawSlugs, bool $negate, User $actor): void { $slugs = $this->asStringArray($rawSlugs); diff --git a/framework/core/src/Api/Controller/CreatePostController.php b/framework/core/src/Api/Controller/CreatePostController.php index 93e3e8e79..717b5ab4d 100644 --- a/framework/core/src/Api/Controller/CreatePostController.php +++ b/framework/core/src/Api/Controller/CreatePostController.php @@ -39,9 +39,10 @@ class CreatePostController extends AbstractCreateController { $actor = RequestUtil::getActor($request); $data = Arr::get($request->getParsedBody(), 'data', []); - $discussionId = Arr::get($data, 'relationships.discussion.data.id'); + $discussionId = (int) Arr::get($data, 'relationships.discussion.data.id'); $ipAddress = $request->getAttribute('ipAddress'); + /** @var CommentPost $post */ $post = $this->bus->dispatch( new PostReply($discussionId, $actor, $data, $ipAddress) ); @@ -56,7 +57,7 @@ class CreatePostController extends AbstractCreateController } $discussion = $post->discussion; - $discussion->posts = $discussion->posts()->whereVisibleTo($actor)->orderBy('created_at')->pluck('id'); + $discussion->setRelation('posts', $discussion->posts()->whereVisibleTo($actor)->orderBy('created_at')->pluck('id')); $this->loadRelations($post->newCollection([$post]), $this->extractInclude($request), $request); diff --git a/framework/core/src/Api/Controller/UpdateDiscussionController.php b/framework/core/src/Api/Controller/UpdateDiscussionController.php index 7e6380217..24516159c 100644 --- a/framework/core/src/Api/Controller/UpdateDiscussionController.php +++ b/framework/core/src/Api/Controller/UpdateDiscussionController.php @@ -33,7 +33,7 @@ class UpdateDiscussionController extends AbstractShowController protected function data(ServerRequestInterface $request, Document $document): Discussion { $actor = RequestUtil::getActor($request); - $discussionId = Arr::get($request->getQueryParams(), 'id'); + $discussionId = (int) Arr::get($request->getQueryParams(), 'id'); $data = Arr::get($request->getParsedBody(), 'data', []); /** @var Discussion $discussion */ diff --git a/framework/core/src/Api/Middleware/ThrottleApi.php b/framework/core/src/Api/Middleware/ThrottleApi.php index f85b345ab..317695678 100644 --- a/framework/core/src/Api/Middleware/ThrottleApi.php +++ b/framework/core/src/Api/Middleware/ThrottleApi.php @@ -17,11 +17,9 @@ use Psr\Http\Server\RequestHandlerInterface as Handler; class ThrottleApi implements Middleware { - protected $throttlers; - - public function __construct(array $throttlers) - { - $this->throttlers = $throttlers; + public function __construct( + protected array $throttlers + ) { } public function process(Request $request, Handler $handler): Response @@ -33,9 +31,6 @@ class ThrottleApi implements Middleware return $handler->handle($request); } - /** - * @return bool - */ public function throttle(Request $request): bool { $throttle = false; diff --git a/framework/core/src/Api/Serializer/BasicDiscussionSerializer.php b/framework/core/src/Api/Serializer/BasicDiscussionSerializer.php index c155e448b..5f18cbb73 100644 --- a/framework/core/src/Api/Serializer/BasicDiscussionSerializer.php +++ b/framework/core/src/Api/Serializer/BasicDiscussionSerializer.php @@ -40,37 +40,37 @@ class BasicDiscussionSerializer extends AbstractSerializer ]; } - protected function user($discussion): ?Relationship + protected function user(Discussion $discussion): ?Relationship { return $this->hasOne($discussion, BasicUserSerializer::class); } - protected function firstPost($discussion): ?Relationship + protected function firstPost(Discussion $discussion): ?Relationship { return $this->hasOne($discussion, BasicPostSerializer::class); } - protected function lastPostedUser($discussion): ?Relationship + protected function lastPostedUser(Discussion $discussion): ?Relationship { return $this->hasOne($discussion, BasicUserSerializer::class); } - protected function lastPost($discussion): ?Relationship + protected function lastPost(Discussion $discussion): ?Relationship { return $this->hasOne($discussion, BasicPostSerializer::class); } - protected function posts($discussion): ?Relationship + protected function posts(Discussion $discussion): ?Relationship { return $this->hasMany($discussion, PostSerializer::class); } - protected function mostRelevantPost($discussion): ?Relationship + protected function mostRelevantPost(Discussion $discussion): ?Relationship { return $this->hasOne($discussion, PostSerializer::class); } - protected function hiddenUser($discussion): ?Relationship + protected function hiddenUser(Discussion $discussion): ?Relationship { return $this->hasOne($discussion, BasicUserSerializer::class); } diff --git a/framework/core/src/Api/Serializer/BasicUserSerializer.php b/framework/core/src/Api/Serializer/BasicUserSerializer.php index 3f14efa13..4f2f55384 100644 --- a/framework/core/src/Api/Serializer/BasicUserSerializer.php +++ b/framework/core/src/Api/Serializer/BasicUserSerializer.php @@ -42,7 +42,7 @@ class BasicUserSerializer extends AbstractSerializer ]; } - protected function groups($user): Relationship + protected function groups(User $user): Relationship { if ($this->getActor()->can('viewHiddenGroups')) { return $this->hasMany($user, GroupSerializer::class); diff --git a/framework/core/src/Api/Serializer/ForumSerializer.php b/framework/core/src/Api/Serializer/ForumSerializer.php index afe0a744c..f5a9bfdb7 100644 --- a/framework/core/src/Api/Serializer/ForumSerializer.php +++ b/framework/core/src/Api/Serializer/ForumSerializer.php @@ -100,7 +100,7 @@ class ForumSerializer extends AbstractSerializer return $attributes; } - protected function groups($model): ?Relationship + protected function groups(array $model): ?Relationship { return $this->hasMany($model, GroupSerializer::class); } @@ -119,12 +119,12 @@ class ForumSerializer extends AbstractSerializer return $faviconPath ? $this->getAssetUrl($faviconPath) : null; } - public function getAssetUrl($assetPath): string + public function getAssetUrl(string $assetPath): string { return $this->assetsFilesystem->url($assetPath); } - protected function actor($model): ?Relationship + protected function actor(array $model): ?Relationship { return $this->hasOne($model, CurrentUserSerializer::class); } diff --git a/framework/core/src/Console/Schedule.php b/framework/core/src/Console/Schedule.php index 37d105e29..ab2be9c97 100644 --- a/framework/core/src/Console/Schedule.php +++ b/framework/core/src/Console/Schedule.php @@ -11,6 +11,7 @@ namespace Flarum\Console; use Flarum\Foundation\Config; use Illuminate\Console\Scheduling\Schedule as LaravelSchedule; +use Illuminate\Contracts\Container\Container; use Illuminate\Support\Collection; class Schedule extends LaravelSchedule @@ -21,7 +22,7 @@ class Schedule extends LaravelSchedule return (new Collection($this->events))->filter->isDue(new class($app) { protected Config $config; - public function __construct($app) + public function __construct(Container $app) { $this->config = $app->make(Config::class); } diff --git a/framework/core/src/Database/Migration.php b/framework/core/src/Database/Migration.php index bef6760e8..c926378cf 100644 --- a/framework/core/src/Database/Migration.php +++ b/framework/core/src/Database/Migration.php @@ -21,7 +21,7 @@ use Illuminate\Database\Schema\Builder; */ abstract class Migration { - public static function createTable($name, callable $definition): array + public static function createTable(string $name, callable $definition): array { return [ 'up' => function (Builder $schema) use ($name, $definition) { @@ -35,7 +35,7 @@ abstract class Migration ]; } - public static function createTableIfNotExists($name, callable $definition): array + public static function createTableIfNotExists(string $name, callable $definition): array { return [ 'up' => function (Builder $schema) use ($name, $definition) { @@ -51,7 +51,7 @@ abstract class Migration ]; } - public static function renameTable($from, $to): array + public static function renameTable(string $from, string $to): array { return [ 'up' => function (Builder $schema) use ($from, $to) { @@ -63,7 +63,7 @@ abstract class Migration ]; } - public static function addColumns($tableName, array $columnDefinitions): array + public static function addColumns(string $tableName, array $columnDefinitions): array { return [ 'up' => function (Builder $schema) use ($tableName, $columnDefinitions) { @@ -82,7 +82,7 @@ abstract class Migration ]; } - public static function dropColumns($tableName, array $columnDefinitions): array + public static function dropColumns(string $tableName, array $columnDefinitions): array { $inverse = static::addColumns($tableName, $columnDefinitions); @@ -92,12 +92,12 @@ abstract class Migration ]; } - public static function renameColumn($tableName, $from, $to): array + public static function renameColumn(string $tableName, string $from, string $to): array { return static::renameColumns($tableName, [$from => $to]); } - public static function renameColumns($tableName, array $columnNames): array + public static function renameColumns(string $tableName, array $columnNames): array { return [ 'up' => function (Builder $schema) use ($tableName, $columnNames) { diff --git a/framework/core/src/Database/ScopeVisibilityTrait.php b/framework/core/src/Database/ScopeVisibilityTrait.php index 1cbfc3346..a3e3f333b 100644 --- a/framework/core/src/Database/ScopeVisibilityTrait.php +++ b/framework/core/src/Database/ScopeVisibilityTrait.php @@ -22,7 +22,7 @@ trait ScopeVisibilityTrait */ protected static array $visibilityScopers = []; - public static function registerVisibilityScoper($scoper, ?string $ability = null): void + public static function registerVisibilityScoper(callable $scoper, ?string $ability = null): void { $model = static::class; diff --git a/framework/core/src/Discussion/Access/DiscussionPolicy.php b/framework/core/src/Discussion/Access/DiscussionPolicy.php index e1dfb50e3..3e4099b07 100644 --- a/framework/core/src/Discussion/Access/DiscussionPolicy.php +++ b/framework/core/src/Discussion/Access/DiscussionPolicy.php @@ -21,14 +21,16 @@ class DiscussionPolicy extends AbstractPolicy ) { } - public function can(User $actor, string $ability) + public function can(User $actor, string $ability): ?string { if ($actor->hasPermission('discussion.'.$ability)) { return $this->allow(); } + + return null; } - public function rename(User $actor, Discussion $discussion) + public function rename(User $actor, Discussion $discussion): ?string { if ($discussion->user_id == $actor->id && $actor->can('reply', $discussion)) { $allowRenaming = $this->settings->get('allow_renaming'); @@ -39,9 +41,11 @@ class DiscussionPolicy extends AbstractPolicy return $this->allow(); } } + + return null; } - public function hide(User $actor, Discussion $discussion) + public function hide(User $actor, Discussion $discussion): ?string { if ($discussion->user_id == $actor->id && $discussion->participant_count <= 1 @@ -50,5 +54,7 @@ class DiscussionPolicy extends AbstractPolicy ) { return $this->allow(); } + + return null; } } diff --git a/framework/core/src/Discussion/Command/EditDiscussion.php b/framework/core/src/Discussion/Command/EditDiscussion.php index b3dfabc7a..e49a1bd51 100644 --- a/framework/core/src/Discussion/Command/EditDiscussion.php +++ b/framework/core/src/Discussion/Command/EditDiscussion.php @@ -14,7 +14,7 @@ use Flarum\User\User; class EditDiscussion { public function __construct( - public $discussionId, + public int $discussionId, public User $actor, public array $data ) { diff --git a/framework/core/src/Discussion/Command/ReadDiscussion.php b/framework/core/src/Discussion/Command/ReadDiscussion.php index 9963bdb52..a8220e250 100644 --- a/framework/core/src/Discussion/Command/ReadDiscussion.php +++ b/framework/core/src/Discussion/Command/ReadDiscussion.php @@ -14,11 +14,11 @@ use Flarum\User\User; class ReadDiscussion { public function __construct( - public $discussionId, + public int $discussionId, /** The user to mark the discussion as read for */ public User $actor, /** The number of the post to mark as read */ - public $lastReadPostNumber + public int $lastReadPostNumber ) { } } diff --git a/framework/core/src/Discussion/Query/AuthorFilterGambit.php b/framework/core/src/Discussion/Query/AuthorFilterGambit.php index 7d804be75..16919ff2a 100644 --- a/framework/core/src/Discussion/Query/AuthorFilterGambit.php +++ b/framework/core/src/Discussion/Query/AuthorFilterGambit.php @@ -46,7 +46,7 @@ class AuthorFilterGambit extends AbstractRegexGambit implements FilterInterface $this->constrain($filterState->getQuery(), $filterValue, $negate); } - protected function constrain(Builder $query, string|array $rawUsernames, $negate) + protected function constrain(Builder $query, string|array $rawUsernames, bool $negate): void { $usernames = $this->asStringArray($rawUsernames); diff --git a/framework/core/src/Discussion/Query/CreatedFilterGambit.php b/framework/core/src/Discussion/Query/CreatedFilterGambit.php index ad4d36d3a..7d5a98a6b 100644 --- a/framework/core/src/Discussion/Query/CreatedFilterGambit.php +++ b/framework/core/src/Discussion/Query/CreatedFilterGambit.php @@ -45,7 +45,7 @@ class CreatedFilterGambit extends AbstractRegexGambit implements FilterInterface $this->constrain($filterState->getQuery(), Arr::get($matches, 1), Arr::get($matches, 3), $negate); } - public function constrain(Builder $query, ?string $firstDate, ?string $secondDate, $negate) + public function constrain(Builder $query, ?string $firstDate, ?string $secondDate, bool $negate): void { // If we've just been provided with a single YYYY-MM-DD date, then find // discussions that were started on that exact date. But if we've been diff --git a/framework/core/src/Discussion/Query/HiddenFilterGambit.php b/framework/core/src/Discussion/Query/HiddenFilterGambit.php index a5e88ebb7..d0bebdf95 100644 --- a/framework/core/src/Discussion/Query/HiddenFilterGambit.php +++ b/framework/core/src/Discussion/Query/HiddenFilterGambit.php @@ -37,7 +37,7 @@ class HiddenFilterGambit extends AbstractRegexGambit implements FilterInterface $this->constrain($filterState->getQuery(), $negate); } - protected function constrain(Builder $query, bool $negate) + protected function constrain(Builder $query, bool $negate): void { $query->where(function ($query) use ($negate) { if ($negate) { diff --git a/framework/core/src/Discussion/Query/UnreadFilterGambit.php b/framework/core/src/Discussion/Query/UnreadFilterGambit.php index 2a25a0ea5..5709681e3 100644 --- a/framework/core/src/Discussion/Query/UnreadFilterGambit.php +++ b/framework/core/src/Discussion/Query/UnreadFilterGambit.php @@ -52,7 +52,7 @@ class UnreadFilterGambit extends AbstractRegexGambit implements FilterInterface $this->constrain($filterState->getQuery(), $filterState->getActor(), $negate); } - protected function constrain(Builder $query, User $actor, bool $negate) + protected function constrain(Builder $query, User $actor, bool $negate): void { if ($actor->exists) { $readIds = $this->discussions->getReadIdsQuery($actor); diff --git a/framework/core/src/Extend/Console.php b/framework/core/src/Extend/Console.php index 40492c2cc..741890465 100644 --- a/framework/core/src/Extend/Console.php +++ b/framework/core/src/Extend/Console.php @@ -43,7 +43,7 @@ class Console implements ExtenderInterface * The callback should apply relevant methods to $event, and does not need to return anything. * * @see https://laravel.com/api/8.x/Illuminate/Console/Scheduling/Event.html - * @see https://laravel.com/docs/8.x/scheduling#schedule-frequency-options + * @see https://laravel.com/docs/10.x/scheduling#schedule-frequency-options * for more information on available methods and what they do. * * @param array $args An array of args to call the command with. diff --git a/framework/core/src/Extend/Event.php b/framework/core/src/Extend/Event.php index 07b8b6eac..a7092081e 100644 --- a/framework/core/src/Extend/Event.php +++ b/framework/core/src/Extend/Event.php @@ -44,7 +44,7 @@ class Event implements ExtenderInterface * Event subscribers are classes that may subscribe to multiple events from within the subscriber class itself, * allowing you to define several event handlers within a single class. * - * @see https://laravel.com/docs/8.x/events#writing-event-subscribers + * @see https://laravel.com/docs/10.x/events#writing-event-subscribers * * @param string $subscriber: The ::class attribute of the subscriber class. * @return self diff --git a/framework/core/src/Extend/Filesystem.php b/framework/core/src/Extend/Filesystem.php index fa49162e5..f1bd90fc6 100644 --- a/framework/core/src/Extend/Filesystem.php +++ b/framework/core/src/Extend/Filesystem.php @@ -51,7 +51,7 @@ class Filesystem implements ExtenderInterface * }); * ``` * - * @see https://laravel.com/docs/8.x/filesystem#configuration + * @see https://laravel.com/docs/10.x/filesystem#configuration * * @return self */ diff --git a/framework/core/src/Extend/LanguagePack.php b/framework/core/src/Extend/LanguagePack.php index eeafd126a..18bdc1044 100644 --- a/framework/core/src/Extend/LanguagePack.php +++ b/framework/core/src/Extend/LanguagePack.php @@ -61,7 +61,7 @@ class LanguagePack implements ExtenderInterface, LifecycleInterface ); } - private function registerLocale(Container $container, LocaleManager $locales, Extension $extension, $locale, $title): void + private function registerLocale(Container $container, LocaleManager $locales, Extension $extension, string $locale, string $title): void { $locales->addLocale($locale, $title); diff --git a/framework/core/src/Extend/Model.php b/framework/core/src/Extend/Model.php index e1f4229f0..363973be5 100644 --- a/framework/core/src/Extend/Model.php +++ b/framework/core/src/Extend/Model.php @@ -48,7 +48,7 @@ class Model implements ExtenderInterface * Add a custom attribute type cast. Should not be applied to non-extension attributes. * * @param string $attribute: The new attribute name. - * @param string $cast: The cast type. See https://laravel.com/docs/8.x/eloquent-mutators#attribute-casting + * @param string $cast: The cast type. See https://laravel.com/docs/10.x/eloquent-mutators#attribute-casting * @return self */ public function cast(string $attribute, string $cast): self diff --git a/framework/core/src/Extend/ModelPrivate.php b/framework/core/src/Extend/ModelPrivate.php index 3eb378e20..5b44b0f29 100644 --- a/framework/core/src/Extend/ModelPrivate.php +++ b/framework/core/src/Extend/ModelPrivate.php @@ -34,7 +34,7 @@ use Illuminate\Contracts\Container\Container; */ class ModelPrivate implements ExtenderInterface { - private $checkers = []; + private array $checkers = []; /** * @param class-string $modelClass: The ::class attribute of the model you are applying private checkers to. diff --git a/framework/core/src/Extend/Routes.php b/framework/core/src/Extend/Routes.php index a5b12449b..fd1b5950c 100644 --- a/framework/core/src/Extend/Routes.php +++ b/framework/core/src/Extend/Routes.php @@ -148,7 +148,7 @@ class Routes implements ExtenderInterface return $this->route('DELETE', $path, $name, $handler); } - private function route(string $httpMethod, string $path, string $name, $handler): self + private function route(string $httpMethod, string $path, string $name, callable|string $handler): self { $this->routes[] = [ 'method' => $httpMethod, diff --git a/framework/core/src/Extension/Exception/ExtensionBootError.php b/framework/core/src/Extension/Exception/ExtensionBootError.php index c5c126d55..ee7a9657d 100644 --- a/framework/core/src/Extension/Exception/ExtensionBootError.php +++ b/framework/core/src/Extension/Exception/ExtensionBootError.php @@ -17,7 +17,7 @@ class ExtensionBootError extends Exception { public function __construct( public Extension $extension, - public $extender, + public object $extender, Throwable $previous = null ) { $extenderClass = get_class($extender); diff --git a/framework/core/src/Extension/Extension.php b/framework/core/src/Extension/Extension.php index e3e7dc464..786c61bbf 100644 --- a/framework/core/src/Extension/Extension.php +++ b/framework/core/src/Extension/Extension.php @@ -84,7 +84,7 @@ class Extension implements Arrayable $this->assignId(); } - protected static function nameToId($name): string + protected static function nameToId(string $name): string { [$vendor, $package] = explode('/', $name); $package = str_replace(['flarum-ext-', 'flarum-'], '', $package); @@ -114,12 +114,12 @@ class Extension implements Arrayable } } - public function __get($name) + public function __get(string $name): mixed { return $this->composerJsonAttribute(Str::snake($name, '-')); } - public function __isset($name) + public function __isset(string $name): bool { return isset($this->{$name}) || $this->composerJsonAttribute(Str::snake($name, '-')); } @@ -127,12 +127,9 @@ class Extension implements Arrayable /** * Dot notation getter for composer.json attributes. * - * @see https://laravel.com/docs/8.x/helpers#arrays - * - * @param $name - * @return mixed + * @see https://laravel.com/docs/10.x/helpers#arrays */ - public function composerJsonAttribute($name): mixed + public function composerJsonAttribute(string $name): mixed { return Arr::get($this->composerJson, $name); } @@ -433,7 +430,7 @@ class Extension implements Arrayable /** * @internal */ - public function migrate(Migrator $migrator, $direction = 'up'): ?int + public function migrate(Migrator $migrator, string $direction = 'up'): ?int { if (! $this->hasMigrations()) { return null; diff --git a/framework/core/src/Filter/ValidateFilterTrait.php b/framework/core/src/Filter/ValidateFilterTrait.php index ae8ac42c2..7c496105e 100644 --- a/framework/core/src/Filter/ValidateFilterTrait.php +++ b/framework/core/src/Filter/ValidateFilterTrait.php @@ -18,7 +18,7 @@ trait ValidateFilterTrait * @throws FlarumValidationException * @return array|array */ - protected function asStringArray($filterValue, bool $multidimensional = false): array + protected function asStringArray(string|array $filterValue, bool $multidimensional = false): array { if (is_array($filterValue)) { $value = array_map(function ($subValue) use ($multidimensional) { @@ -40,7 +40,7 @@ trait ValidateFilterTrait /** * @throws FlarumValidationException */ - protected function asString($filterValue): string + protected function asString(string|array $filterValue): string { if (is_array($filterValue)) { $this->throwValidationException('core.api.invalid_filter_type.must_not_be_array_message'); @@ -52,7 +52,7 @@ trait ValidateFilterTrait /** * @throws FlarumValidationException */ - protected function asInt($filterValue): int + protected function asInt(string|array $filterValue): int { if (! is_numeric($filterValue)) { $this->throwValidationException('core.api.invalid_filter_type.must_be_numeric_message'); @@ -65,7 +65,7 @@ trait ValidateFilterTrait * @throws FlarumValidationException * @return array */ - protected function asIntArray($filterValue): array + protected function asIntArray(string|array $filterValue): array { return array_map(function ($value) { return $this->asInt($value); @@ -75,7 +75,7 @@ trait ValidateFilterTrait /** * @throws FlarumValidationException */ - protected function asBool($filterValue): bool + protected function asBool(string|array $filterValue): bool { return $this->asString($filterValue) === '1'; } diff --git a/framework/core/src/Formatter/Formatter.php b/framework/core/src/Formatter/Formatter.php index af2ed15b4..4f9e0ed12 100644 --- a/framework/core/src/Formatter/Formatter.php +++ b/framework/core/src/Formatter/Formatter.php @@ -94,7 +94,7 @@ class Formatter return $renderer->render($xml); } - public function unparse(string $xml, $context = null): string + public function unparse(string $xml, mixed $context = null): string { foreach ($this->unparsingCallbacks as $callback) { $xml = $callback($context, $xml); diff --git a/framework/core/src/Forum/Auth/Registration.php b/framework/core/src/Forum/Auth/Registration.php index 2d24d3aa7..062367c09 100644 --- a/framework/core/src/Forum/Auth/Registration.php +++ b/framework/core/src/Forum/Auth/Registration.php @@ -66,7 +66,7 @@ class Registration return $this->suggest('email', $email); } - public function setPayload($payload): self + public function setPayload(mixed $payload): self { $this->payload = $payload; diff --git a/framework/core/src/Forum/Content/Discussion.php b/framework/core/src/Forum/Content/Discussion.php index 40533edec..5c49cadbf 100644 --- a/framework/core/src/Forum/Content/Discussion.php +++ b/framework/core/src/Forum/Content/Discussion.php @@ -92,7 +92,7 @@ class Discussion * * @throws RouteNotFoundException */ - protected function getApiDocument(Request $request, string $id, array $params) + protected function getApiDocument(Request $request, string $id, array $params): object { $params['bySlug'] = true; $response = $this->api diff --git a/framework/core/src/Forum/Content/User.php b/framework/core/src/Forum/Content/User.php index 08ebffde7..cbd46140a 100644 --- a/framework/core/src/Forum/Content/User.php +++ b/framework/core/src/Forum/Content/User.php @@ -44,7 +44,7 @@ class User * * @throws ModelNotFoundException */ - protected function getApiDocument(Request $request, string $username) + protected function getApiDocument(Request $request, string $username): object { $response = $this->api->withParentRequest($request)->withQueryParams(['bySlug' => true])->get("/users/$username"); $statusCode = $response->getStatusCode(); diff --git a/framework/core/src/Foundation/AbstractValidator.php b/framework/core/src/Foundation/AbstractValidator.php index fc04a263c..84470f6c1 100644 --- a/framework/core/src/Foundation/AbstractValidator.php +++ b/framework/core/src/Foundation/AbstractValidator.php @@ -33,7 +33,7 @@ abstract class AbstractValidator ) { } - public function addConfiguration($callable): void + public function addConfiguration(callable $callable): void { $this->configuration[] = $callable; } diff --git a/framework/core/src/Foundation/Config.php b/framework/core/src/Foundation/Config.php index ec20e4cfd..c81679394 100644 --- a/framework/core/src/Foundation/Config.php +++ b/framework/core/src/Foundation/Config.php @@ -39,7 +39,7 @@ class Config implements ArrayAccess return $this->data['offline'] ?? false; } - private function requireKeys(...$keys): void + private function requireKeys(mixed ...$keys): void { foreach ($keys as $key) { if (! array_key_exists($key, $this->data)) { diff --git a/framework/core/src/Foundation/Container.php b/framework/core/src/Foundation/Container.php index 20998c8cf..04ad0be5e 100644 --- a/framework/core/src/Foundation/Container.php +++ b/framework/core/src/Foundation/Container.php @@ -20,7 +20,7 @@ class Container extends LaravelContainer * * @TODO: Implement the Application contract and merge the container into it. */ - public function __call(string $name, array $arguments) + public function __call(string $name, array $arguments): mixed { return $this->get('flarum')->$name(...$arguments); } diff --git a/framework/core/src/Foundation/DispatchEventsTrait.php b/framework/core/src/Foundation/DispatchEventsTrait.php index 46917fdfd..5c40079e4 100644 --- a/framework/core/src/Foundation/DispatchEventsTrait.php +++ b/framework/core/src/Foundation/DispatchEventsTrait.php @@ -16,8 +16,14 @@ trait DispatchEventsTrait /** * Dispatch all events for an entity. */ - public function dispatchEventsFor($entity, User $actor = null): void + public function dispatchEventsFor(mixed $entity, User $actor = null): void { + if (! method_exists($entity, 'releaseEvents')) { + throw new \InvalidArgumentException( + 'The entity must use the EventGeneratorTrait trait in order to dispatch events.' + ); + } + foreach ($entity->releaseEvents() as $event) { $event->actor = $actor; diff --git a/framework/core/src/Foundation/ErrorHandling/ExceptionHandler/ValidationExceptionHandler.php b/framework/core/src/Foundation/ErrorHandling/ExceptionHandler/ValidationExceptionHandler.php index 779ca7c7b..cdc8fee06 100644 --- a/framework/core/src/Foundation/ErrorHandling/ExceptionHandler/ValidationExceptionHandler.php +++ b/framework/core/src/Foundation/ErrorHandling/ExceptionHandler/ValidationExceptionHandler.php @@ -26,7 +26,7 @@ class ValidationExceptionHandler )); } - private function buildDetails(array $messages, $pointer): array + private function buildDetails(array $messages, string $pointer): array { return array_map(function ($path, $detail) use ($pointer) { return [ diff --git a/framework/core/src/Foundation/EventGeneratorTrait.php b/framework/core/src/Foundation/EventGeneratorTrait.php index 19cdcb873..4eb1ade86 100644 --- a/framework/core/src/Foundation/EventGeneratorTrait.php +++ b/framework/core/src/Foundation/EventGeneratorTrait.php @@ -13,10 +13,7 @@ trait EventGeneratorTrait { protected array $pendingEvents = []; - /** - * Raise a new event. - */ - public function raise($event): void + public function raise(object $event): void { $this->pendingEvents[] = $event; } diff --git a/framework/core/src/Foundation/InstalledApp.php b/framework/core/src/Foundation/InstalledApp.php index 7f04673ad..c794753d6 100644 --- a/framework/core/src/Foundation/InstalledApp.php +++ b/framework/core/src/Foundation/InstalledApp.php @@ -83,7 +83,7 @@ class InstalledApp implements AppInterface return $this->config->url()->getPath() ?: '/'; } - protected function subPath($pathName): string + protected function subPath(string $pathName): string { return '/'.($this->config['paths'][$pathName] ?? $pathName); } diff --git a/framework/core/src/Foundation/Paths.php b/framework/core/src/Foundation/Paths.php index c40198397..59fdcaaca 100644 --- a/framework/core/src/Foundation/Paths.php +++ b/framework/core/src/Foundation/Paths.php @@ -37,7 +37,7 @@ class Paths $this->paths['vendor'] = $this->vendor ?? $this->base.'/vendor'; } - public function __get($name): ?string + public function __get(string $name): ?string { return $this->paths[$name] ?? null; } diff --git a/framework/core/src/Foundation/Site.php b/framework/core/src/Foundation/Site.php index c127587eb..3eca6db0e 100644 --- a/framework/core/src/Foundation/Site.php +++ b/framework/core/src/Foundation/Site.php @@ -34,12 +34,12 @@ class Site )->extendWith(static::loadExtenders($paths->base)); } - protected static function hasConfigFile($basePath): bool + protected static function hasConfigFile(string $basePath): bool { return file_exists("$basePath/config.php"); } - protected static function loadConfig($basePath): Config + protected static function loadConfig(string $basePath): Config { $config = include "$basePath/config.php"; @@ -50,7 +50,7 @@ class Site return new Config($config); } - protected static function loadExtenders($basePath): array + protected static function loadExtenders(string $basePath): array { $extenderFile = "$basePath/extend.php"; diff --git a/framework/core/src/Frontend/Assets.php b/framework/core/src/Frontend/Assets.php index 9a6abf6b3..63415a919 100644 --- a/framework/core/src/Frontend/Assets.php +++ b/framework/core/src/Frontend/Assets.php @@ -44,35 +44,35 @@ class Assets ) { } - public function js($sources): static + public function js(callable $callback): static { - $this->addSources('js', $sources); + $this->addSources('js', $callback); return $this; } - public function css($callback): static + public function css(callable $callback): static { $this->addSources('css', $callback); return $this; } - public function localeJs($callback): static + public function localeJs(callable $callback): static { $this->addSources('localeJs', $callback); return $this; } - public function localeCss($callback): static + public function localeCss(callable $callback): static { $this->addSources('localeCss', $callback); return $this; } - private function addSources($type, $callback): void + private function addSources(string $type, callable $callback): void { $this->sources[$type][] = $callback; } @@ -122,7 +122,7 @@ class Assets return $compiler; } - protected function makeJsCompiler(string $filename) + protected function makeJsCompiler(string $filename): JsCompiler { return resolve(JsCompiler::class, [ 'assetsDir' => $this->assetsDir, @@ -163,7 +163,7 @@ class Assets return $this->name; } - public function setName(string $name) + public function setName(string $name): void { $this->name = $name; } @@ -173,7 +173,7 @@ class Assets return $this->assetsDir; } - public function setAssetsDir(Cloud $assetsDir) + public function setAssetsDir(Cloud $assetsDir): void { $this->assetsDir = $assetsDir; } @@ -183,7 +183,7 @@ class Assets return $this->cacheDir; } - public function setCacheDir(?string $cacheDir) + public function setCacheDir(?string $cacheDir): void { $this->cacheDir = $cacheDir; } @@ -193,17 +193,17 @@ class Assets return $this->lessImportDirs; } - public function setLessImportDirs(array $lessImportDirs) + public function setLessImportDirs(array $lessImportDirs): void { $this->lessImportDirs = $lessImportDirs; } - public function addLessImportOverrides(array $lessImportOverrides) + public function addLessImportOverrides(array $lessImportOverrides): void { $this->lessImportOverrides = array_merge($this->lessImportOverrides, $lessImportOverrides); } - public function addFileSourceOverrides(array $fileSourceOverrides) + public function addFileSourceOverrides(array $fileSourceOverrides): void { $this->fileSourceOverrides = array_merge($this->fileSourceOverrides, $fileSourceOverrides); } diff --git a/framework/core/src/Frontend/Compiler/VersionerInterface.php b/framework/core/src/Frontend/Compiler/VersionerInterface.php index ad5dae42e..13cd5324f 100644 --- a/framework/core/src/Frontend/Compiler/VersionerInterface.php +++ b/framework/core/src/Frontend/Compiler/VersionerInterface.php @@ -11,7 +11,7 @@ namespace Flarum\Frontend\Compiler; interface VersionerInterface { - public function putRevision(string $file, ?string $revision); + public function putRevision(string $file, ?string $revision): void; public function getRevision(string $file): ?string; } diff --git a/framework/core/src/Frontend/FrontendServiceProvider.php b/framework/core/src/Frontend/FrontendServiceProvider.php index 4f51d3441..4b3b01588 100644 --- a/framework/core/src/Frontend/FrontendServiceProvider.php +++ b/framework/core/src/Frontend/FrontendServiceProvider.php @@ -40,8 +40,8 @@ class FrontendServiceProvider extends AbstractServiceProvider $paths->vendor.'/components/font-awesome/less' => '' ]); - $assets->css([$this, 'addBaseCss']); - $assets->localeCss([$this, 'addBaseCss']); + $assets->css($this->addBaseCss(...)); + $assets->localeCss($this->addBaseCss(...)); return $assets; }; diff --git a/framework/core/src/Group/Access/GroupPolicy.php b/framework/core/src/Group/Access/GroupPolicy.php index cff5c4749..19189a490 100644 --- a/framework/core/src/Group/Access/GroupPolicy.php +++ b/framework/core/src/Group/Access/GroupPolicy.php @@ -14,10 +14,12 @@ use Flarum\User\User; class GroupPolicy extends AbstractPolicy { - public function can(User $actor, string $ability) + public function can(User $actor, string $ability): ?string { if ($actor->hasPermission('group.'.$ability)) { return $this->allow(); } + + return null; } } diff --git a/framework/core/src/Http/Access/AccessTokenPolicy.php b/framework/core/src/Http/Access/AccessTokenPolicy.php index 5346ae627..fc7419536 100644 --- a/framework/core/src/Http/Access/AccessTokenPolicy.php +++ b/framework/core/src/Http/Access/AccessTokenPolicy.php @@ -15,10 +15,12 @@ use Flarum\User\User; class AccessTokenPolicy extends AbstractPolicy { - public function revoke(User $actor, AccessToken $token) + public function revoke(User $actor, AccessToken $token): ?string { if ($token->user_id === $actor->id || $actor->hasPermission('moderateAccessTokens')) { return $this->allow(); } + + return null; } } diff --git a/framework/core/src/Http/Middleware/AuthenticateWithHeader.php b/framework/core/src/Http/Middleware/AuthenticateWithHeader.php index 27b346df5..bce59949b 100644 --- a/framework/core/src/Http/Middleware/AuthenticateWithHeader.php +++ b/framework/core/src/Http/Middleware/AuthenticateWithHeader.php @@ -58,7 +58,7 @@ class AuthenticateWithHeader implements Middleware return $handler->handle($request); } - private function getUser($string): ?User + private function getUser(string $string): ?User { $parts = explode('=', trim($string)); diff --git a/framework/core/src/Http/RouteCollection.php b/framework/core/src/Http/RouteCollection.php index a27640441..9d20e22e0 100644 --- a/framework/core/src/Http/RouteCollection.php +++ b/framework/core/src/Http/RouteCollection.php @@ -30,32 +30,32 @@ class RouteCollection $this->routeParser = new RouteParser\Std; } - public function get($path, $name, $handler): self + public function get(string $path, string $name, callable|string $handler): self { return $this->addRoute('GET', $path, $name, $handler); } - public function post($path, $name, $handler): self + public function post(string $path, string $name, callable|string $handler): self { return $this->addRoute('POST', $path, $name, $handler); } - public function put($path, $name, $handler): self + public function put(string $path, string $name, callable|string $handler): self { return $this->addRoute('PUT', $path, $name, $handler); } - public function patch($path, $name, $handler): self + public function patch(string $path, string $name, callable|string $handler): self { return $this->addRoute('PATCH', $path, $name, $handler); } - public function delete($path, $name, $handler): self + public function delete(string $path, string $name, callable|string $handler): self { return $this->addRoute('DELETE', $path, $name, $handler); } - public function addRoute($method, $path, $name, $handler): self + public function addRoute(string $method, string $path, string $name, callable|string $handler): self { if (isset($this->routes[$name])) { throw new \RuntimeException("Route $name already exists"); @@ -102,7 +102,7 @@ class RouteCollection return $this->dataGenerator->getData(); } - protected function fixPathPart(mixed $part, array $parameters, string $routeName) + protected function fixPathPart(mixed $part, array $parameters, string $routeName): string { if (! is_array($part)) { return $part; diff --git a/framework/core/src/Http/RouteHandlerFactory.php b/framework/core/src/Http/RouteHandlerFactory.php index ea45c3b8b..eef4d5db8 100644 --- a/framework/core/src/Http/RouteHandlerFactory.php +++ b/framework/core/src/Http/RouteHandlerFactory.php @@ -26,7 +26,7 @@ class RouteHandlerFactory ) { } - public function toController($controller): Closure + public function toController(callable|string $controller): Closure { return function (Request $request, array $routeParams) use ($controller) { $controller = $this->resolveController($controller); @@ -60,7 +60,7 @@ class RouteHandlerFactory return $this->toFrontend('admin', $content); } - private function resolveController($controller): Handler + private function resolveController(callable|string $controller): Handler { if (is_callable($controller)) { $controller = $this->container->call($controller); diff --git a/framework/core/src/Http/Server.php b/framework/core/src/Http/Server.php index c872d05f1..4fff8e0a0 100644 --- a/framework/core/src/Http/Server.php +++ b/framework/core/src/Http/Server.php @@ -52,7 +52,7 @@ class Server * * @throws Throwable */ - private function safelyBootAndGetHandler() + private function safelyBootAndGetHandler() // @phpstan-ignore-line { try { return $this->site->bootApp()->getRequestHandler(); diff --git a/framework/core/src/Install/Console/InstallCommand.php b/framework/core/src/Install/Console/InstallCommand.php index 8c98eb376..d75b4d1de 100644 --- a/framework/core/src/Install/Console/InstallCommand.php +++ b/framework/core/src/Install/Console/InstallCommand.php @@ -103,7 +103,7 @@ class InstallCommand extends AbstractCommand ->run(); } - protected function showProblems($problems): void + protected function showProblems(iterable $problems): void { $this->output->writeln( 'Please fix the following problems before we can continue with the installation.' diff --git a/framework/core/src/Install/Console/UserDataProvider.php b/framework/core/src/Install/Console/UserDataProvider.php index 38cecf7fa..f72b55bb7 100644 --- a/framework/core/src/Install/Console/UserDataProvider.php +++ b/framework/core/src/Install/Console/UserDataProvider.php @@ -76,7 +76,7 @@ class UserDataProvider implements DataProviderInterface ); } - private function askForAdminPassword() + private function askForAdminPassword(): string { while (true) { $password = $this->secret('Admin password (required >= 8 characters):'); @@ -108,14 +108,14 @@ class UserDataProvider implements DataProviderInterface ]; } - private function ask($question, $default = null): mixed + private function ask(string $question, string $default = null): mixed { $question = new Question("$question ", $default); return $this->questionHelper->ask($this->input, $this->output, $question); } - private function secret($question): mixed + private function secret(string $question): mixed { $question = new Question("$question "); @@ -124,7 +124,7 @@ class UserDataProvider implements DataProviderInterface return $this->questionHelper->ask($this->input, $this->output, $question); } - private function validationError($message): void + private function validationError(string $message): void { $this->output->writeln("$message"); $this->output->writeln('Please try again.'); diff --git a/framework/core/src/Install/Pipeline.php b/framework/core/src/Install/Pipeline.php index 21a5fa571..1af323ec5 100644 --- a/framework/core/src/Install/Pipeline.php +++ b/framework/core/src/Install/Pipeline.php @@ -33,7 +33,7 @@ class Pipeline return $this; } - public function on($event, callable $callback): self + public function on(string $event, callable $callback): self { $this->callbacks[$event] = $callback; @@ -88,7 +88,7 @@ class Pipeline } } - private function fireCallbacks($event, Step $step): void + private function fireCallbacks(string $event, Step $step): void { if (isset($this->callbacks[$event])) { ($this->callbacks[$event])($step); diff --git a/framework/core/src/Install/Prerequisite/WritablePaths.php b/framework/core/src/Install/Prerequisite/WritablePaths.php index b5fb8a86d..91ca12190 100644 --- a/framework/core/src/Install/Prerequisite/WritablePaths.php +++ b/framework/core/src/Install/Prerequisite/WritablePaths.php @@ -54,7 +54,7 @@ class WritablePaths implements PrerequisiteInterface }); } - private function getAbsolutePath($path) + private function getAbsolutePath(string $path): string { $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); diff --git a/framework/core/src/Locale/LocaleManager.php b/framework/core/src/Locale/LocaleManager.php index 36e14d749..2bae99c86 100644 --- a/framework/core/src/Locale/LocaleManager.php +++ b/framework/core/src/Locale/LocaleManager.php @@ -49,7 +49,7 @@ class LocaleManager return isset($this->locales[$locale]); } - public function addTranslations(string $locale, $file, string $module = null): void + public function addTranslations(string $locale, string $file, string $module = null): void { $prefix = $module ? $module.'::' : ''; diff --git a/framework/core/src/Locale/PrefixedYamlFileLoader.php b/framework/core/src/Locale/PrefixedYamlFileLoader.php index 20f69a4d4..528a05aff 100644 --- a/framework/core/src/Locale/PrefixedYamlFileLoader.php +++ b/framework/core/src/Locale/PrefixedYamlFileLoader.php @@ -14,7 +14,7 @@ use Symfony\Component\Translation\MessageCatalogue; class PrefixedYamlFileLoader extends YamlFileLoader { - public function load(mixed $resource, $locale, $domain = 'messages'): MessageCatalogue + public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue { $catalogue = parent::load($resource['file'], $locale, $domain); diff --git a/framework/core/src/Post/Access/PostPolicy.php b/framework/core/src/Post/Access/PostPolicy.php index 839fa57a2..2171f1f55 100644 --- a/framework/core/src/Post/Access/PostPolicy.php +++ b/framework/core/src/Post/Access/PostPolicy.php @@ -22,14 +22,16 @@ class PostPolicy extends AbstractPolicy ) { } - public function can(User $actor, string $ability, Post $post) + public function can(User $actor, string $ability, Post $post): ?string { if ($actor->can($ability.'Posts', $post->discussion)) { return $this->allow(); } + + return null; } - public function edit(User $actor, Post $post) + public function edit(User $actor, Post $post): ?string { // A post is allowed to be edited if the user is the author, the post // hasn't been deleted by someone else, and the user is allowed to @@ -43,9 +45,11 @@ class PostPolicy extends AbstractPolicy return $this->allow(); } } + + return null; } - public function hide(User $actor, Post $post) + public function hide(User $actor, Post $post): ?string { if ($post->user_id == $actor->id && (! $post->hidden_at || $post->hidden_user_id == $actor->id) && $actor->can('reply', $post->discussion)) { $allowHiding = $this->settings->get('allow_hide_own_posts'); @@ -56,5 +60,7 @@ class PostPolicy extends AbstractPolicy return $this->allow(); } } + + return null; } } diff --git a/framework/core/src/Queue/QueueServiceProvider.php b/framework/core/src/Queue/QueueServiceProvider.php index 4d19b30fc..bf7d6fa68 100644 --- a/framework/core/src/Queue/QueueServiceProvider.php +++ b/framework/core/src/Queue/QueueServiceProvider.php @@ -16,6 +16,7 @@ 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\Cache\Repository; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandling; use Illuminate\Contracts\Events\Dispatcher; @@ -91,29 +92,24 @@ 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 { - /** - * @var Container - */ - private $container; - - public function __construct(Container $container) - { - $this->container = $container; + public function __construct( + private readonly Container $container + ) { } - public function driver() + public function driver(): Repository { return $this->container['cache.store']; } // We have to define this explicitly // so that we implement the interface. - public function store($name = null) + public function store($name = null): mixed { return $this->__call($name, null); } - public function __call($name, $arguments) + public function __call(string $name, ?array $arguments): mixed { return call_user_func_array([$this->driver(), $name], $arguments); } diff --git a/framework/core/src/Settings/DatabaseSettingsRepository.php b/framework/core/src/Settings/DatabaseSettingsRepository.php index 801d0c7e9..51b05d4fa 100644 --- a/framework/core/src/Settings/DatabaseSettingsRepository.php +++ b/framework/core/src/Settings/DatabaseSettingsRepository.php @@ -23,7 +23,7 @@ class DatabaseSettingsRepository implements SettingsRepositoryInterface return $this->database->table('settings')->pluck('value', 'key')->all(); } - public function get(string $key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { if (is_null($value = $this->database->table('settings')->where('key', $key)->value('value'))) { return $default; diff --git a/framework/core/src/Settings/DefaultSettingsRepository.php b/framework/core/src/Settings/DefaultSettingsRepository.php index ee0235fa3..e1b93bbbd 100644 --- a/framework/core/src/Settings/DefaultSettingsRepository.php +++ b/framework/core/src/Settings/DefaultSettingsRepository.php @@ -19,7 +19,7 @@ class DefaultSettingsRepository implements SettingsRepositoryInterface ) { } - public function get(string $key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { // Global default overrules local default because local default is deprecated, // and will be removed in 2.0 diff --git a/framework/core/src/Settings/MemoryCacheSettingsRepository.php b/framework/core/src/Settings/MemoryCacheSettingsRepository.php index b045fa123..5f75849f3 100644 --- a/framework/core/src/Settings/MemoryCacheSettingsRepository.php +++ b/framework/core/src/Settings/MemoryCacheSettingsRepository.php @@ -31,7 +31,7 @@ class MemoryCacheSettingsRepository implements SettingsRepositoryInterface return $this->cache; } - public function get(string $key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { if (array_key_exists($key, $this->cache)) { return $this->cache[$key]; diff --git a/framework/core/src/Settings/OverrideSettingsRepository.php b/framework/core/src/Settings/OverrideSettingsRepository.php index efc9468ef..4e2f349f0 100644 --- a/framework/core/src/Settings/OverrideSettingsRepository.php +++ b/framework/core/src/Settings/OverrideSettingsRepository.php @@ -36,7 +36,7 @@ class OverrideSettingsRepository implements SettingsRepositoryInterface return array_merge($this->inner->all(), $this->overrides); } - public function get(string $key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { if (array_key_exists($key, $this->overrides)) { return $this->overrides[$key]; diff --git a/framework/core/src/Settings/SettingsRepositoryInterface.php b/framework/core/src/Settings/SettingsRepositoryInterface.php index 0c6e4c42f..88926c8d6 100644 --- a/framework/core/src/Settings/SettingsRepositoryInterface.php +++ b/framework/core/src/Settings/SettingsRepositoryInterface.php @@ -16,7 +16,7 @@ interface SettingsRepositoryInterface /** * @todo remove deprecated $default in 2.0 */ - public function get(string $key, $default = null): mixed; + public function get(string $key, mixed $default = null): mixed; public function set(string $key, mixed $value): void; diff --git a/framework/core/src/Settings/UninstalledSettingsRepository.php b/framework/core/src/Settings/UninstalledSettingsRepository.php index e602180af..e1199151e 100644 --- a/framework/core/src/Settings/UninstalledSettingsRepository.php +++ b/framework/core/src/Settings/UninstalledSettingsRepository.php @@ -16,7 +16,7 @@ class UninstalledSettingsRepository implements SettingsRepositoryInterface return []; } - public function get(string $key, $default = null): mixed + public function get(string $key, mixed $default = null): mixed { return $default; } diff --git a/framework/core/src/User/Access/AbstractPolicy.php b/framework/core/src/User/Access/AbstractPolicy.php index e1166e006..16bd326cb 100644 --- a/framework/core/src/User/Access/AbstractPolicy.php +++ b/framework/core/src/User/Access/AbstractPolicy.php @@ -9,6 +9,7 @@ namespace Flarum\User\Access; +use Flarum\Database\AbstractModel; use Flarum\User\User; abstract class AbstractPolicy @@ -39,7 +40,7 @@ abstract class AbstractPolicy return static::FORCE_DENY; } - public function checkAbility(User $actor, string $ability, $instance) + public function checkAbility(User $actor, string $ability, string|AbstractModel|null $instance): ?string { // If a specific method for this ability is defined, // call that and return any non-null results @@ -55,6 +56,8 @@ abstract class AbstractPolicy if (method_exists($this, 'can')) { return $this->sanitizeResult(call_user_func_array([$this, 'can'], [$actor, $ability, $instance])); } + + return null; } /** diff --git a/framework/core/src/User/Access/Gate.php b/framework/core/src/User/Access/Gate.php index 75f01a688..66e1e5771 100644 --- a/framework/core/src/User/Access/Gate.php +++ b/framework/core/src/User/Access/Gate.php @@ -46,6 +46,7 @@ class Gate public function allows(User $actor, string $ability, string|AbstractModel|null $model): bool { $results = []; + /** @var AbstractPolicy[] $appliedPolicies */ $appliedPolicies = []; if ($model) { diff --git a/framework/core/src/User/Access/UserPolicy.php b/framework/core/src/User/Access/UserPolicy.php index 2fd137df0..4db006a02 100644 --- a/framework/core/src/User/Access/UserPolicy.php +++ b/framework/core/src/User/Access/UserPolicy.php @@ -13,14 +13,16 @@ use Flarum\User\User; class UserPolicy extends AbstractPolicy { - public function can(User $actor, string $ability) + public function can(User $actor, string $ability): ?string { if ($actor->hasPermission('user.'.$ability)) { return $this->allow(); } + + return null; } - public function editCredentials(User $actor, User $user) + public function editCredentials(User $actor, User $user): ?string { if ($user->isAdmin() && ! $actor->isAdmin()) { return $this->deny(); @@ -29,5 +31,7 @@ class UserPolicy extends AbstractPolicy if ($actor->hasPermission('user.editCredentials')) { return $this->allow(); } + + return null; } } diff --git a/framework/core/src/User/AvatarValidator.php b/framework/core/src/User/AvatarValidator.php index 15b237133..615e86b6d 100644 --- a/framework/core/src/User/AvatarValidator.php +++ b/framework/core/src/User/AvatarValidator.php @@ -91,7 +91,7 @@ class AvatarValidator extends AbstractValidator } } - protected function raise($error, array $parameters = [], $rule = null): void + protected function raise(string $error, array $parameters = [], string $rule = null): void { // When we switched to intl ICU message format, the translation parameters // have become required to be in the format `{param}`. diff --git a/framework/core/src/User/Command/RegisterUserHandler.php b/framework/core/src/User/Command/RegisterUserHandler.php index 4dc745bc7..88f848382 100644 --- a/framework/core/src/User/Command/RegisterUserHandler.php +++ b/framework/core/src/User/Command/RegisterUserHandler.php @@ -96,7 +96,7 @@ class RegisterUserHandler return $user; } - private function applyToken(User $user, RegistrationToken $token) + private function applyToken(User $user, RegistrationToken $token): void { foreach ($token->user_attributes as $k => $v) { if ($k === 'avatar_url') { diff --git a/framework/core/src/User/Query/EmailFilterGambit.php b/framework/core/src/User/Query/EmailFilterGambit.php index 2fa4bb58b..c0028fe84 100644 --- a/framework/core/src/User/Query/EmailFilterGambit.php +++ b/framework/core/src/User/Query/EmailFilterGambit.php @@ -53,7 +53,7 @@ class EmailFilterGambit extends AbstractRegexGambit implements FilterInterface $this->constrain($filterState->getQuery(), $filterValue, $negate); } - protected function constrain(Builder $query, $rawEmail, bool $negate): void + protected function constrain(Builder $query, string|array $rawEmail, bool $negate): void { $email = $this->asString($rawEmail); diff --git a/framework/core/src/User/Query/GroupFilterGambit.php b/framework/core/src/User/Query/GroupFilterGambit.php index 39807fba2..ebb118b42 100644 --- a/framework/core/src/User/Query/GroupFilterGambit.php +++ b/framework/core/src/User/Query/GroupFilterGambit.php @@ -42,7 +42,7 @@ class GroupFilterGambit extends AbstractRegexGambit implements FilterInterface $this->constrain($filterState->getQuery(), $filterState->getActor(), $filterValue, $negate); } - protected function constrain(Builder $query, User $actor, $rawQuery, bool $negate): void + protected function constrain(Builder $query, User $actor, string|array $rawQuery, bool $negate): void { $groupIdentifiers = $this->asStringArray($rawQuery); $groupQuery = Group::whereVisibleTo($actor); diff --git a/framework/core/src/helpers.php b/framework/core/src/helpers.php index 51aa9acb8..6df8ffa4c 100644 --- a/framework/core/src/helpers.php +++ b/framework/core/src/helpers.php @@ -114,7 +114,7 @@ if (! function_exists('config')) { /** * @deprecated do not use, will be transferred to flarum/laravel-helpers. */ - function config(string $key, $default = null) + function config(string $key, mixed $default = null): mixed { return resolve(Repository::class)->get($key, $default); } diff --git a/phpstan.neon b/phpstan.neon index 5081c1bac..30392ff54 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,7 +2,7 @@ includes: - php-packages/phpstan/extension.neon parameters: - level: 5 + level: 6 paths: - framework/core/src - extensions/akismet/src @@ -36,4 +36,5 @@ parameters: excludePaths: - *.blade.php checkMissingIterableValueType: false + checkGenericClassInNonGenericObjectType: false databaseMigrationsPath: ['framework/core/migrations']