chore: update codebase to php8.1 (#3827)

* chore: set minimum php version to 8.1

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* chore: update codebase to php8.1

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* Apply fixes from StyleCI

* chore: update workflow php version

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: caught errors

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: more caught errors

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: phpstan caught errors

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* Apply fixes from StyleCI

* fix: test-caught errors

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: test-caught errors

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: test-caught errors

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: introduce `Flarum\Locale\TranslatorInterface`

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* Apply fixes from StyleCI

* chore: remove mixin

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: test-caught errors

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

* fix: one last error

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>

---------

Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>
Co-authored-by: StyleCI Bot <bot@styleci.io>
This commit is contained in:
Sami Mazouz 2023-05-30 11:36:12 +01:00 committed by GitHub
parent 34a04b0746
commit 6f11e044a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
703 changed files with 4329 additions and 12772 deletions

View File

@ -25,7 +25,7 @@ on:
description: Versions of PHP to test with. Should be array of strings encoded as JSON array description: Versions of PHP to test with. Should be array of strings encoded as JSON array
type: string type: string
required: false required: false
default: '["7.3", "7.4", "8.0", "8.1", "8.2"]' default: '["8.1", "8.2"]'
php_extensions: php_extensions:
description: PHP extensions to install. description: PHP extensions to install.

View File

@ -85,7 +85,7 @@
"flarum/testing": "self.version" "flarum/testing": "self.version"
}, },
"require": { "require": {
"php": ">=7.3", "php": "^8.1",
"ext-json": "*", "ext-json": "*",
"components/font-awesome": "^5.14.0", "components/font-awesome": "^5.14.0",
"composer/composer": "^2.0", "composer/composer": "^2.0",

View File

@ -14,17 +14,12 @@ use Flarum\Approval\Event\PostWasApproved;
class SubmitHam class SubmitHam
{ {
/** public function __construct(
* @var Akismet protected Akismet $akismet
*/ ) {
protected $akismet;
public function __construct(Akismet $akismet)
{
$this->akismet = $akismet;
} }
public function handle(PostWasApproved $event) public function handle(PostWasApproved $event): void
{ {
if (! $this->akismet->isConfigured()) { if (! $this->akismet->isConfigured()) {
return; return;

View File

@ -14,17 +14,12 @@ use Flarum\Post\Event\Hidden;
class SubmitSpam class SubmitSpam
{ {
/** public function __construct(
* @var Akismet protected Akismet $akismet
*/ ) {
protected $akismet;
public function __construct(Akismet $akismet)
{
$this->akismet = $akismet;
} }
public function handle(Hidden $event) public function handle(Hidden $event): void
{ {
if (! $this->akismet->isConfigured()) { if (! $this->akismet->isConfigured()) {
return; return;

View File

@ -18,22 +18,13 @@ use Flarum\Settings\SettingsRepositoryInterface;
class ValidatePost class ValidatePost
{ {
/** public function __construct(
* @var Akismet protected Akismet $akismet,
*/ protected SettingsRepositoryInterface $settings
protected $akismet; ) {
/**
* @var SettingsRepositoryInterface
*/
private $settings;
public function __construct(Akismet $akismet, SettingsRepositoryInterface $settings)
{
$this->akismet = $akismet;
$this->settings = $settings;
} }
public function handle(Saving $event) public function handle(Saving $event): void
{ {
if (! $this->akismet->isConfigured()) { if (! $this->akismet->isConfigured()) {
return; return;

View File

@ -20,7 +20,7 @@ use Illuminate\Container\Container;
class AkismetProvider extends AbstractServiceProvider class AkismetProvider extends AbstractServiceProvider
{ {
public function register() public function register(): void
{ {
$this->container->bind(Akismet::class, function (Container $container) { $this->container->bind(Akismet::class, function (Container $container) {
/** @var SettingsRepositoryInterface $settings */ /** @var SettingsRepositoryInterface $settings */

View File

@ -37,7 +37,7 @@ return [
->cast('is_approved', 'bool'), ->cast('is_approved', 'bool'),
(new Extend\ApiSerializer(BasicDiscussionSerializer::class)) (new Extend\ApiSerializer(BasicDiscussionSerializer::class))
->attribute('isApproved', function ($serializer, Discussion $discussion) { ->attribute('isApproved', function (BasicDiscussionSerializer $serializer, Discussion $discussion): bool {
return $discussion->is_approved; return $discussion->is_approved;
}), }),
@ -65,8 +65,8 @@ return [
->scope(Access\ScopePrivateDiscussionVisibility::class, 'viewPrivate'), ->scope(Access\ScopePrivateDiscussionVisibility::class, 'viewPrivate'),
(new Extend\ModelPrivate(Discussion::class)) (new Extend\ModelPrivate(Discussion::class))
->checker([Listener\UnapproveNewContent::class, 'markUnapprovedContentAsPrivate']), ->checker(Listener\UnapproveNewContent::markUnapprovedContentAsPrivate(...)),
(new Extend\ModelPrivate(CommentPost::class)) (new Extend\ModelPrivate(CommentPost::class))
->checker([Listener\UnapproveNewContent::class, 'markUnapprovedContentAsPrivate']), ->checker(Listener\UnapproveNewContent::markUnapprovedContentAsPrivate(...)),
]; ];

View File

@ -14,11 +14,7 @@ use Illuminate\Database\Eloquent\Builder;
class ScopePrivateDiscussionVisibility class ScopePrivateDiscussionVisibility
{ {
/** public function __invoke(User $actor, Builder $query): void
* @param Builder $query
* @param User $actor
*/
public function __invoke(User $actor, Builder $query)
{ {
// All statements need to be wrapped in an orWhere, since we're adding a // All statements need to be wrapped in an orWhere, since we're adding a
// subset of private discussions that should be visible, not restricting the visible // subset of private discussions that should be visible, not restricting the visible

View File

@ -16,11 +16,7 @@ use Illuminate\Database\Eloquent\Builder;
class ScopePrivatePostVisibility class ScopePrivatePostVisibility
{ {
/** public function __invoke(User $actor, Builder $query): void
* @param Builder $query
* @param User $actor
*/
public function __invoke(User $actor, Builder $query)
{ {
// All statements need to be wrapped in an orWhere, since we're adding a // All statements need to be wrapped in an orWhere, since we're adding a
// subset of private posts that should be visible, not restricting the visible // subset of private posts that should be visible, not restricting the visible

View File

@ -15,10 +15,7 @@ use Flarum\User\User;
class TagPolicy extends AbstractPolicy class TagPolicy extends AbstractPolicy
{ {
/** public function addToDiscussion(User $actor, Tag $tag): bool
* @return bool|null
*/
public function addToDiscussion(User $actor, Tag $tag)
{ {
return $actor->can('discussion.startWithoutApproval', $tag); return $actor->can('discussion.startWithoutApproval', $tag);
} }

View File

@ -14,25 +14,9 @@ use Flarum\User\User;
class PostWasApproved class PostWasApproved
{ {
/** public function __construct(
* The post that was approved. public Post $post,
* public User $actor
* @var Post ) {
*/
public $post;
/**
* @var User
*/
public $actor;
/**
* @param Post $post
* @param User $actor
*/
public function __construct(Post $post, User $actor)
{
$this->post = $post;
$this->actor = $actor;
} }
} }

View File

@ -15,15 +15,12 @@ use Illuminate\Contracts\Events\Dispatcher;
class ApproveContent class ApproveContent
{ {
/** public function subscribe(Dispatcher $events): void
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events)
{ {
$events->listen(Saving::class, [$this, 'approvePost']); $events->listen(Saving::class, $this->approvePost(...));
} }
public function approvePost(Saving $event) public function approvePost(Saving $event): void
{ {
$attributes = $event->data['attributes']; $attributes = $event->data['attributes'];
$post = $event->post; $post = $event->post;

View File

@ -18,18 +18,12 @@ use Illuminate\Contracts\Events\Dispatcher;
class UnapproveNewContent class UnapproveNewContent
{ {
/** public function subscribe(Dispatcher $events): void
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events)
{ {
$events->listen(Saving::class, [$this, 'unapproveNewPosts']); $events->listen(Saving::class, $this->unapproveNewPosts(...));
} }
/** public function unapproveNewPosts(Saving $event): void
* @param Saving $event
*/
public function unapproveNewPosts(Saving $event)
{ {
$post = $event->post; $post = $event->post;
@ -63,14 +57,12 @@ class UnapproveNewContent
} }
} }
/** public static function markUnapprovedContentAsPrivate(Discussion|CommentPost $instance): ?bool
* @param Discussion|CommentPost $instance
* @return bool|null
*/
public static function markUnapprovedContentAsPrivate($instance)
{ {
if (! $instance->is_approved) { if (! $instance->is_approved) {
return true; return true;
} }
return null;
} }
} }

View File

@ -13,7 +13,7 @@ use Flarum\Approval\Event\PostWasApproved;
class UpdateDiscussionAfterPostApproval class UpdateDiscussionAfterPostApproval
{ {
public function handle(PostWasApproved $event) public function handle(PostWasApproved $event): void
{ {
$post = $event->post; $post = $event->post;
$discussion = $post->discussion; $discussion = $post->discussion;

View File

@ -13,7 +13,7 @@ use s9e\TextFormatter\Configurator;
class Configure class Configure
{ {
public function __invoke(Configurator $config) public function __invoke(Configurator $config): void
{ {
$this->addTagsFromRepositories($config); $this->addTagsFromRepositories($config);
$this->adaptHighlightJs($config); $this->adaptHighlightJs($config);

View File

@ -9,19 +9,14 @@
namespace Flarum\BBCode; namespace Flarum\BBCode;
use Flarum\Locale\TranslatorInterface;
use s9e\TextFormatter\Renderer; use s9e\TextFormatter\Renderer;
use Symfony\Contracts\Translation\TranslatorInterface;
class Render class Render
{ {
/** public function __construct(
* @var TranslatorInterface protected TranslatorInterface $translator
*/ ) {
protected $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
} }
public function __invoke(Renderer $renderer, $context, string $xml): string public function __invoke(Renderer $renderer, $context, string $xml): string

View File

@ -16,17 +16,12 @@ use Illuminate\Database\Eloquent\Builder;
class ScopeFlagVisibility class ScopeFlagVisibility
{ {
/** public function __construct(
* @var ExtensionManager protected ExtensionManager $extensions
*/ ) {
protected $extensions;
public function __construct(ExtensionManager $extensions)
{
$this->extensions = $extensions;
} }
public function __invoke(User $actor, Builder $query) public function __invoke(User $actor, Builder $query): void
{ {
if ($this->extensions->isEnabled('flarum-tags')) { if ($this->extensions->isEnabled('flarum-tags')) {
$query $query

View File

@ -16,20 +16,12 @@ use Flarum\User\User;
class AddCanFlagAttribute class AddCanFlagAttribute
{ {
/** public function __construct(
* @var SettingsRepositoryInterface protected SettingsRepositoryInterface $settings
*/ ) {
protected $settings;
/**
* @param SettingsRepositoryInterface $settings
*/
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
} }
public function __invoke(PostSerializer $serializer, Post $post) public function __invoke(PostSerializer $serializer, Post $post): bool
{ {
return $serializer->getActor()->can('flag', $post) && $this->checkFlagOwnPostSetting($serializer->getActor(), $post); return $serializer->getActor()->can('flag', $post) && $this->checkFlagOwnPostSetting($serializer->getActor(), $post);
} }

View File

@ -15,20 +15,12 @@ use Flarum\User\User;
class AddFlagsApiAttributes class AddFlagsApiAttributes
{ {
/** public function __construct(
* @var SettingsRepositoryInterface protected SettingsRepositoryInterface $settings
*/ ) {
protected $settings;
/**
* @param SettingsRepositoryInterface $settings
*/
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
} }
public function __invoke(ForumSerializer $serializer) public function __invoke(ForumSerializer $serializer): array
{ {
$attributes = [ $attributes = [
'canViewFlags' => $serializer->getActor()->hasPermissionLike('discussion.viewFlags') 'canViewFlags' => $serializer->getActor()->hasPermissionLike('discussion.viewFlags')
@ -41,11 +33,7 @@ class AddFlagsApiAttributes
return $attributes; return $attributes;
} }
/** protected function getFlagCount(User $actor): int
* @param User $actor
* @return int
*/
protected function getFlagCount(User $actor)
{ {
return Flag::whereVisibleTo($actor)->distinct()->count('flags.post_id'); return Flag::whereVisibleTo($actor)->distinct()->count('flags.post_id');
} }

View File

@ -14,16 +14,12 @@ use Flarum\User\User;
class AddNewFlagCountAttribute class AddNewFlagCountAttribute
{ {
public function __invoke(CurrentUserSerializer $serializer, User $user) public function __invoke(CurrentUserSerializer $serializer, User $user): int
{ {
return (int) $this->getNewFlagCount($user); return $this->getNewFlagCount($user);
} }
/** protected function getNewFlagCount(User $actor): int
* @param User $actor
* @return int
*/
protected function getNewFlagCount(User $actor)
{ {
$query = Flag::whereVisibleTo($actor); $query = Flag::whereVisibleTo($actor);

View File

@ -12,6 +12,7 @@ namespace Flarum\Flags\Api\Controller;
use Flarum\Api\Controller\AbstractCreateController; use Flarum\Api\Controller\AbstractCreateController;
use Flarum\Flags\Api\Serializer\FlagSerializer; use Flarum\Flags\Api\Serializer\FlagSerializer;
use Flarum\Flags\Command\CreateFlag; use Flarum\Flags\Command\CreateFlag;
use Flarum\Flags\Flag;
use Flarum\Http\RequestUtil; use Flarum\Http\RequestUtil;
use Illuminate\Contracts\Bus\Dispatcher; use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
@ -20,37 +21,20 @@ use Tobscure\JsonApi\Document;
class CreateFlagController extends AbstractCreateController class CreateFlagController extends AbstractCreateController
{ {
/** public ?string $serializer = FlagSerializer::class;
* {@inheritdoc}
*/
public $serializer = FlagSerializer::class;
/** public array $include = [
* {@inheritdoc}
*/
public $include = [
'post', 'post',
'post.flags', 'post.flags',
'user' 'user'
]; ];
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
/**
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
/** protected function data(ServerRequestInterface $request, Document $document): Flag
* {@inheritdoc}
*/
protected function data(ServerRequestInterface $request, Document $document)
{ {
return $this->bus->dispatch( return $this->bus->dispatch(
new CreateFlag(RequestUtil::getActor($request), Arr::get($request->getParsedBody(), 'data', [])) new CreateFlag(RequestUtil::getActor($request), Arr::get($request->getParsedBody(), 'data', []))

View File

@ -18,23 +18,12 @@ use Psr\Http\Message\ServerRequestInterface;
class DeleteFlagsController extends AbstractDeleteController class DeleteFlagsController extends AbstractDeleteController
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
/**
* @param Dispatcher $bus
*/
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
/** protected function delete(ServerRequestInterface $request): void
* {@inheritdoc}
*/
protected function delete(ServerRequestInterface $request)
{ {
$this->bus->dispatch( $this->bus->dispatch(
new DeleteFlags(Arr::get($request->getQueryParams(), 'id'), RequestUtil::getActor($request), $request->getParsedBody()) new DeleteFlags(Arr::get($request->getQueryParams(), 'id'), RequestUtil::getActor($request), $request->getParsedBody())

View File

@ -19,25 +19,16 @@ use Tobscure\JsonApi\Document;
class ListFlagsController extends AbstractListController class ListFlagsController extends AbstractListController
{ {
/** public ?string $serializer = FlagSerializer::class;
* {@inheritdoc}
*/
public $serializer = FlagSerializer::class;
/** public array $include = [
* {@inheritdoc}
*/
public $include = [
'user', 'user',
'post', 'post',
'post.user', 'post.user',
'post.discussion' 'post.discussion'
]; ];
/** protected function data(ServerRequestInterface $request, Document $document): iterable
* {@inheritdoc}
*/
protected function data(ServerRequestInterface $request, Document $document)
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);
$include = $this->extractInclude($request); $include = $this->extractInclude($request);

View File

@ -14,42 +14,34 @@ use Flarum\Api\Serializer\BasicUserSerializer;
use Flarum\Api\Serializer\PostSerializer; use Flarum\Api\Serializer\PostSerializer;
use Flarum\Flags\Flag; use Flarum\Flags\Flag;
use InvalidArgumentException; use InvalidArgumentException;
use Tobscure\JsonApi\Relationship;
class FlagSerializer extends AbstractSerializer class FlagSerializer extends AbstractSerializer
{ {
/**
* {@inheritdoc}
*/
protected $type = 'flags'; protected $type = 'flags';
protected function getDefaultAttributes($flag) protected function getDefaultAttributes(object|array $model): array
{ {
if (! ($flag instanceof Flag)) { if (! ($model instanceof Flag)) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
get_class($this).' can only serialize instances of '.Flag::class get_class($this).' can only serialize instances of '.Flag::class
); );
} }
return [ return [
'type' => $flag->type, 'type' => $model->type,
'reason' => $flag->reason, 'reason' => $model->reason,
'reasonDetail' => $flag->reason_detail, 'reasonDetail' => $model->reason_detail,
'createdAt' => $this->formatDate($flag->created_at), 'createdAt' => $this->formatDate($model->created_at),
]; ];
} }
/** protected function post(Flag $flag): ?Relationship
* @return \Tobscure\JsonApi\Relationship
*/
protected function post($flag)
{ {
return $this->hasOne($flag, PostSerializer::class); return $this->hasOne($flag, PostSerializer::class);
} }
/** protected function user(Flag $flag): ?Relationship
* @return \Tobscure\JsonApi\Relationship
*/
protected function user($flag)
{ {
return $this->hasOne($flag, BasicUserSerializer::class); return $this->hasOne($flag, BasicUserSerializer::class);
} }

View File

@ -13,27 +13,9 @@ use Flarum\User\User;
class CreateFlag class CreateFlag
{ {
/** public function __construct(
* The user performing the action. public User $actor,
* public array $data
* @var User ) {
*/
public $actor;
/**
* The attributes of the new flag.
*
* @var array
*/
public $data;
/**
* @param User $actor The user performing the action.
* @param array $data The attributes of the new flag.
*/
public function __construct(User $actor, array $data)
{
$this->actor = $actor;
$this->data = $data;
} }
} }

View File

@ -13,58 +13,26 @@ use Carbon\Carbon;
use Flarum\Flags\Event\Created; use Flarum\Flags\Event\Created;
use Flarum\Flags\Flag; use Flarum\Flags\Flag;
use Flarum\Foundation\ValidationException; use Flarum\Foundation\ValidationException;
use Flarum\Locale\TranslatorInterface;
use Flarum\Post\CommentPost; use Flarum\Post\CommentPost;
use Flarum\Post\PostRepository; use Flarum\Post\PostRepository;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\Exception\PermissionDeniedException; use Flarum\User\Exception\PermissionDeniedException;
use Illuminate\Events\Dispatcher; use Illuminate\Events\Dispatcher;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tobscure\JsonApi\Exception\InvalidParameterException; use Tobscure\JsonApi\Exception\InvalidParameterException;
class CreateFlagHandler class CreateFlagHandler
{ {
/** public function __construct(
* @var PostRepository protected PostRepository $posts,
*/ protected TranslatorInterface $translator,
protected $posts; protected SettingsRepositoryInterface $settings,
protected Dispatcher $events
/** ) {
* @var TranslatorInterface
*/
protected $translator;
/**
* @var SettingsRepositoryInterface
*/
protected $settings;
/**
* @var Dispatcher
*/
protected $events;
/**
* @param PostRepository $posts
* @param TranslatorInterface $translator
* @param SettingsRepositoryInterface $settings
* @param Dispatcher $events
*/
public function __construct(PostRepository $posts, TranslatorInterface $translator, SettingsRepositoryInterface $settings, Dispatcher $events)
{
$this->posts = $posts;
$this->translator = $translator;
$this->settings = $settings;
$this->events = $events;
} }
/** public function handle(CreateFlag $command): Flag
* @param CreateFlag $command
* @return Flag
* @throws InvalidParameterException
* @throws ValidationException
*/
public function handle(CreateFlag $command)
{ {
$actor = $command->actor; $actor = $command->actor;
$data = $command->data; $data = $command->data;

View File

@ -13,34 +13,10 @@ use Flarum\User\User;
class DeleteFlags class DeleteFlags
{ {
/** public function __construct(
* The ID of the post to delete flags for. public int $postId,
* public User $actor,
* @var int public array $data = []
*/ ) {
public $postId;
/**
* The user performing the action.
*
* @var User
*/
public $actor;
/**
* @var array
*/
public $data;
/**
* @param int $postId The ID of the post to delete flags for.
* @param User $actor The user performing the action.
* @param array $data
*/
public function __construct($postId, User $actor, array $data = [])
{
$this->postId = $postId;
$this->actor = $actor;
$this->data = $data;
} }
} }

View File

@ -17,31 +17,13 @@ use Illuminate\Events\Dispatcher;
class DeleteFlagsHandler class DeleteFlagsHandler
{ {
/** public function __construct(
* @var PostRepository protected PostRepository $posts,
*/ protected Dispatcher $events
protected $posts; ) {
/**
* @var Dispatcher
*/
protected $events;
/**
* @param PostRepository $posts
* @param Dispatcher $events
*/
public function __construct(PostRepository $posts, Dispatcher $events)
{
$this->posts = $posts;
$this->events = $events;
} }
/** public function handle(DeleteFlags $command): Post
* @param DeleteFlags $command
* @return Post
*/
public function handle(DeleteFlags $command)
{ {
$actor = $command->actor; $actor = $command->actor;

View File

@ -14,30 +14,10 @@ use Flarum\User\User;
class Created class Created
{ {
/** public function __construct(
* @var Flag public Flag $flag,
*/ public User $actor,
public $flag; public array $data = []
) {
/**
* @var User
*/
public $actor;
/**
* @var array
*/
public $data;
/**
* @param Flag $flag
* @param User $actor
* @param array $data
*/
public function __construct(Flag $flag, User $actor, array $data = [])
{
$this->flag = $flag;
$this->actor = $actor;
$this->data = $data;
} }
} }

View File

@ -14,30 +14,10 @@ use Flarum\User\User;
class Deleting class Deleting
{ {
/** public function __construct(
* @var Flag public Flag $flag,
*/ public User $actor,
public $flag; public array $data = []
) {
/**
* @var User
*/
public $actor;
/**
* @var array
*/
public $data;
/**
* @param Flag $flag
* @param User $actor
* @param array $data
*/
public function __construct(Flag $flag, User $actor, array $data = [])
{
$this->flag = $flag;
$this->actor = $actor;
$this->data = $data;
} }
} }

View File

@ -18,30 +18,10 @@ use Flarum\User\User;
*/ */
class FlagsWillBeDeleted class FlagsWillBeDeleted
{ {
/** public function __construct(
* @var Post public Post $post,
*/ public User $actor,
public $post; public array $data = []
) {
/**
* @var User
*/
public $actor;
/**
* @var array
*/
public $data;
/**
* @param Post $post
* @param User $actor
* @param array $data
*/
public function __construct(Post $post, User $actor, array $data = [])
{
$this->post = $post;
$this->actor = $actor;
$this->data = $data;
} }
} }

View File

@ -14,6 +14,7 @@ use Flarum\Database\AbstractModel;
use Flarum\Database\ScopeVisibilityTrait; use Flarum\Database\ScopeVisibilityTrait;
use Flarum\Post\Post; use Flarum\Post\Post;
use Flarum\User\User; use Flarum\User\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/** /**
* @property int $post_id * @property int $post_id
@ -30,23 +31,14 @@ class Flag extends AbstractModel
{ {
use ScopeVisibilityTrait; use ScopeVisibilityTrait;
/**
* {@inheritdoc}
*/
protected $dates = ['created_at']; protected $dates = ['created_at'];
/** public function post(): BelongsTo
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function post()
{ {
return $this->belongsTo(Post::class); return $this->belongsTo(Post::class);
} }
/** public function user(): BelongsTo
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{ {
return $this->belongsTo(User::class); return $this->belongsTo(User::class);
} }

View File

@ -13,10 +13,7 @@ use Flarum\Post\Event\Deleted;
class DeleteFlags class DeleteFlags
{ {
/** public function handle(Deleted $event): void
* @param Deleted $event
*/
public function handle(Deleted $event)
{ {
$event->post->flags()->delete(); $event->post->flags()->delete();
} }

View File

@ -17,7 +17,7 @@ use Psr\Http\Message\ServerRequestInterface;
class PrepareFlagsApiData class PrepareFlagsApiData
{ {
public function __invoke(Controller\AbstractSerializeController $controller, $data, ServerRequestInterface $request) public function __invoke(Controller\AbstractSerializeController $controller, mixed $data, ServerRequestInterface $request): void
{ {
// For any API action that allows the 'flags' relationship to be // For any API action that allows the 'flags' relationship to be
// included, we need to preload this relationship onto the data (Post // included, we need to preload this relationship onto the data (Post

View File

@ -51,25 +51,25 @@ return [
(new Extend\ApiController(Controller\ShowDiscussionController::class)) (new Extend\ApiController(Controller\ShowDiscussionController::class))
->addInclude('posts.likes') ->addInclude('posts.likes')
->loadWhere('posts.likes', [LoadLikesRelationship::class, 'mutateRelation']) ->loadWhere('posts.likes', LoadLikesRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadLikesRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadLikesRelationship::countRelation(...)),
(new Extend\ApiController(Controller\ListPostsController::class)) (new Extend\ApiController(Controller\ListPostsController::class))
->addInclude('likes') ->addInclude('likes')
->loadWhere('likes', [LoadLikesRelationship::class, 'mutateRelation']) ->loadWhere('likes', LoadLikesRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadLikesRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadLikesRelationship::countRelation(...)),
(new Extend\ApiController(Controller\ShowPostController::class)) (new Extend\ApiController(Controller\ShowPostController::class))
->addInclude('likes') ->addInclude('likes')
->loadWhere('likes', [LoadLikesRelationship::class, 'mutateRelation']) ->loadWhere('likes', LoadLikesRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadLikesRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadLikesRelationship::countRelation(...)),
(new Extend\ApiController(Controller\CreatePostController::class)) (new Extend\ApiController(Controller\CreatePostController::class))
->addInclude('likes') ->addInclude('likes')
->loadWhere('likes', [LoadLikesRelationship::class, 'mutateRelation']) ->loadWhere('likes', LoadLikesRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadLikesRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadLikesRelationship::countRelation(...)),
(new Extend\ApiController(Controller\UpdatePostController::class)) (new Extend\ApiController(Controller\UpdatePostController::class))
->addInclude('likes') ->addInclude('likes')
->loadWhere('likes', [LoadLikesRelationship::class, 'mutateRelation']) ->loadWhere('likes', LoadLikesRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadLikesRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadLikesRelationship::countRelation(...)),
(new Extend\Event()) (new Extend\Event())
->listen(PostWasLiked::class, Listener\SendNotificationWhenPostIsLiked::class) ->listen(PostWasLiked::class, Listener\SendNotificationWhenPostIsLiked::class)

View File

@ -16,14 +16,9 @@ use Flarum\User\User;
class LikePostPolicy extends AbstractPolicy class LikePostPolicy extends AbstractPolicy
{ {
/** public function __construct(
* @var SettingsRepositoryInterface protected SettingsRepositoryInterface $settings
*/ ) {
protected $settings;
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
} }
public function like(User $actor, Post $post) public function like(User $actor, Post $post)

View File

@ -9,6 +9,7 @@
namespace Flarum\Likes\Api; namespace Flarum\Likes\Api;
use Flarum\Api\Controller\AbstractSerializeController;
use Flarum\Discussion\Discussion; use Flarum\Discussion\Discussion;
use Flarum\Http\RequestUtil; use Flarum\Http\RequestUtil;
use Flarum\Post\Post; use Flarum\Post\Post;
@ -19,15 +20,15 @@ use Psr\Http\Message\ServerRequestInterface;
class LoadLikesRelationship class LoadLikesRelationship
{ {
public static $maxLikes = 4; public static int $maxLikes = 4;
public static function mutateRelation(BelongsToMany $query, ServerRequestInterface $request): BelongsToMany public static function mutateRelation(BelongsToMany $query, ServerRequestInterface $request): void
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);
$grammar = $query->getQuery()->getGrammar(); $grammar = $query->getQuery()->getGrammar();
return $query $query
// So that we can tell if the current user has liked the post. // So that we can tell if the current user has liked the post.
->orderBy(new Expression($grammar->wrap('user_id').' = '.$actor->id), 'desc') ->orderBy(new Expression($grammar->wrap('user_id').' = '.$actor->id), 'desc')
// Limiting a relationship results is only possible because // Limiting a relationship results is only possible because
@ -39,12 +40,14 @@ class LoadLikesRelationship
/** /**
* Called using the @see ApiController::prepareDataForSerialization extender. * Called using the @see ApiController::prepareDataForSerialization extender.
*/ */
public static function countRelation($controller, $data): void public static function countRelation(AbstractSerializeController $controller, mixed $data): array
{ {
$loadable = null; $loadable = null;
if ($data instanceof Discussion) { if ($data instanceof Discussion) {
$loadable = $data->newCollection($data->posts)->filter(function ($post) { // We do this because the ShowDiscussionController manipulates the posts
// in a way that some of them are just ids.
$loadable = $data->posts->filter(function ($post) {
return $post instanceof Post; return $post instanceof Post;
}); });
} elseif ($data instanceof Collection) { } elseif ($data instanceof Collection) {
@ -56,5 +59,7 @@ class LoadLikesRelationship
if ($loadable) { if ($loadable) {
$loadable->loadCount('likes'); $loadable->loadCount('likes');
} }
return [];
} }
} }

View File

@ -14,23 +14,9 @@ use Flarum\User\User;
class PostWasLiked class PostWasLiked
{ {
/** public function __construct(
* @var Post public Post $post,
*/ public User $user
public $post; ) {
/**
* @var User
*/
public $user;
/**
* @param Post $post
* @param User $user
*/
public function __construct(Post $post, User $user)
{
$this->post = $post;
$this->user = $user;
} }
} }

View File

@ -14,23 +14,9 @@ use Flarum\User\User;
class PostWasUnliked class PostWasUnliked
{ {
/** public function __construct(
* @var Post public Post $post,
*/ public User $user
public $post; ) {
/**
* @var User
*/
public $user;
/**
* @param Post $post
* @param User $user
*/
public function __construct(Post $post, User $user)
{
$this->post = $post;
$this->user = $user;
} }
} }

View File

@ -17,19 +17,13 @@ use Illuminate\Contracts\Events\Dispatcher;
class SaveLikesToDatabase class SaveLikesToDatabase
{ {
/** public function subscribe(Dispatcher $events): void
* @param Dispatcher $events
*/
public function subscribe(Dispatcher $events)
{ {
$events->listen(Saving::class, [$this, 'whenPostIsSaving']); $events->listen(Saving::class, $this->whenPostIsSaving(...));
$events->listen(Deleted::class, [$this, 'whenPostIsDeleted']); $events->listen(Deleted::class, $this->whenPostIsDeleted(...));
} }
/** public function whenPostIsSaving(Saving $event): void
* @param Saving $event
*/
public function whenPostIsSaving(Saving $event)
{ {
$post = $event->post; $post = $event->post;
$data = $event->data; $data = $event->data;
@ -54,10 +48,7 @@ class SaveLikesToDatabase
} }
} }
/** public function whenPostIsDeleted(Deleted $event): void
* @param Deleted $event
*/
public function whenPostIsDeleted(Deleted $event)
{ {
$event->post->likes()->detach(); $event->post->likes()->detach();
} }

View File

@ -15,20 +15,12 @@ use Flarum\Notification\NotificationSyncer;
class SendNotificationWhenPostIsLiked class SendNotificationWhenPostIsLiked
{ {
/** public function __construct(
* @var NotificationSyncer protected NotificationSyncer $notifications
*/ ) {
protected $notifications;
/**
* @param NotificationSyncer $notifications
*/
public function __construct(NotificationSyncer $notifications)
{
$this->notifications = $notifications;
} }
public function handle(PostWasLiked $event) public function handle(PostWasLiked $event): void
{ {
if ($event->post->user && $event->post->user->id != $event->user->id) { if ($event->post->user && $event->post->user->id != $event->user->id) {
$this->notifications->sync( $this->notifications->sync(

View File

@ -15,20 +15,12 @@ use Flarum\Notification\NotificationSyncer;
class SendNotificationWhenPostIsUnliked class SendNotificationWhenPostIsUnliked
{ {
/** public function __construct(
* @var NotificationSyncer protected NotificationSyncer $notifications
*/ ) {
protected $notifications;
/**
* @param NotificationSyncer $notifications
*/
public function __construct(NotificationSyncer $notifications)
{
$this->notifications = $notifications;
} }
public function handle(PostWasUnliked $event) public function handle(PostWasUnliked $event): void
{ {
if ($event->post->user && $event->post->user->id != $event->user->id) { if ($event->post->user && $event->post->user->id != $event->user->id) {
$this->notifications->sync( $this->notifications->sync(

View File

@ -9,67 +9,40 @@
namespace Flarum\Likes\Notification; namespace Flarum\Likes\Notification;
use Flarum\Database\AbstractModel;
use Flarum\Notification\Blueprint\BlueprintInterface; use Flarum\Notification\Blueprint\BlueprintInterface;
use Flarum\Post\Post; use Flarum\Post\Post;
use Flarum\User\User; use Flarum\User\User;
class PostLikedBlueprint implements BlueprintInterface class PostLikedBlueprint implements BlueprintInterface
{ {
/** public function __construct(
* @var Post public Post $post,
*/ public User $user
public $post; ) {
/**
* @var User
*/
public $user;
/**
* @param Post $post
* @param User $user
*/
public function __construct(Post $post, User $user)
{
$this->post = $post;
$this->user = $user;
} }
/** public function getSubject(): ?AbstractModel
* {@inheritdoc}
*/
public function getSubject()
{ {
return $this->post; return $this->post;
} }
/** public function getFromUser(): ?User
* {@inheritdoc}
*/
public function getFromUser()
{ {
return $this->user; return $this->user;
} }
/** public function getData(): mixed
* {@inheritdoc}
*/
public function getData()
{ {
return null;
} }
/** public static function getType(): string
* {@inheritdoc}
*/
public static function getType()
{ {
return 'postLiked'; return 'postLiked';
} }
/** public static function getSubjectModel(): string
* {@inheritdoc}
*/
public static function getSubjectModel()
{ {
return Post::class; return Post::class;
} }

View File

@ -22,7 +22,7 @@ class LikedByFilter implements FilterInterface
return 'likedBy'; return 'likedBy';
} }
public function filter(FilterState $filterState, $filterValue, bool $negate) public function filter(FilterState $filterState, string|array $filterValue, bool $negate): void
{ {
$likedId = $this->asInt($filterValue); $likedId = $this->asInt($filterValue);

View File

@ -11,17 +11,20 @@ namespace Flarum\Likes\Query;
use Flarum\Filter\FilterInterface; use Flarum\Filter\FilterInterface;
use Flarum\Filter\FilterState; use Flarum\Filter\FilterState;
use Flarum\Filter\ValidateFilterTrait;
class LikedFilter implements FilterInterface class LikedFilter implements FilterInterface
{ {
use ValidateFilterTrait;
public function getFilterKey(): string public function getFilterKey(): string
{ {
return 'liked'; return 'liked';
} }
public function filter(FilterState $filterState, string $filterValue, bool $negate) public function filter(FilterState $filterState, string|array $filterValue, bool $negate): void
{ {
$likedId = trim($filterValue, '"'); $likedId = $this->asString($filterValue);
$filterState $filterState
->getQuery() ->getQuery()

View File

@ -15,11 +15,6 @@ use Flarum\User\User;
class DiscussionPolicy extends AbstractPolicy class DiscussionPolicy extends AbstractPolicy
{ {
/**
* @param User $actor
* @param Discussion $discussion
* @return string|void
*/
public function reply(User $actor, Discussion $discussion) public function reply(User $actor, Discussion $discussion)
{ {
if ($discussion->is_locked && $actor->cannot('lock', $discussion)) { if ($discussion->is_locked && $actor->cannot('lock', $discussion)) {

View File

@ -14,23 +14,9 @@ use Flarum\User\User;
class DiscussionWasLocked class DiscussionWasLocked
{ {
/** public function __construct(
* @var Discussion public Discussion $discussion,
*/ public User $user
public $discussion; ) {
/**
* @var User
*/
public $user;
/**
* @param Discussion $discussion
* @param User $user
*/
public function __construct(Discussion $discussion, User $user)
{
$this->discussion = $discussion;
$this->user = $user;
} }
} }

View File

@ -14,23 +14,9 @@ use Flarum\User\User;
class DiscussionWasUnlocked class DiscussionWasUnlocked
{ {
/** public function __construct(
* @var Discussion public Discussion $discussion,
*/ public User $user
public $discussion; ) {
/**
* @var User
*/
public $user;
/**
* @param Discussion $discussion
* @param User $user
*/
public function __construct(Discussion $discussion, User $user)
{
$this->discussion = $discussion;
$this->user = $user;
} }
} }

View File

@ -16,17 +16,12 @@ use Flarum\Notification\NotificationSyncer;
class CreatePostWhenDiscussionIsLocked class CreatePostWhenDiscussionIsLocked
{ {
/** public function __construct(
* @var NotificationSyncer protected NotificationSyncer $notifications
*/ ) {
protected $notifications;
public function __construct(NotificationSyncer $notifications)
{
$this->notifications = $notifications;
} }
public function handle(DiscussionWasLocked $event) public function handle(DiscussionWasLocked $event): void
{ {
$post = DiscussionLockedPost::reply( $post = DiscussionLockedPost::reply(
$event->discussion->id, $event->discussion->id,

View File

@ -16,17 +16,12 @@ use Flarum\Notification\NotificationSyncer;
class CreatePostWhenDiscussionIsUnlocked class CreatePostWhenDiscussionIsUnlocked
{ {
/** public function __construct(
* @var NotificationSyncer protected NotificationSyncer $notifications
*/ ) {
protected $notifications;
public function __construct(NotificationSyncer $notifications)
{
$this->notifications = $notifications;
} }
public function handle(DiscussionWasUnlocked $event) public function handle(DiscussionWasUnlocked $event): void
{ {
$post = DiscussionLockedPost::reply( $post = DiscussionLockedPost::reply(
$event->discussion->id, $event->discussion->id,

View File

@ -15,7 +15,7 @@ use Flarum\Lock\Event\DiscussionWasUnlocked;
class SaveLockedToDatabase class SaveLockedToDatabase
{ {
public function handle(Saving $event) public function handle(Saving $event): void
{ {
if (isset($event->data['attributes']['isLocked'])) { if (isset($event->data['attributes']['isLocked'])) {
$isLocked = (bool) $event->data['attributes']['isLocked']; $isLocked = (bool) $event->data['attributes']['isLocked'];

View File

@ -9,61 +9,40 @@
namespace Flarum\Lock\Notification; namespace Flarum\Lock\Notification;
use Flarum\Database\AbstractModel;
use Flarum\Discussion\Discussion; use Flarum\Discussion\Discussion;
use Flarum\Lock\Post\DiscussionLockedPost; use Flarum\Lock\Post\DiscussionLockedPost;
use Flarum\Notification\Blueprint\BlueprintInterface; use Flarum\Notification\Blueprint\BlueprintInterface;
use Flarum\User\User;
class DiscussionLockedBlueprint implements BlueprintInterface class DiscussionLockedBlueprint implements BlueprintInterface
{ {
/** public function __construct(
* @var DiscussionLockedPost protected DiscussionLockedPost $post
*/ ) {
protected $post;
/**
* @param DiscussionLockedPost $post
*/
public function __construct(DiscussionLockedPost $post)
{
$this->post = $post;
} }
/** public function getFromUser(): ?User
* {@inheritdoc}
*/
public function getFromUser()
{ {
return $this->post->user; return $this->post->user;
} }
/** public function getSubject(): ?AbstractModel
* {@inheritdoc}
*/
public function getSubject()
{ {
return $this->post->discussion; return $this->post->discussion;
} }
/** public function getData(): array
* {@inheritdoc}
*/
public function getData()
{ {
return ['postNumber' => (int) $this->post->number]; return ['postNumber' => (int) $this->post->number];
} }
/** public static function getType(): string
* {@inheritdoc}
*/
public static function getType()
{ {
return 'discussionLocked'; return 'discussionLocked';
} }
/** public static function getSubjectModel(): string
* {@inheritdoc}
*/
public static function getSubjectModel()
{ {
return Discussion::class; return Discussion::class;
} }

View File

@ -16,15 +16,9 @@ use Flarum\Post\Post;
class DiscussionLockedPost extends AbstractEventPost implements MergeableInterface class DiscussionLockedPost extends AbstractEventPost implements MergeableInterface
{ {
/** public static string $type = 'discussionLocked';
* {@inheritdoc}
*/
public static $type = 'discussionLocked';
/** public function saveAfter(Post $previous = null): static
* {@inheritdoc}
*/
public function saveAfter(Post $previous = null)
{ {
// If the previous post is another 'discussion locked' post, and it's // If the previous post is another 'discussion locked' post, and it's
// by the same user, then we can merge this post into it. If we find // by the same user, then we can merge this post into it. If we find
@ -47,15 +41,7 @@ class DiscussionLockedPost extends AbstractEventPost implements MergeableInterfa
return $this; return $this;
} }
/** public static function reply(int $discussionId, int $userId, bool $isLocked): static
* Create a new instance in reply to a discussion.
*
* @param int $discussionId
* @param int $userId
* @param bool $isLocked
* @return static
*/
public static function reply($discussionId, $userId, $isLocked)
{ {
$post = new static; $post = new static;
@ -67,14 +53,8 @@ class DiscussionLockedPost extends AbstractEventPost implements MergeableInterfa
return $post; return $post;
} }
/** public static function buildContent(bool $isLocked): array
* Build the content attribute.
*
* @param bool $isLocked Whether or not the discussion is locked.
* @return array
*/
public static function buildContent($isLocked)
{ {
return ['locked' => (bool) $isLocked]; return ['locked' => $isLocked];
} }
} }

View File

@ -17,14 +17,14 @@ use Illuminate\Database\Query\Builder;
class LockedFilterGambit extends AbstractRegexGambit implements FilterInterface class LockedFilterGambit extends AbstractRegexGambit implements FilterInterface
{ {
protected function getGambitPattern() protected function getGambitPattern(): string
{ {
return 'is:locked'; return 'is:locked';
} }
protected function conditions(SearchState $searchState, array $matches, $negate) protected function conditions(SearchState $search, array $matches, bool $negate): void
{ {
$this->constrain($searchState->getQuery(), $negate); $this->constrain($search->getQuery(), $negate);
} }
public function getFilterKey(): string public function getFilterKey(): string
@ -32,12 +32,12 @@ class LockedFilterGambit extends AbstractRegexGambit implements FilterInterface
return 'locked'; return 'locked';
} }
public function filter(FilterState $filterState, $filterValue, bool $negate) public function filter(FilterState $filterState, string|array $filterValue, bool $negate): void
{ {
$this->constrain($filterState->getQuery(), $negate); $this->constrain($filterState->getQuery(), $negate);
} }
protected function constrain(Builder $query, bool $negate) protected function constrain(Builder $query, bool $negate): void
{ {
$query->where('is_locked', ! $negate); $query->where('is_locked', ! $negate);
} }

View File

@ -80,8 +80,8 @@ return [
'posts.mentionsUsers', 'posts.mentionsPosts', 'posts.mentionsPosts.user', 'posts.mentionsUsers', 'posts.mentionsPosts', 'posts.mentionsPosts.user',
'posts.mentionsGroups' 'posts.mentionsGroups'
]) ])
->loadWhere('posts.mentionedBy', [LoadMentionedByRelationship::class, 'mutateRelation']) ->loadWhere('posts.mentionedBy', LoadMentionedByRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadMentionedByRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadMentionedByRelationship::countRelation(...)),
(new Extend\ApiController(Controller\ListDiscussionsController::class)) (new Extend\ApiController(Controller\ListDiscussionsController::class))
->load([ ->load([
@ -93,14 +93,14 @@ return [
->addInclude(['mentionedBy', 'mentionedBy.user', 'mentionedBy.discussion']) ->addInclude(['mentionedBy', 'mentionedBy.user', 'mentionedBy.discussion'])
// We wouldn't normally need to eager load on a single model, // We wouldn't normally need to eager load on a single model,
// but we do so here for visibility scoping. // but we do so here for visibility scoping.
->loadWhere('mentionedBy', [LoadMentionedByRelationship::class, 'mutateRelation']) ->loadWhere('mentionedBy', LoadMentionedByRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadMentionedByRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadMentionedByRelationship::countRelation(...)),
(new Extend\ApiController(Controller\ListPostsController::class)) (new Extend\ApiController(Controller\ListPostsController::class))
->addInclude(['mentionedBy', 'mentionedBy.user', 'mentionedBy.discussion']) ->addInclude(['mentionedBy', 'mentionedBy.user', 'mentionedBy.discussion'])
->load(['mentionsUsers', 'mentionsPosts', 'mentionsPosts.user', 'mentionsGroups']) ->load(['mentionsUsers', 'mentionsPosts', 'mentionsPosts.user', 'mentionsGroups'])
->loadWhere('mentionedBy', [LoadMentionedByRelationship::class, 'mutateRelation']) ->loadWhere('mentionedBy', LoadMentionedByRelationship::mutateRelation(...))
->prepareDataForSerialization([LoadMentionedByRelationship::class, 'countRelation']), ->prepareDataForSerialization(LoadMentionedByRelationship::countRelation(...)),
(new Extend\Settings) (new Extend\Settings)
->serializeToForum('allowUsernameMentionFormat', 'flarum-mentions.allow_username_format', 'boolval'), ->serializeToForum('allowUsernameMentionFormat', 'flarum-mentions.allow_username_format', 'boolval'),

View File

@ -9,6 +9,7 @@
namespace Flarum\Mentions\Api; namespace Flarum\Mentions\Api;
use Flarum\Api\Controller\AbstractSerializeController;
use Flarum\Discussion\Discussion; use Flarum\Discussion\Discussion;
use Flarum\Http\RequestUtil; use Flarum\Http\RequestUtil;
use Flarum\Post\Post; use Flarum\Post\Post;
@ -22,13 +23,13 @@ use Psr\Http\Message\ServerRequestInterface;
*/ */
class LoadMentionedByRelationship class LoadMentionedByRelationship
{ {
public static $maxMentionedBy = 4; public static int $maxMentionedBy = 4;
public static function mutateRelation(BelongsToMany $query, ServerRequestInterface $request) public static function mutateRelation(BelongsToMany $query, ServerRequestInterface $request): void
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);
return $query $query
->with(['mentionsPosts', 'mentionsPosts.user', 'mentionsUsers']) ->with(['mentionsPosts', 'mentionsPosts.user', 'mentionsUsers'])
->whereVisibleTo($actor) ->whereVisibleTo($actor)
->oldest() ->oldest()
@ -41,13 +42,15 @@ class LoadMentionedByRelationship
/** /**
* Called using the @see ApiController::prepareDataForSerialization extender. * Called using the @see ApiController::prepareDataForSerialization extender.
*/ */
public static function countRelation($controller, $data, ServerRequestInterface $request): void public static function countRelation(AbstractSerializeController $controller, mixed $data, ServerRequestInterface $request): array
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);
$loadable = null; $loadable = null;
if ($data instanceof Discussion) { if ($data instanceof Discussion) {
$loadable = $data->newCollection($data->posts)->filter(function ($post) { // We do this because the ShowDiscussionController manipulates the posts
// in a way that some of them are just ids.
$loadable = $data->posts->filter(function ($post) {
return $post instanceof Post; return $post instanceof Post;
}); });
} elseif ($data instanceof Collection) { } elseif ($data instanceof Collection) {
@ -63,5 +66,7 @@ class LoadMentionedByRelationship
} }
]); ]);
} }
return [];
} }
} }

View File

@ -30,23 +30,13 @@ class ConfigureMentions
public const GROUP_MENTION_WITH_NAME_REGEX = '/\B@["“](?<groupname>((?!"#[a-z]{0,3}[0-9]+).)+)["|”]#g(?<id>[0-9]+)\b/'; public const GROUP_MENTION_WITH_NAME_REGEX = '/\B@["“](?<groupname>((?!"#[a-z]{0,3}[0-9]+).)+)["|”]#g(?<id>[0-9]+)\b/';
public const TAG_MENTION_WITH_SLUG_REGEX = '/(?:[^“"]|^)\B#(?<slug>[-_\p{L}\p{N}\p{M}]+)\b/ui'; public const TAG_MENTION_WITH_SLUG_REGEX = '/(?:[^“"]|^)\B#(?<slug>[-_\p{L}\p{N}\p{M}]+)\b/ui';
/** public function __construct(
* @var UrlGenerator protected UrlGenerator $url,
*/ protected ExtensionManager $extensions
protected $url; ) {
/**
* @var ExtensionManager
*/
protected $extensions;
public function __construct(UrlGenerator $url, ExtensionManager $extensions)
{
$this->url = $url;
$this->extensions = $extensions;
} }
public function __invoke(Configurator $config) public function __invoke(Configurator $config): void
{ {
$this->configureUserMentions($config); $this->configureUserMentions($config);
$this->configurePostMentions($config); $this->configurePostMentions($config);

View File

@ -22,7 +22,7 @@ class MentionedFilter implements FilterInterface
return 'mentioned'; return 'mentioned';
} }
public function filter(FilterState $filterState, $filterValue, bool $negate) public function filter(FilterState $filterState, string|array $filterValue, bool $negate): void
{ {
$mentionedId = $this->asInt($filterValue); $mentionedId = $this->asInt($filterValue);

View File

@ -19,7 +19,7 @@ class MentionedPostFilter implements FilterInterface
return 'mentionedPost'; return 'mentionedPost';
} }
public function filter(FilterState $filterState, string $filterValue, bool $negate) public function filter(FilterState $filterState, string|array $filterValue, bool $negate): void
{ {
$mentionedId = trim($filterValue, '"'); $mentionedId = trim($filterValue, '"');

View File

@ -20,38 +20,15 @@ use s9e\TextFormatter\Parser;
class EagerLoadMentionedModels class EagerLoadMentionedModels
{ {
/** public function __construct(
* @var ExtensionManager protected ExtensionManager $extensions,
*/ protected PostRepository $posts,
protected $extensions; protected GroupRepository $groups,
protected TagRepository $tags
/** ) {
* @var PostRepository
*/
protected $posts;
/**
* @var GroupRepository
*/
protected $groups;
/**
* @var TagRepository
*/
protected $tags;
public function __construct(ExtensionManager $extensions, PostRepository $posts, GroupRepository $groups, TagRepository $tags)
{
$this->extensions = $extensions;
$this->posts = $posts;
$this->groups = $groups;
$this->tags = $tags;
} }
/** public function __invoke(Parser $parser, mixed $context, string $text, ?User $actor): string
* @param mixed|\Flarum\Post\CommentPost|null $context
*/
public function __invoke(Parser $parser, $context, string $text, ?User $actor): string
{ {
$callables = $this->getEagerLoaders(); $callables = $this->getEagerLoaders();

View File

@ -10,32 +10,19 @@
namespace Flarum\Mentions\Formatter; namespace Flarum\Mentions\Formatter;
use Flarum\Group\Group; use Flarum\Group\Group;
use Flarum\Locale\TranslatorInterface;
use Flarum\Post\Post; use Flarum\Post\Post;
use s9e\TextFormatter\Renderer; use s9e\TextFormatter\Renderer;
use s9e\TextFormatter\Utils; use s9e\TextFormatter\Utils;
use Symfony\Contracts\Translation\TranslatorInterface;
class FormatGroupMentions class FormatGroupMentions
{ {
/** public function __construct(
* @var TranslatorInterface private readonly TranslatorInterface $translator
*/ ) {
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
} }
/** public function __invoke(Renderer $renderer, mixed $context, string $xml): string
* Configure rendering for group mentions.
*
* @param \s9e\TextFormatter\Renderer $renderer
* @param mixed $context
* @param string $xml
* @return string
*/
public function __invoke(Renderer $renderer, $context, string $xml): string
{ {
return Utils::replaceAttributes($xml, 'GROUPMENTION', function ($attributes) use ($context) { return Utils::replaceAttributes($xml, 'GROUPMENTION', function ($attributes) use ($context) {
$group = (($context && isset($context->getRelations()['mentionsGroups'])) || $context instanceof Post) $group = (($context && isset($context->getRelations()['mentionsGroups'])) || $context instanceof Post)

View File

@ -9,33 +9,19 @@
namespace Flarum\Mentions\Formatter; namespace Flarum\Mentions\Formatter;
use Flarum\Locale\TranslatorInterface;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use s9e\TextFormatter\Renderer; use s9e\TextFormatter\Renderer;
use s9e\TextFormatter\Utils; use s9e\TextFormatter\Utils;
use Symfony\Contracts\Translation\TranslatorInterface;
class FormatPostMentions class FormatPostMentions
{ {
/** public function __construct(
* @var TranslatorInterface private readonly TranslatorInterface $translator
*/ ) {
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
} }
/** public function __invoke(Renderer $renderer, mixed $context, ?string $xml, Request $request = null): string
* Configure rendering for post mentions.
*
* @param \s9e\TextFormatter\Renderer $renderer
* @param mixed $context
* @param string|null $xml
* @param \Psr\Http\Message\ServerRequestInterface $request
* @return string
*/
public function __invoke(Renderer $renderer, $context, $xml, Request $request = null)
{ {
$post = $context; $post = $context;

View File

@ -17,7 +17,7 @@ use s9e\TextFormatter\Utils;
class FormatTagMentions class FormatTagMentions
{ {
public function __invoke(Renderer $renderer, $context, ?string $xml, Request $request = null): string public function __invoke(Renderer $renderer, mixed $context, ?string $xml, Request $request = null): string
{ {
return Utils::replaceAttributes($xml, 'TAGMENTION', function ($attributes) use ($context) { return Utils::replaceAttributes($xml, 'TAGMENTION', function ($attributes) use ($context) {
/** @var Tag|null $tag */ /** @var Tag|null $tag */

View File

@ -10,39 +10,21 @@
namespace Flarum\Mentions\Formatter; namespace Flarum\Mentions\Formatter;
use Flarum\Http\SlugManager; use Flarum\Http\SlugManager;
use Flarum\Locale\TranslatorInterface;
use Flarum\Post\Post; use Flarum\Post\Post;
use Flarum\User\User; use Flarum\User\User;
use s9e\TextFormatter\Renderer; use s9e\TextFormatter\Renderer;
use s9e\TextFormatter\Utils; use s9e\TextFormatter\Utils;
use Symfony\Contracts\Translation\TranslatorInterface;
class FormatUserMentions class FormatUserMentions
{ {
/** public function __construct(
* @var SlugManager private readonly TranslatorInterface $translator,
*/ private readonly SlugManager $slugManager
private $slugManager; ) {
/**
* @var TranslatorInterface
*/
private $translator;
public function __construct(SlugManager $slugManager, TranslatorInterface $translator)
{
$this->slugManager = $slugManager;
$this->translator = $translator;
} }
/** public function __invoke(Renderer $renderer, mixed $context, string $xml): string
* Configure rendering for user mentions.
*
* @param \s9e\TextFormatter\Renderer $renderer
* @param mixed $context
* @param string $xml
* @return string $xml to be rendered
*/
public function __invoke(Renderer $renderer, $context, string $xml)
{ {
return Utils::replaceAttributes($xml, 'USERMENTION', function ($attributes) use ($context) { return Utils::replaceAttributes($xml, 'USERMENTION', function ($attributes) use ($context) {
$user = (($context && isset($context->getRelations()['mentionsUsers'])) || $context instanceof Post) $user = (($context && isset($context->getRelations()['mentionsUsers'])) || $context instanceof Post)

View File

@ -9,42 +9,25 @@
namespace Flarum\Mentions\Formatter; namespace Flarum\Mentions\Formatter;
use Flarum\Locale\TranslatorInterface;
use s9e\TextFormatter\Utils; use s9e\TextFormatter\Utils;
use Symfony\Contracts\Translation\TranslatorInterface;
class UnparsePostMentions class UnparsePostMentions
{ {
/** public function __construct(
* @var TranslatorInterface private readonly TranslatorInterface $translator
*/ ) {
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
} }
/** public function __invoke(mixed $context, string $xml): string
* Configure rendering for user mentions.
*
* @param string $xml
* @param mixed $context
* @return string $xml to be unparsed
*/
public function __invoke($context, string $xml)
{ {
$xml = $this->updatePostMentionTags($context, $xml); return $this->unparsePostMentionTags(
$xml = $this->unparsePostMentionTags($xml); $this->updatePostMentionTags($context, $xml)
);
return $xml;
} }
/** /**
* Updates XML post mention tags before unparsing so that unparsing uses new display names. * Updates XML post mention tags before unparsing so that unparsing uses new display names.
*
* @param mixed $context
* @param string $xml : Parsed text.
* @return string $xml : Updated XML tags;
*/ */
protected function updatePostMentionTags($context, string $xml): string protected function updatePostMentionTags($context, string $xml): string
{ {
@ -74,9 +57,6 @@ class UnparsePostMentions
/** /**
* Transforms post mention tags from XML to raw unparsed content with updated format and display name. * Transforms post mention tags from XML to raw unparsed content with updated format and display name.
*
* @param string $xml : Parsed text.
* @return string : Unparsed text.
*/ */
protected function unparsePostMentionTags(string $xml): string protected function unparsePostMentionTags(string $xml): string
{ {

View File

@ -15,29 +15,17 @@ use s9e\TextFormatter\Utils;
class UnparseTagMentions class UnparseTagMentions
{ {
/** public function __invoke(mixed $context, string $xml): string
* Configure rendering for user mentions.
*
* @param string $xml
* @param mixed $context
* @return string $xml to be unparsed
*/
public function __invoke($context, string $xml)
{ {
$xml = $this->updateTagMentionTags($context, $xml); return $this->unparseTagMentionTags(
$xml = $this->unparseTagMentionTags($xml); $this->updateTagMentionTags($context, $xml)
);
return $xml;
} }
/** /**
* Updates XML user mention tags before unparsing so that unparsing uses new tag names. * Updates XML user mention tags before unparsing so that unparsing uses new tag names.
*
* @param mixed $context
* @param string $xml : Parsed text.
* @return string $xml : Updated XML tags;
*/ */
protected function updateTagMentionTags($context, string $xml): string protected function updateTagMentionTags(mixed $context, string $xml): string
{ {
return Utils::replaceAttributes($xml, 'TAGMENTION', function (array $attributes) use ($context) { return Utils::replaceAttributes($xml, 'TAGMENTION', function (array $attributes) use ($context) {
/** @var Tag|null $tag */ /** @var Tag|null $tag */
@ -56,9 +44,6 @@ class UnparseTagMentions
/** /**
* Transforms tag mention tags from XML to raw unparsed content with updated name. * Transforms tag mention tags from XML to raw unparsed content with updated name.
*
* @param string $xml : Parsed text.
* @return string : Unparsed text.
*/ */
protected function unparseTagMentionTags(string $xml): string protected function unparseTagMentionTags(string $xml): string
{ {

View File

@ -9,46 +9,29 @@
namespace Flarum\Mentions\Formatter; namespace Flarum\Mentions\Formatter;
use Flarum\Locale\TranslatorInterface;
use Flarum\Post\Post; use Flarum\Post\Post;
use Flarum\User\User; use Flarum\User\User;
use s9e\TextFormatter\Utils; use s9e\TextFormatter\Utils;
use Symfony\Contracts\Translation\TranslatorInterface;
class UnparseUserMentions class UnparseUserMentions
{ {
/** public function __construct(
* @var TranslatorInterface private readonly TranslatorInterface $translator
*/ ) {
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
} }
/** public function __invoke(mixed $context, string $xml): string
* Configure rendering for user mentions.
*
* @param string $xml
* @param mixed $context
* @return string $xml to be unparsed
*/
public function __invoke($context, string $xml)
{ {
$xml = $this->updateUserMentionTags($context, $xml); return $this->unparseUserMentionTags(
$xml = $this->unparseUserMentionTags($xml); $this->updateUserMentionTags($context, $xml)
);
return $xml;
} }
/** /**
* Updates XML user mention tags before unparsing so that unparsing uses new display names. * Updates XML user mention tags before unparsing so that unparsing uses new display names.
*
* @param mixed $context
* @param string $xml : Parsed text.
* @return string $xml : Updated XML tags;
*/ */
protected function updateUserMentionTags($context, string $xml): string protected function updateUserMentionTags(mixed $context, string $xml): string
{ {
return Utils::replaceAttributes($xml, 'USERMENTION', function ($attributes) use ($context) { return Utils::replaceAttributes($xml, 'USERMENTION', function ($attributes) use ($context) {
$user = (($context && isset($context->getRelations()['mentionsUsers'])) || $context instanceof Post) $user = (($context && isset($context->getRelations()['mentionsUsers'])) || $context instanceof Post)
@ -71,9 +54,6 @@ class UnparseUserMentions
/** /**
* Transforms user mention tags from XML to raw unparsed content with updated format and display name. * Transforms user mention tags from XML to raw unparsed content with updated format and display name.
*
* @param string $xml : Parsed text.
* @return string : Unparsed text.
*/ */
protected function unparseUserMentionTags(string $xml): string protected function unparseUserMentionTags(string $xml): string
{ {

View File

@ -20,37 +20,14 @@ use Flarum\User\User;
class SendMentionsNotificationsJob extends AbstractJob class SendMentionsNotificationsJob extends AbstractJob
{ {
/** private NotificationSyncer $notifications;
* @var CommentPost
*/
protected $post;
/** public function __construct(
* @var array protected CommentPost $post,
*/ protected array $userMentions,
protected $userMentions; protected array $postMentions,
protected array $groupMentions
/** ) {
* @var array
*/
protected $postMentions;
/**
* @var array
*/
protected $groupMentions;
/**
* @var NotificationSyncer
*/
private $notifications;
public function __construct(CommentPost $post, array $userMentions, array $postMentions, array $groupMentions)
{
$this->post = $post;
$this->userMentions = $userMentions;
$this->postMentions = $postMentions;
$this->groupMentions = $groupMentions;
} }
public function handle(NotificationSyncer $notifications): void public function handle(NotificationSyncer $notifications): void
@ -62,7 +39,7 @@ class SendMentionsNotificationsJob extends AbstractJob
$this->notifyAboutGroupMentions($this->post, $this->groupMentions); $this->notifyAboutGroupMentions($this->post, $this->groupMentions);
} }
protected function notifyAboutUserMentions(Post $post, array $mentioned) protected function notifyAboutUserMentions(Post $post, array $mentioned): void
{ {
$users = User::whereIn('id', $mentioned) $users = User::whereIn('id', $mentioned)
->with('groups') ->with('groups')
@ -75,7 +52,7 @@ class SendMentionsNotificationsJob extends AbstractJob
$this->notifications->sync(new UserMentionedBlueprint($post), $users); $this->notifications->sync(new UserMentionedBlueprint($post), $users);
} }
protected function notifyAboutPostMentions(Post $reply, array $mentioned) protected function notifyAboutPostMentions(Post $reply, array $mentioned): void
{ {
$posts = Post::with('user') $posts = Post::with('user')
->whereIn('id', $mentioned) ->whereIn('id', $mentioned)
@ -91,7 +68,7 @@ class SendMentionsNotificationsJob extends AbstractJob
} }
} }
protected function notifyAboutGroupMentions(Post $post, array $mentioned) protected function notifyAboutGroupMentions(Post $post, array $mentioned): void
{ {
$users = User::whereHas('groups', function ($query) use ($mentioned) { $users = User::whereHas('groups', function ($query) use ($mentioned) {
$query->whereIn('groups.id', $mentioned); $query->whereIn('groups.id', $mentioned);

View File

@ -17,26 +17,13 @@ use Flarum\Post\Event\Hidden;
class UpdateMentionsMetadataWhenInvisible class UpdateMentionsMetadataWhenInvisible
{ {
/** public function __construct(
* @var NotificationSyncer protected NotificationSyncer $notifications,
*/ protected ExtensionManager $extensions
protected $notifications; ) {
/**
* @var ExtensionManager
*/
protected $extensions;
public function __construct(NotificationSyncer $notifications, ExtensionManager $extensions)
{
$this->notifications = $notifications;
$this->extensions = $extensions;
} }
/** public function handle(Deleted|Hidden $event): void
* @param Deleted|Hidden $event
*/
public function handle($event)
{ {
// Remove user mentions // Remove user mentions
$event->post->mentionsUsers()->sync([]); $event->post->mentionsUsers()->sync([]);

View File

@ -22,26 +22,13 @@ use s9e\TextFormatter\Utils;
class UpdateMentionsMetadataWhenVisible class UpdateMentionsMetadataWhenVisible
{ {
/** public function __construct(
* @var ExtensionManager protected ExtensionManager $extensions,
*/ protected Queue $queue
protected $extensions; ) {
/**
* @var Queue
*/
protected $queue;
public function __construct(ExtensionManager $extensions, Queue $queue)
{
$this->extensions = $extensions;
$this->queue = $queue;
} }
/** public function handle(Restored|Revised|Posted|PostWasApproved $event): void
* @param Posted|Restored|Revised|PostWasApproved $event
*/
public function handle($event)
{ {
if (! $event->post instanceof CommentPost) { if (! $event->post instanceof CommentPost) {
return; return;
@ -74,25 +61,25 @@ class UpdateMentionsMetadataWhenVisible
$this->queue->push(new SendMentionsNotificationsJob($event->post, $userMentions, $postMentions, $groupMentions)); $this->queue->push(new SendMentionsNotificationsJob($event->post, $userMentions, $postMentions, $groupMentions));
} }
protected function syncUserMentions(Post $post, array $mentioned) protected function syncUserMentions(Post $post, array $mentioned): void
{ {
$post->mentionsUsers()->sync($mentioned); $post->mentionsUsers()->sync($mentioned);
$post->unsetRelation('mentionsUsers'); $post->unsetRelation('mentionsUsers');
} }
protected function syncPostMentions(Post $reply, array $mentioned) protected function syncPostMentions(Post $reply, array $mentioned): void
{ {
$reply->mentionsPosts()->sync($mentioned); $reply->mentionsPosts()->sync($mentioned);
$reply->unsetRelation('mentionsPosts'); $reply->unsetRelation('mentionsPosts');
} }
protected function syncGroupMentions(Post $post, array $mentioned) protected function syncGroupMentions(Post $post, array $mentioned): void
{ {
$post->mentionsGroups()->sync($mentioned); $post->mentionsGroups()->sync($mentioned);
$post->unsetRelation('mentionsGroups'); $post->unsetRelation('mentionsGroups');
} }
protected function syncTagMentions(Post $post, array $mentioned) protected function syncTagMentions(Post $post, array $mentioned): void
{ {
$post->mentionsTags()->sync($mentioned); $post->mentionsTags()->sync($mentioned);
$post->unsetRelation('mentionsTags'); $post->unsetRelation('mentionsTags');

View File

@ -9,61 +9,41 @@
namespace Flarum\Mentions\Notification; namespace Flarum\Mentions\Notification;
use Flarum\Database\AbstractModel;
use Flarum\Locale\TranslatorInterface;
use Flarum\Notification\Blueprint\BlueprintInterface; use Flarum\Notification\Blueprint\BlueprintInterface;
use Flarum\Notification\MailableInterface; use Flarum\Notification\MailableInterface;
use Flarum\Post\Post; use Flarum\Post\Post;
use Symfony\Contracts\Translation\TranslatorInterface; use Flarum\User\User;
class GroupMentionedBlueprint implements BlueprintInterface, MailableInterface class GroupMentionedBlueprint implements BlueprintInterface, MailableInterface
{ {
/** public function __construct(
* @var Post public Post $post
*/ ) {
public $post;
/**
* @param Post $post
*/
public function __construct(Post $post)
{
$this->post = $post;
} }
/** public function getSubject(): ?AbstractModel
* {@inheritdoc}
*/
public function getSubject()
{ {
return $this->post; return $this->post;
} }
/** public function getFromUser(): ?User
* {@inheritdoc}
*/
public function getFromUser()
{ {
return $this->post->user; return $this->post->user;
} }
/** public function getData(): mixed
* {@inheritdoc}
*/
public function getData()
{ {
return null;
} }
/** public function getEmailView(): string|array
* {@inheritdoc}
*/
public function getEmailView()
{ {
return ['text' => 'flarum-mentions::emails.groupMentioned']; return ['text' => 'flarum-mentions::emails.groupMentioned'];
} }
/** public function getEmailSubject(TranslatorInterface $translator): string
* {@inheritdoc}
*/
public function getEmailSubject(TranslatorInterface $translator)
{ {
return $translator->trans('flarum-mentions.email.group_mentioned.subject', [ return $translator->trans('flarum-mentions.email.group_mentioned.subject', [
'{mentioner_display_name}' => $this->post->user->display_name, '{mentioner_display_name}' => $this->post->user->display_name,
@ -71,18 +51,12 @@ class GroupMentionedBlueprint implements BlueprintInterface, MailableInterface
]); ]);
} }
/** public static function getType(): string
* {@inheritdoc}
*/
public static function getType()
{ {
return 'groupMentioned'; return 'groupMentioned';
} }
/** public static function getSubjectModel(): string
* {@inheritdoc}
*/
public static function getSubjectModel()
{ {
return Post::class; return Post::class;
} }

View File

@ -9,69 +9,42 @@
namespace Flarum\Mentions\Notification; namespace Flarum\Mentions\Notification;
use Flarum\Database\AbstractModel;
use Flarum\Locale\TranslatorInterface;
use Flarum\Notification\Blueprint\BlueprintInterface; use Flarum\Notification\Blueprint\BlueprintInterface;
use Flarum\Notification\MailableInterface; use Flarum\Notification\MailableInterface;
use Flarum\Post\Post; use Flarum\Post\Post;
use Symfony\Contracts\Translation\TranslatorInterface; use Flarum\User\User;
class PostMentionedBlueprint implements BlueprintInterface, MailableInterface class PostMentionedBlueprint implements BlueprintInterface, MailableInterface
{ {
/** public function __construct(
* @var Post public Post $post,
*/ public Post $reply
public $post; ) {
/**
* @var Post
*/
public $reply;
/**
* @param Post $post
* @param Post $reply
*/
public function __construct(Post $post, Post $reply)
{
$this->post = $post;
$this->reply = $reply;
} }
/** public function getSubject(): ?AbstractModel
* {@inheritdoc}
*/
public function getSubject()
{ {
return $this->post; return $this->post;
} }
/** public function getFromUser(): ?User
* {@inheritdoc}
*/
public function getFromUser()
{ {
return $this->reply->user; return $this->reply->user;
} }
/** public function getData(): array
* {@inheritdoc}
*/
public function getData()
{ {
return ['replyNumber' => (int) $this->reply->number]; return ['replyNumber' => (int) $this->reply->number];
} }
/** public function getEmailView(): string|array
* {@inheritdoc}
*/
public function getEmailView()
{ {
return ['text' => 'flarum-mentions::emails.postMentioned']; return ['text' => 'flarum-mentions::emails.postMentioned'];
} }
/** public function getEmailSubject(TranslatorInterface $translator): string
* {@inheritdoc}
*/
public function getEmailSubject(TranslatorInterface $translator)
{ {
return $translator->trans('flarum-mentions.email.post_mentioned.subject', [ return $translator->trans('flarum-mentions.email.post_mentioned.subject', [
'{replier_display_name}' => $this->reply->user->display_name, '{replier_display_name}' => $this->reply->user->display_name,
@ -79,18 +52,12 @@ class PostMentionedBlueprint implements BlueprintInterface, MailableInterface
]); ]);
} }
/** public static function getType(): string
* {@inheritdoc}
*/
public static function getType()
{ {
return 'postMentioned'; return 'postMentioned';
} }
/** public static function getSubjectModel(): string
* {@inheritdoc}
*/
public static function getSubjectModel()
{ {
return Post::class; return Post::class;
} }

View File

@ -9,61 +9,41 @@
namespace Flarum\Mentions\Notification; namespace Flarum\Mentions\Notification;
use Flarum\Database\AbstractModel;
use Flarum\Locale\TranslatorInterface;
use Flarum\Notification\Blueprint\BlueprintInterface; use Flarum\Notification\Blueprint\BlueprintInterface;
use Flarum\Notification\MailableInterface; use Flarum\Notification\MailableInterface;
use Flarum\Post\Post; use Flarum\Post\Post;
use Symfony\Contracts\Translation\TranslatorInterface; use Flarum\User\User;
class UserMentionedBlueprint implements BlueprintInterface, MailableInterface class UserMentionedBlueprint implements BlueprintInterface, MailableInterface
{ {
/** public function __construct(
* @var Post public Post $post
*/ ) {
public $post;
/**
* @param Post $post
*/
public function __construct(Post $post)
{
$this->post = $post;
} }
/** public function getSubject(): ?AbstractModel
* {@inheritdoc}
*/
public function getSubject()
{ {
return $this->post; return $this->post;
} }
/** public function getFromUser(): ?User
* {@inheritdoc}
*/
public function getFromUser()
{ {
return $this->post->user; return $this->post->user;
} }
/** public function getData(): mixed
* {@inheritdoc}
*/
public function getData()
{ {
return null;
} }
/** public function getEmailView(): string|array
* {@inheritdoc}
*/
public function getEmailView()
{ {
return ['text' => 'flarum-mentions::emails.userMentioned']; return ['text' => 'flarum-mentions::emails.userMentioned'];
} }
/** public function getEmailSubject(TranslatorInterface $translator): string
* {@inheritdoc}
*/
public function getEmailSubject(TranslatorInterface $translator)
{ {
return $translator->trans('flarum-mentions.email.user_mentioned.subject', [ return $translator->trans('flarum-mentions.email.user_mentioned.subject', [
'{mentioner_display_name}' => $this->post->user->display_name, '{mentioner_display_name}' => $this->post->user->display_name,
@ -71,18 +51,12 @@ class UserMentionedBlueprint implements BlueprintInterface, MailableInterface
]); ]);
} }
/** public static function getType(): string
* {@inheritdoc}
*/
public static function getType()
{ {
return 'userMentioned'; return 'userMentioned';
} }
/** public static function getSubjectModel(): string
* {@inheritdoc}
*/
public static function getSubjectModel()
{ {
return Post::class; return Post::class;
} }

View File

@ -15,21 +15,11 @@ use Flarum\User\User;
class UserPolicy extends AbstractPolicy class UserPolicy extends AbstractPolicy
{ {
/** public function __construct(
* @var SettingsRepositoryInterface protected SettingsRepositoryInterface $settings
*/ ) {
protected $settings;
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
} }
/**
* @param User $actor
* @param User $user
* @return bool|null
*/
public function editNickname(User $actor, User $user) public function editNickname(User $actor, User $user)
{ {
if ($actor->isGuest() && ! $user->exists && $this->settings->get('flarum-nicknames.set_on_registration')) { if ($actor->isGuest() && ! $user->exists && $this->settings->get('flarum-nicknames.set_on_registration')) {

View File

@ -9,29 +9,20 @@
namespace Flarum\Nicknames; namespace Flarum\Nicknames;
use Flarum\Locale\TranslatorInterface;
use Flarum\Settings\SettingsRepositoryInterface; use Flarum\Settings\SettingsRepositoryInterface;
use Flarum\User\UserValidator;
use Illuminate\Validation\Validator; use Illuminate\Validation\Validator;
use Symfony\Contracts\Translation\TranslatorInterface;
class AddNicknameValidation class AddNicknameValidation
{ {
/** public function __construct(
* @var SettingsRepositoryInterface protected SettingsRepositoryInterface $settings,
*/ protected TranslatorInterface $translator
protected $settings; ) {
/**
* @var TranslatorInterface
*/
protected $translator;
public function __construct(SettingsRepositoryInterface $settings, TranslatorInterface $translator)
{
$this->settings = $settings;
$this->translator = $translator;
} }
public function __invoke($flarumValidator, Validator $validator) public function __invoke(UserValidator $flarumValidator, Validator $validator): void
{ {
$idSuffix = $flarumValidator->getUser() ? ','.$flarumValidator->getUser()->id : ''; $idSuffix = $flarumValidator->getUser() ? ','.$flarumValidator->getUser()->id : '';
$rules = $validator->getRules(); $rules = $validator->getRules();

View File

@ -16,6 +16,6 @@ class NicknameDriver implements DriverInterface
{ {
public function displayName(User $user): string public function displayName(User $user): string
{ {
return $user->nickname ? $user->nickname : $user->username; return $user->nickname ?? $user->username;
} }
} }

View File

@ -19,27 +19,16 @@ namespace Flarum\Nicknames;
use Flarum\Search\GambitInterface; use Flarum\Search\GambitInterface;
use Flarum\Search\SearchState; use Flarum\Search\SearchState;
use Flarum\User\UserRepository; use Flarum\User\UserRepository;
use Illuminate\Database\Eloquent\Builder;
class NicknameFullTextGambit implements GambitInterface class NicknameFullTextGambit implements GambitInterface
{ {
/** public function __construct(
* @var UserRepository protected UserRepository $users
*/ ) {
protected $users;
/**
* @param \Flarum\User\UserRepository $users
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
} }
/** private function getUserSearchSubQuery(string $searchValue): Builder
* @param $searchValue
* @return \Illuminate\Database\Eloquent\Builder
*/
private function getUserSearchSubQuery($searchValue)
{ {
return $this->users return $this->users
->query() ->query()
@ -48,15 +37,12 @@ class NicknameFullTextGambit implements GambitInterface
->orWhere('nickname', 'like', "{$searchValue}%"); ->orWhere('nickname', 'like', "{$searchValue}%");
} }
/** public function apply(SearchState $search, string $bit): bool
* {@inheritdoc}
*/
public function apply(SearchState $search, $searchValue)
{ {
$search->getQuery() $search->getQuery()
->whereIn( ->whereIn(
'id', 'id',
$this->getUserSearchSubQuery($searchValue) $this->getUserSearchSubQuery($bit)
); );
return true; return true;

View File

@ -15,17 +15,12 @@ use Illuminate\Support\Arr;
class SaveNicknameToDatabase class SaveNicknameToDatabase
{ {
/** public function __construct(
* @var SettingsRepositoryInterface protected SettingsRepositoryInterface $settings
*/ ) {
protected $settings;
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
} }
public function handle(Saving $event) public function handle(Saving $event): void
{ {
$user = $event->user; $user = $event->user;
$data = $event->data; $data = $event->data;

View File

@ -19,19 +19,11 @@ use Psr\Http\Server\RequestHandlerInterface;
class CheckForUpdatesController implements RequestHandlerInterface class CheckForUpdatesController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
/**
* @throws \Flarum\User\Exception\PermissionDeniedException
*/
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);

View File

@ -20,19 +20,11 @@ use Psr\Http\Server\RequestHandlerInterface;
class GlobalUpdateController implements RequestHandlerInterface class GlobalUpdateController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
/**
* @throws \Flarum\User\Exception\PermissionDeniedException
*/
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);

View File

@ -19,28 +19,15 @@ use Tobscure\JsonApi\Document;
class ListTasksController extends AbstractListController class ListTasksController extends AbstractListController
{ {
/** public ?string $serializer = TaskSerializer::class;
* {@inheritdoc}
*/
public $serializer = TaskSerializer::class;
/** public function __construct(
* @var UrlGenerator protected UrlGenerator $url,
*/ protected TaskRepository $repository
protected $url; ) {
/**
* @var TaskRepository
*/
protected $repository;
public function __construct(UrlGenerator $url, TaskRepository $repository)
{
$this->url = $url;
$this->repository = $repository;
} }
protected function data(ServerRequestInterface $request, Document $document) protected function data(ServerRequestInterface $request, Document $document): iterable
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);

View File

@ -21,14 +21,9 @@ use Psr\Http\Server\RequestHandlerInterface;
class MajorUpdateController implements RequestHandlerInterface class MajorUpdateController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -20,19 +20,11 @@ use Psr\Http\Server\RequestHandlerInterface;
class MinorUpdateController implements RequestHandlerInterface class MinorUpdateController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
/**
* @throws \Flarum\User\Exception\PermissionDeniedException
*/
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface
{ {
$actor = RequestUtil::getActor($request); $actor = RequestUtil::getActor($request);

View File

@ -21,14 +21,9 @@ use Psr\Http\Server\RequestHandlerInterface;
class RemoveExtensionController implements RequestHandlerInterface class RemoveExtensionController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -20,14 +20,9 @@ use Psr\Http\Server\RequestHandlerInterface;
class RequireExtensionController implements RequestHandlerInterface class RequireExtensionController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -21,14 +21,9 @@ use Psr\Http\Server\RequestHandlerInterface;
class UpdateExtensionController implements RequestHandlerInterface class UpdateExtensionController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -20,14 +20,9 @@ use Psr\Http\Server\RequestHandlerInterface;
class WhyNotController implements RequestHandlerInterface class WhyNotController implements RequestHandlerInterface
{ {
/** public function __construct(
* @var Dispatcher protected Dispatcher $bus
*/ ) {
protected $bus;
public function __construct(Dispatcher $bus)
{
$this->bus = $bus;
} }
public function handle(ServerRequestInterface $request): ResponseInterface public function handle(ServerRequestInterface $request): ResponseInterface

View File

@ -15,18 +15,12 @@ use InvalidArgumentException;
class TaskSerializer extends AbstractSerializer class TaskSerializer extends AbstractSerializer
{ {
/**
* {@inheritdoc}
*/
protected $type = 'package-manager-tasks'; protected $type = 'package-manager-tasks';
/** /**
* {@inheritdoc}
*
* @param Task $model
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
protected function getDefaultAttributes($model) protected function getDefaultAttributes(object|array $model): array
{ {
if (! ($model instanceof Task)) { if (! ($model instanceof Task)) {
throw new InvalidArgumentException( throw new InvalidArgumentException(

View File

@ -13,15 +13,8 @@ use Flarum\PackageManager\Task\Task;
abstract class AbstractActionCommand abstract class AbstractActionCommand
{ {
/** public ?Task $task = null;
* @var Task|null public ?string $package = null;
*/
public $task = null;
/**
* @var string|null
*/
public $package = null;
abstract public function getOperationName(): string; abstract public function getOperationName(): string;
} }

View File

@ -14,14 +14,9 @@ use Flarum\User\User;
class CheckForUpdates extends AbstractActionCommand class CheckForUpdates extends AbstractActionCommand
{ {
/** public function __construct(
* @var \Flarum\User\User public User $actor
*/ ) {
public $actor;
public function __construct(User $actor)
{
$this->actor = $actor;
} }
public function getOperationName(): string public function getOperationName(): string

View File

@ -16,20 +16,10 @@ use Symfony\Component\Console\Input\ArrayInput;
class CheckForUpdatesHandler class CheckForUpdatesHandler
{ {
/** public function __construct(
* @var ComposerAdapter private ComposerAdapter $composer,
*/ private LastUpdateCheck $lastUpdateCheck
protected $composer; ) {
/**
* @var \Flarum\PackageManager\Settings\LastUpdateCheck
*/
protected $lastUpdateCheck;
public function __construct(ComposerAdapter $composer, LastUpdateCheck $lastUpdateCheck)
{
$this->composer = $composer;
$this->lastUpdateCheck = $lastUpdateCheck;
} }
/** /**
@ -50,7 +40,7 @@ class CheckForUpdatesHandler
* *
* @throws ComposerCommandFailedException * @throws ComposerCommandFailedException
*/ */
public function handle(CheckForUpdates $command) public function handle(CheckForUpdates $command): array
{ {
$firstOutput = $this->runComposerCommand(false, $command); $firstOutput = $this->runComposerCommand(false, $command);
$firstOutput = json_decode($this->cleanJson($firstOutput), true); $firstOutput = json_decode($this->cleanJson($firstOutput), true);

View File

@ -14,14 +14,9 @@ use Flarum\User\User;
class GlobalUpdate extends AbstractActionCommand class GlobalUpdate extends AbstractActionCommand
{ {
/** public function __construct(
* @var \Flarum\User\User public User $actor
*/ ) {
public $actor;
public function __construct(User $actor)
{
$this->actor = $actor;
} }
public function getOperationName(): string public function getOperationName(): string

View File

@ -18,32 +18,14 @@ use Symfony\Component\Console\Input\StringInput;
class GlobalUpdateHandler class GlobalUpdateHandler
{ {
/** public function __construct(
* @var ComposerAdapter protected ComposerAdapter $composer,
*/ protected Dispatcher $events,
protected $composer; protected FlarumDispatcher $commandDispatcher
) {
/**
* @var Dispatcher
*/
protected $events;
/**
* @var FlarumDispatcher
*/
protected $commandDispatcher;
public function __construct(ComposerAdapter $composer, Dispatcher $events, FlarumDispatcher $commandDispatcher)
{
$this->composer = $composer;
$this->events = $events;
$this->commandDispatcher = $commandDispatcher;
} }
/** public function handle(GlobalUpdate $command): void
* @throws \Flarum\User\Exception\PermissionDeniedException|ComposerUpdateFailedException
*/
public function handle(GlobalUpdate $command)
{ {
$command->actor->assertAdmin(); $command->actor->assertAdmin();

View File

@ -14,20 +14,10 @@ use Flarum\User\User;
class MajorUpdate extends AbstractActionCommand class MajorUpdate extends AbstractActionCommand
{ {
/** public function __construct(
* @var \Flarum\User\User public User $actor,
*/ public bool $dryRun
public $actor; ) {
/**
* @var bool
*/
public $dryRun;
public function __construct(User $actor, bool $dryRun)
{
$this->actor = $actor;
$this->dryRun = $dryRun;
} }
public function getOperationName(): string public function getOperationName(): string

View File

@ -20,38 +20,12 @@ use Symfony\Component\Console\Input\ArrayInput;
class MajorUpdateHandler class MajorUpdateHandler
{ {
/** public function __construct(
* @var ComposerAdapter protected ComposerAdapter $composer,
*/ protected LastUpdateCheck $lastUpdateCheck,
protected $composer; protected Dispatcher $events,
protected ComposerJson $composerJson
/** ) {
* @var LastUpdateCheck
*/
protected $lastUpdateCheck;
/**
* @var Dispatcher
*/
protected $events;
/**
* @var ComposerJson
*/
protected $composerJson;
/**
* @param ComposerAdapter $composer
* @param LastUpdateCheck $lastUpdateCheck
* @param Dispatcher $events
* @param ComposerJson $composerJson
*/
public function __construct(ComposerAdapter $composer, LastUpdateCheck $lastUpdateCheck, Dispatcher $events, ComposerJson $composerJson)
{
$this->composer = $composer;
$this->lastUpdateCheck = $lastUpdateCheck;
$this->events = $events;
$this->composerJson = $composerJson;
} }
/** /**
@ -64,7 +38,7 @@ class MajorUpdateHandler
* @throws \Flarum\User\Exception\PermissionDeniedException * @throws \Flarum\User\Exception\PermissionDeniedException
* @throws NoNewMajorVersionException|MajorUpdateFailedException * @throws NoNewMajorVersionException|MajorUpdateFailedException
*/ */
public function handle(MajorUpdate $command) public function handle(MajorUpdate $command): void
{ {
$command->actor->assertAdmin(); $command->actor->assertAdmin();

View File

@ -14,14 +14,9 @@ use Flarum\User\User;
class MinorUpdate extends AbstractActionCommand class MinorUpdate extends AbstractActionCommand
{ {
/** public function __construct(
* @var \Flarum\User\User public User $actor
*/ ) {
public $actor;
public function __construct(User $actor)
{
$this->actor = $actor;
} }
public function getOperationName(): string public function getOperationName(): string

View File

@ -19,39 +19,15 @@ use Symfony\Component\Console\Input\StringInput;
class MinorUpdateHandler class MinorUpdateHandler
{ {
/** public function __construct(
* @var ComposerAdapter protected ComposerAdapter $composer,
*/ protected LastUpdateCheck $lastUpdateCheck,
protected $composer; protected Dispatcher $events,
protected ComposerJson $composerJson
/** ) {
* @var \Flarum\PackageManager\Settings\LastUpdateCheck
*/
protected $lastUpdateCheck;
/**
* @var Dispatcher
*/
protected $events;
/**
* @var ComposerJson
*/
protected $composerJson;
public function __construct(ComposerAdapter $composer, LastUpdateCheck $lastUpdateCheck, Dispatcher $events, ComposerJson $composerJson)
{
$this->composer = $composer;
$this->lastUpdateCheck = $lastUpdateCheck;
$this->events = $events;
$this->composerJson = $composerJson;
} }
/** public function handle(MinorUpdate $command): void
* @throws \Flarum\User\Exception\PermissionDeniedException
* @throws ComposerUpdateFailedException
*/
public function handle(MinorUpdate $command)
{ {
$command->actor->assertAdmin(); $command->actor->assertAdmin();

View File

@ -14,20 +14,10 @@ use Flarum\User\User;
class RemoveExtension extends AbstractActionCommand class RemoveExtension extends AbstractActionCommand
{ {
/** public function __construct(
* @var User public User $actor,
*/ public string $extensionId
public $actor; ) {
/**
* @var string
*/
public $extensionId;
public function __construct(User $actor, string $extensionId)
{
$this->actor = $actor;
$this->extensionId = $extensionId;
} }
public function getOperationName(): string public function getOperationName(): string

View File

@ -19,33 +19,14 @@ use Symfony\Component\Console\Input\StringInput;
class RemoveExtensionHandler class RemoveExtensionHandler
{ {
/** public function __construct(
* @var ComposerAdapter private ComposerAdapter $composer,
*/ private ExtensionManager $extensions,
protected $composer; private Dispatcher $events
) {
/**
* @var ExtensionManager
*/
protected $extensions;
/**
* @var Dispatcher
*/
protected $events;
public function __construct(ComposerAdapter $composer, ExtensionManager $extensions, Dispatcher $events)
{
$this->composer = $composer;
$this->extensions = $extensions;
$this->events = $events;
} }
/** public function handle(RemoveExtension $command): void
* @throws \Flarum\User\Exception\PermissionDeniedException
* @throws \Exception
*/
public function handle(RemoveExtension $command)
{ {
$command->actor->assertAdmin(); $command->actor->assertAdmin();

View File

@ -14,20 +14,10 @@ use Flarum\User\User;
class RequireExtension extends AbstractActionCommand class RequireExtension extends AbstractActionCommand
{ {
/** public function __construct(
* @var User public User $actor,
*/ public ?string $package
public $actor; ) {
/**
* @var string
*/
public $package;
public function __construct(User $actor, string $package)
{
$this->actor = $actor;
$this->package = $package;
} }
public function getOperationName(): string public function getOperationName(): string

Some files were not shown because too many files have changed in this diff Show More