[TOOLS] Continue raising PHPStan level to 6

This commit is contained in:
Hugo Sales 2022-10-19 22:39:17 +01:00
parent c31f3d4997
commit 2fd46ca886
Signed by: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0
89 changed files with 646 additions and 278 deletions

View File

@ -178,7 +178,7 @@ return $config
// There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis. // There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis.
'no_spaces_inside_parenthesis' => true, 'no_spaces_inside_parenthesis' => true,
// Removes `@param`, `@return` and `@var` tags that don't provide any useful information. // Removes `@param`, `@return` and `@var` tags that don't provide any useful information.
'no_superfluous_phpdoc_tags' => true, 'no_superfluous_phpdoc_tags' => false,
// Remove trailing commas in list function calls. // Remove trailing commas in list function calls.
'no_trailing_comma_in_list_call' => true, 'no_trailing_comma_in_list_call' => true,
// PHP single-line arrays should not have trailing comma. // PHP single-line arrays should not have trailing comma.

View File

@ -54,7 +54,7 @@ use Symfony\Component\HttpFoundation\Request;
*/ */
class Circle extends Component class Circle extends Component
{ {
/** @phpstan-use MetaCollectionTrait<Circle> */ /** @phpstan-use MetaCollectionTrait<ActorCircle> */
use MetaCollectionTrait; use MetaCollectionTrait;
public const TAG_CIRCLE_REGEX = '/' . Nickname::BEFORE_MENTIONS . '@#([\pL\pN_\-\.]{1,64})/'; public const TAG_CIRCLE_REGEX = '/' . Nickname::BEFORE_MENTIONS . '@#([\pL\pN_\-\.]{1,64})/';
protected const SLUG = 'circle'; protected const SLUG = 'circle';
@ -228,7 +228,7 @@ class Circle extends Component
* @param null|array<string, mixed> $vars Page vars sent by AppendRightPanelBlock event * @param null|array<string, mixed> $vars Page vars sent by AppendRightPanelBlock event
* @param bool $ids_only true if only the Collections ids are to be returned * @param bool $ids_only true if only the Collections ids are to be returned
* *
* @return Circle[]|int[] * @return ($ids_only is true ? int[] : ActorCircle[])
*/ */
protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array
{ {

View File

@ -90,14 +90,12 @@ class Circles extends MetaCollectionController
return $this->getCollectionItems($tagger_id, $circle_id); return $this->getCollectionItems($tagger_id, $circle_id);
} }
/**
* @return ActorCircle[]
*/
public function getCollectionsByActorId(int $owner_id): array public function getCollectionsByActorId(int $owner_id): array
{ {
return DB::findBy(ActorCircle::class, ['tagger' => $owner_id], order_by: ['id' => 'desc']); return DB::findBy(ActorCircle::class, ['tagger' => $owner_id], order_by: ['id' => 'desc']);
} }
public function getCollectionBy(int $owner_id, int $collection_id): ActorCircle
public function getCollectionBy(int $owner_id, int $collection_id): self
{ {
return DB::findOneBy(ActorCircle::class, ['id' => $collection_id, 'actor_id' => $owner_id]); return DB::findOneBy(ActorCircle::class, ['id' => $collection_id, 'actor_id' => $owner_id]);
} }

View File

@ -26,7 +26,8 @@ class Collection extends Component
* *
* @param array<string, OrderByType> $note_order_by * @param array<string, OrderByType> $note_order_by
* @param array<string, OrderByType> $actor_order_by * @param array<string, OrderByType> $actor_order_by
* @return array{notes: Note[], actors: Actor[]} *
* @return array{notes: null|Note[], actors: null|Actor[]}
*/ */
public static function query(string $query, int $page, ?string $locale = null, ?Actor $actor = null, array $note_order_by = [], array $actor_order_by = []): array public static function query(string $query, int $page, ?string $locale = null, ?Actor $actor = null, array $note_order_by = [], array $actor_order_by = []): array
{ {
@ -84,6 +85,9 @@ class Collection extends Component
/** /**
* Convert $term to $note_expr and $actor_expr, search criteria. Handles searching for text * Convert $term to $note_expr and $actor_expr, search criteria. Handles searching for text
* notes, for different types of actors and for the content of text notes * notes, for different types of actors and for the content of text notes
*
* @param mixed $note_expr
* @param mixed $actor_expr
*/ */
public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult
{ {

View File

@ -4,6 +4,9 @@ declare(strict_types = 1);
namespace Component\Collection\Util\Controller; namespace Component\Collection\Util\Controller;
/**
* @extends OrderedCollection<\Component\Circle\Entity\ActorCircle>
*/
class CircleController extends OrderedCollection class CircleController extends OrderedCollection
{ {
} }

View File

@ -6,18 +6,20 @@ namespace Component\Collection\Util\Controller;
use App\Core\Controller; use App\Core\Controller;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use Component\Collection\Collection as CollectionComponent; use Component\Collection\Collection as CollectionComponent;
/** /**
* @template T * @template T
*/ */
class Collection extends Controller abstract class Collection extends Controller
{ {
/** /**
* @param array<string, OrderByType> $note_order_by * @param array<string, OrderByType> $note_order_by
* @param array<string, OrderByType> $actor_order_by * @param array<string, OrderByType> $actor_order_by
* @return array<T> *
* @return array{notes: null|Note[], actors: null|Actor[]}
*/ */
public function query(string $query, ?string $locale = null, ?Actor $actor = null, array $note_order_by = [], array $actor_order_by = []): array public function query(string $query, ?string $locale = null, ?Actor $actor = null, array $note_order_by = [], array $actor_order_by = []): array
{ {

View File

@ -38,6 +38,11 @@ use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use Functional as F; use Functional as F;
/**
* @template T
*
* @extends OrderedCollection<T>
*/
abstract class FeedController extends OrderedCollection abstract class FeedController extends OrderedCollection
{ {
/** /**
@ -45,9 +50,11 @@ abstract class FeedController extends OrderedCollection
* notes or actors the user specified, as well as format the raw * notes or actors the user specified, as well as format the raw
* list of notes into a usable format * list of notes into a usable format
* *
* @template T of Note|Actor * @template NA of Note|Actor
* @param T[] $result *
* @return T[] * @param NA[] $result
*
* @return NA[]
*/ */
protected function postProcess(array $result): array protected function postProcess(array $result): array
{ {

View File

@ -39,10 +39,13 @@ use App\Util\Common;
use App\Util\Exception\RedirectException; use App\Util\Exception\RedirectException;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormView;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/** /**
* @template T * @template T of object
*
* @extends FeedController<T>
*/ */
abstract class MetaCollectionController extends FeedController abstract class MetaCollectionController extends FeedController
{ {
@ -70,7 +73,7 @@ abstract class MetaCollectionController extends FeedController
abstract public function createCollection(int $owner_id, string $name): bool; abstract public function createCollection(int $owner_id, string $name): bool;
/** /**
* @return T[] * @return ControllerResultType
*/ */
public function collectionsViewByActorNickname(Request $request, string $nickname): array public function collectionsViewByActorNickname(Request $request, string $nickname): array
{ {
@ -79,7 +82,7 @@ abstract class MetaCollectionController extends FeedController
} }
/** /**
* @return T[] * @return ControllerResultType
*/ */
public function collectionsViewByActorId(Request $request, int $id): array public function collectionsViewByActorId(Request $request, int $id): array
{ {
@ -135,34 +138,23 @@ abstract class MetaCollectionController extends FeedController
// the functions and passing that class to the template. // the functions and passing that class to the template.
// This is suggested at https://web.archive.org/web/20220226132328/https://stackoverflow.com/questions/3595727/twig-pass-function-into-template/50364502 // This is suggested at https://web.archive.org/web/20220226132328/https://stackoverflow.com/questions/3595727/twig-pass-function-into-template/50364502
$fn = new class($id, $nickname, $request, $this, static::SLUG) { $fn = new class($id, $nickname, $request, $this, static::SLUG) {
private $id; public function __construct(private int $id, private string $nickname, private Request $request, private object $parent, private string $slug)
private $nick;
private $request;
private $parent;
private $slug;
public function __construct($id, $nickname, $request, $parent, $slug)
{ {
$this->id = $id;
$this->nick = $nickname;
$this->request = $request;
$this->parent = $parent;
$this->slug = $slug;
} }
// there's already an injected function called path, // there's already an injected function called path,
// that maps to Router::url(name, args), but since // that maps to Router::url(name, args), but since
// I want to preserve nicknames, I think it's better // I want to preserve nicknames, I think it's better
// to use that getUrl function // to use that getUrl function
public function getUrl($cid) public function getUrl(int $cid): string
{ {
return $this->parent->getCollectionUrl($this->id, $this->nick, $cid); return $this->parent->getCollectionUrl($this->id, $this->nickname, $cid);
} }
// There are many collections in this page and we need two // There are many collections in this page and we need two
// forms for each one of them: one form to edit the collection's // forms for each one of them: one form to edit the collection's
// name and another to remove the collection. // name and another to remove the collection.
// creating the edit form // creating the edit form
public function editForm($collection) public function editForm(object $collection): FormView
{ {
$edit = Form::create([ $edit = Form::create([
['name', TextType::class, [ ['name', TextType::class, [
@ -181,7 +173,7 @@ abstract class MetaCollectionController extends FeedController
]); ]);
$edit->handleRequest($this->request); $edit->handleRequest($this->request);
if ($edit->isSubmitted() && $edit->isValid()) { if ($edit->isSubmitted() && $edit->isValid()) {
$this->parent->setCollectionName($this->id, $this->nick, $collection, $edit->getData()['name']); $this->parent->setCollectionName($this->id, $this->nickname, $collection, $edit->getData()['name']);
DB::flush(); DB::flush();
throw new RedirectException(); throw new RedirectException();
} }
@ -189,7 +181,7 @@ abstract class MetaCollectionController extends FeedController
} }
// creating the remove form // creating the remove form
public function rmForm($collection) public function rmForm(object $collection): FormView
{ {
$rm = Form::create([ $rm = Form::create([
['remove_' . $collection->getId(), SubmitType::class, [ ['remove_' . $collection->getId(), SubmitType::class, [
@ -202,7 +194,7 @@ abstract class MetaCollectionController extends FeedController
]); ]);
$rm->handleRequest($this->request); $rm->handleRequest($this->request);
if ($rm->isSubmitted()) { if ($rm->isSubmitted()) {
$this->parent->removeCollection($this->id, $this->nick, $collection); $this->parent->removeCollection($this->id, $this->nickname, $collection);
DB::flush(); DB::flush();
throw new RedirectException(); throw new RedirectException();
} }
@ -220,12 +212,18 @@ abstract class MetaCollectionController extends FeedController
]; ];
} }
/**
* @return ControllerResultType
*/
public function collectionsEntryViewNotesByNickname(Request $request, string $nickname, int $cid): array public function collectionsEntryViewNotesByNickname(Request $request, string $nickname, int $cid): array
{ {
$user = DB::findOneBy(LocalUser::class, ['nickname' => $nickname]); $user = DB::findOneBy(LocalUser::class, ['nickname' => $nickname]);
return self::collectionsEntryViewNotesByActorId($request, $user->getId(), $cid); return self::collectionsEntryViewNotesByActorId($request, $user->getId(), $cid);
} }
/**
* @return ControllerResultType
*/
public function collectionsEntryViewNotesByActorId(Request $request, int $id, int $cid): array public function collectionsEntryViewNotesByActorId(Request $request, int $id, int $cid): array
{ {
$collection = $this->getCollectionBy($id, $cid); $collection = $this->getCollectionBy($id, $cid);

View File

@ -4,6 +4,11 @@ declare(strict_types = 1);
namespace Component\Collection\Util\Controller; namespace Component\Collection\Util\Controller;
class OrderedCollection extends Collection /**
* @template T
*
* @extends Collection<T>
*/
abstract class OrderedCollection extends Collection
{ {
} }

View File

@ -82,6 +82,7 @@ trait MetaCollectionTrait
/** /**
* Check the route to determine whether the widget should be added * Check the route to determine whether the widget should be added
*
* @param array<string, mixed> $vars * @param array<string, mixed> $vars
*/ */
abstract protected function shouldAddToRightPanel(Actor $user, array $vars, Request $request): bool; abstract protected function shouldAddToRightPanel(Actor $user, array $vars, Request $request): bool;
@ -91,7 +92,8 @@ trait MetaCollectionTrait
* @param Actor $owner Collection's owner * @param Actor $owner Collection's owner
* @param null|array<string, mixed> $vars Page vars sent by AppendRightPanelBlock event * @param null|array<string, mixed> $vars Page vars sent by AppendRightPanelBlock event
* @param bool $ids_only if true, the function must return only the primary key or each collections * @param bool $ids_only if true, the function must return only the primary key or each collections
* @return T[]|int[] *
* @return int[]|T[]
*/ */
abstract protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array; abstract protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array;
@ -196,7 +198,7 @@ trait MetaCollectionTrait
} }
/** /**
* @param string[] * @param string[] $styles
*/ */
public function onEndShowStyles(array &$styles, string $route): EventResult public function onEndShowStyles(array &$styles, string $route): EventResult
{ {

View File

@ -32,6 +32,9 @@ abstract class Parser
{ {
/** /**
* Merge $parts into $criteria_arr * Merge $parts into $criteria_arr
*
* @param mixed[] $parts
* @param Criteria[] $criteria_arr
*/ */
private static function connectParts(array &$parts, array &$criteria_arr, string $last_op, mixed $eb, bool $force = false): void private static function connectParts(array &$parts, array &$criteria_arr, string $last_op, mixed $eb, bool $force = false): void
{ {

View File

@ -46,6 +46,9 @@ use Component\Conversation\Entity\ConversationMute;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/**
* @extends FeedController<\App\Entity\Note>
*/
class Conversation extends FeedController class Conversation extends FeedController
{ {
/** /**
@ -55,7 +58,10 @@ class Conversation extends FeedController
* *
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
* *
* @return array Array containing keys: 'notes' (all known notes in the given Conversation), 'should_format' (boolean, stating if onFormatNoteList events may or not format given notes), 'page_title' (used as the title header) * @return ControllerResultType Array containing keys: 'notes' (all known
* notes in the given Conversation), 'should_format' (boolean, stating if
* onFormatNoteList events may or not format given notes), 'page_title'
* (used as the title header)
*/ */
public function showConversation(Request $request, int $conversation_id): array public function showConversation(Request $request, int $conversation_id): array
{ {
@ -83,7 +89,7 @@ class Conversation extends FeedController
* @throws NoSuchNoteException * @throws NoSuchNoteException
* @throws ServerException * @throws ServerException
* *
* @return array * @return ControllerResultType
*/ */
public function addReply(Request $request) public function addReply(Request $request)
{ {
@ -103,7 +109,7 @@ class Conversation extends FeedController
* @throws \App\Util\Exception\RedirectException * @throws \App\Util\Exception\RedirectException
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
* *
* @return array Array containing templating where the form is to be rendered, and the form itself * @return ControllerResultType Array containing templating where the form is to be rendered, and the form itself
*/ */
public function muteConversation(Request $request, int $conversation_id) public function muteConversation(Request $request, int $conversation_id)
{ {

View File

@ -96,10 +96,12 @@ class Conversation extends Component
* action, if a user is logged in. * action, if a user is logged in.
* *
* @param \App\Entity\Note $note The Note being rendered * @param \App\Entity\Note $note The Note being rendered
* @param array $actions Contains keys 'url' (linking 'conversation_reply_to' * @param array{url: string, title: string, classes: string, id: string} $actions
* route), 'title' (used as title for aforementioned url), * Contains keys 'url' (linking 'conversation_reply_to' route),
* 'classes' (CSS styling classes used to visually inform the user of action context), * 'title' (used as title for aforementioned url), 'classes' (CSS styling
* 'id' (HTML markup id used to redirect user to this anchor upon performing the action) * classes used to visually inform the user of action context), 'id' (HTML
* markup id used to redirect user to this anchor upon performing the
* action)
* *
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
*/ */
@ -138,8 +140,11 @@ class Conversation extends Component
/** /**
* Append on note information about user actions. * Append on note information about user actions.
* *
* @param array $vars Contains information related to Note currently being rendered * @param array<string, mixed> $vars Contains information related to Note currently being rendered
* @param array $result Contains keys 'actors', and 'action'. Needed to construct a string, stating who ($result['actors']), has already performed a reply ($result['action']), in the given Note (vars['note']) * @param array{actors: Actor[], action: string} $result
*cContains keys 'actors', and 'action'. Needed to construct a string,
* stating who ($result['actors']), has already performed a reply
* ($result['action']), in the given Note (vars['note'])
*/ */
public function onAppendCardNote(array $vars, array &$result): EventResult public function onAppendCardNote(array $vars, array &$result): EventResult
{ {
@ -206,7 +211,7 @@ class Conversation extends Component
/** /**
* Posting event to add extra information to Component\Posting form data * Posting event to add extra information to Component\Posting form data
* *
* @param array $data Transport data to be filled with reply_to_id * @param array{reply_to_id: int} $data Transport data to be filled with reply_to_id
* *
* @throws \App\Util\Exception\ClientException * @throws \App\Util\Exception\ClientException
* @throws \App\Util\Exception\NoSuchNoteException * @throws \App\Util\Exception\NoSuchNoteException
@ -224,6 +229,8 @@ class Conversation extends Component
/** /**
* Add minimal Note card to RightPanel template * Add minimal Note card to RightPanel template
*
* @param string[] $elements
*/ */
public function onPrependPostingForm(Request $request, array &$elements): EventResult public function onPrependPostingForm(Request $request, array &$elements): EventResult
{ {
@ -251,7 +258,9 @@ class Conversation extends Component
* Adds extra actions related to Conversation Component, that act upon/from the given Note. * Adds extra actions related to Conversation Component, that act upon/from the given Note.
* *
* @param \App\Entity\Note $note Current Note being rendered * @param \App\Entity\Note $note Current Note being rendered
* @param array $actions Containing 'url' (Controller connected route), 'title' (used in anchor link containing the url), ?'classes' (CSS classes required for styling, if needed) * @param array{url: string, title: string, classes?: string} $actions Containing 'url' (Controller connected
* route), 'title' (used in anchor link containing the url), ?'classes' (CSS classes required for styling, if
* needed)
* *
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
*/ */

View File

@ -41,10 +41,15 @@ use App\Util\HTML\Heading;
use Component\Collection\Util\Controller\FeedController; use Component\Collection\Util\Controller\FeedController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/**
* @extends FeedController<\App\Entity\Note>
*/
class Feeds extends FeedController class Feeds extends FeedController
{ {
/** /**
* The Planet feed represents every local post. Which is what this instance has to share with the universe. * The Planet feed represents every local post. Which is what this instance has to share with the universe.
*
* @return ControllerResultType
*/ */
public function public(Request $request): array public function public(Request $request): array
{ {
@ -60,6 +65,8 @@ class Feeds extends FeedController
/** /**
* The Home feed represents everything that concerns a certain actor (its subscriptions) * The Home feed represents everything that concerns a certain actor (its subscriptions)
*
* @return ControllerResultType
*/ */
public function home(Request $request): array public function home(Request $request): array
{ {

View File

@ -244,6 +244,8 @@ class FreeNetwork extends Component
/** /**
* Add a link header for LRDD Discovery * Add a link header for LRDD Discovery
*
* @param mixed $action
*/ */
public function onStartShowHTML($action): EventResult public function onStartShowHTML($action): EventResult
{ {
@ -344,6 +346,7 @@ class FreeNetwork extends Component
* @param string $preMention Character(s) that signals a mention ('@', '!'...) * @param string $preMention Character(s) that signals a mention ('@', '!'...)
* *
* @return array the matching URLs (without @ or acct:) and each respective position in the given string * @return array the matching URLs (without @ or acct:) and each respective position in the given string
*
* @example.com/mublog/user * @example.com/mublog/user
*/ */
public static function extractUrlMentions(string $text, string $preMention = '@'): array public static function extractUrlMentions(string $text, string $preMention = '@'): array
@ -375,6 +378,7 @@ class FreeNetwork extends Component
* @param $mentions * @param $mentions
* *
* @return bool hook return value * @return bool hook return value
*
* @example.com/mublog/user * @example.com/mublog/user
*/ */
public function onEndFindMentions(Actor $sender, string $text, array &$mentions): EventResult public function onEndFindMentions(Actor $sender, string $text, array &$mentions): EventResult
@ -496,6 +500,9 @@ class FreeNetwork extends Component
return Event::next; return Event::next;
} }
/**
* @param Actor[] $targets
*/
public static function notify(Actor $sender, Activity $activity, array $targets, ?string $reason = null): bool public static function notify(Actor $sender, Activity $activity, array $targets, ?string $reason = null): bool
{ {
foreach (self::$protocols as $protocol) { foreach (self::$protocols as $protocol) {
@ -517,6 +524,9 @@ class FreeNetwork extends Component
/** /**
* Add fediverse: query expression * Add fediverse: query expression
* // TODO: adding WebFinger would probably be nice * // TODO: adding WebFinger would probably be nice
*
* @param mixed $note_expr
* @param mixed $actor_expr
*/ */
public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult
{ {

View File

@ -61,6 +61,8 @@ class Group extends Controller
* *
* @throws RedirectException * @throws RedirectException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function groupCreate(Request $request): array public function groupCreate(Request $request): array
{ {
@ -89,6 +91,8 @@ class Group extends Controller
* @throws NicknameTooLongException * @throws NicknameTooLongException
* @throws NotFoundException * @throws NotFoundException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function groupSettings(Request $request, int $id): array public function groupSettings(Request $request, int $id): array
{ {

View File

@ -40,10 +40,15 @@ use Component\Subscription\Entity\ActorSubscription;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/**
* @extends FeedController<\App\Entity\Note>
*/
class GroupFeed extends FeedController class GroupFeed extends FeedController
{ {
/** /**
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function groupView(Request $request, Actor $group): array public function groupView(Request $request, Actor $group): array
{ {
@ -96,6 +101,8 @@ class GroupFeed extends FeedController
/** /**
* @throws ClientException * @throws ClientException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function groupViewId(Request $request, int $id): array public function groupViewId(Request $request, int $id): array
{ {
@ -119,6 +126,8 @@ class GroupFeed extends FeedController
* *
* @throws ClientException * @throws ClientException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function groupViewNickname(Request $request, string $nickname): array public function groupViewNickname(Request $request, string $nickname): array
{ {

View File

@ -50,6 +50,8 @@ class Group extends Component
/** /**
* Enqueues a notification for an Actor (such as person or group) which means * Enqueues a notification for an Actor (such as person or group) which means
* it shows up in their home feed and such. * it shows up in their home feed and such.
*
* @param Actor[] $targets
*/ */
public function onNewNotificationStart(Actor $sender, Activity $activity, array $targets = [], ?string $reason = null): EventResult public function onNewNotificationStart(Actor $sender, Activity $activity, array $targets = [], ?string $reason = null): EventResult
{ {
@ -70,6 +72,9 @@ class Group extends Component
/** /**
* Add an <a href=group_actor_settings> to the profile card for groups, if the current actor can access them * Add an <a href=group_actor_settings> to the profile card for groups, if the current actor can access them
*
* @param array<string, mixed> $vars
* @param string[] $res
*/ */
public function onAppendCardProfile(array $vars, array &$res): EventResult public function onAppendCardProfile(array $vars, array &$res): EventResult
{ {
@ -109,6 +114,9 @@ class Group extends Component
return null; return null;
} }
/**
* @param Actor[] $targets
*/
public function onPostingFillTargetChoices(Request $request, Actor $actor, array &$targets): EventResult public function onPostingFillTargetChoices(Request $request, Actor $actor, array &$targets): EventResult
{ {
$group = $this->getGroupFromContext($request); $group = $this->getGroupFromContext($request);

View File

@ -100,6 +100,8 @@ class Language extends Controller
* @throws NoLoggedInUser * @throws NoLoggedInUser
* @throws RedirectException * @throws RedirectException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function sortLanguages(Request $request): array public function sortLanguages(Request $request): array
{ {

View File

@ -119,6 +119,9 @@ class ActorLanguage extends Entity
) ?: [Language::getByLocale(Common::config('site', 'language'))]; ) ?: [Language::getByLocale(Common::config('site', 'language'))];
} }
/**
* @return int[]
*/
public static function getActorRelatedLanguagesIds(Actor $actor): array public static function getActorRelatedLanguagesIds(Actor $actor): array
{ {
return Cache::getList( return Cache::getList(

View File

@ -134,6 +134,9 @@ class Language extends Entity
return self::getById($note->getLanguageId()); return self::getById($note->getLanguageId());
} }
/**
* @return array<string, string>
*/
public static function getLanguageChoices(): array public static function getLanguageChoices(): array
{ {
$langs = Cache::getHashMap( $langs = Cache::getHashMap(
@ -144,6 +147,8 @@ class Language extends Entity
return array_merge(...F\map(array_values($langs), fn ($l) => $l->toChoiceFormat())); return array_merge(...F\map(array_values($langs), fn ($l) => $l->toChoiceFormat()));
} }
/**
* @return array<string, string> */
public function toChoiceFormat(): array public function toChoiceFormat(): array
{ {
return [_m($this->getLongDisplay()) => $this->getLocale()]; return [_m($this->getLongDisplay()) => $this->getLocale()];
@ -152,6 +157,8 @@ class Language extends Entity
/** /**
* Get all the available languages as well as the languages $actor * Get all the available languages as well as the languages $actor
* prefers and are appropriate for posting in/to $context_actor * prefers and are appropriate for posting in/to $context_actor
*
* @return array{array<string, string>, array<string, string>}
*/ */
public static function getSortedLanguageChoices(?Actor $actor, ?Actor $context_actor, ?bool $use_short_display): array public static function getSortedLanguageChoices(?Actor $actor, ?Actor $context_actor, ?bool $use_short_display): array
{ {

View File

@ -45,6 +45,9 @@ class Language extends Component
return Event::next; return Event::next;
} }
/**
* @param Note[] $notes
*/
public function onFilterNoteList(?Actor $actor, array &$notes, Request $request): EventResult public function onFilterNoteList(?Actor $actor, array &$notes, Request $request): EventResult
{ {
if (\is_null($actor)) { if (\is_null($actor)) {
@ -60,6 +63,9 @@ class Language extends Component
/** /**
* Populate $note_expr or $actor_expr with an expression to match a language * Populate $note_expr or $actor_expr with an expression to match a language
*
* @param mixed $note_expr
* @param mixed $actor_expr
*/ */
public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult
{ {

View File

@ -43,6 +43,8 @@ class LeftPanel extends Component
} }
/** /**
* @param array<string, string> $route_params
*
* @throws \App\Util\Exception\DuplicateFoundException * @throws \App\Util\Exception\DuplicateFoundException
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
* @throws ClientException * @throws ClientException

View File

@ -84,6 +84,8 @@ class NoteToLink extends Entity
* Create an instance of NoteToLink or fill in the * Create an instance of NoteToLink or fill in the
* properties of $obj with the associative array $args. Doesn't * properties of $obj with the associative array $args. Doesn't
* persist the result * persist the result
*
* @param (array{link_id: int, note_id: int} & array<string, mixed>) $args
*/ */
public static function create(array $args, bool $_delegated_call = false): static public static function create(array $args, bool $_delegated_call = false): static
{ {

View File

@ -54,6 +54,8 @@ class Link extends Component
/** /**
* Extract URLs from $content and create the appropriate Link and NoteToLink entities * Extract URLs from $content and create the appropriate Link and NoteToLink entities
*
* @param array{ignoreLinks?: string[]} $process_note_content_extra_args
*/ */
public function onProcessNoteContent(Note $note, string $content, string $content_type, array $process_note_content_extra_args = []): EventResult public function onProcessNoteContent(Note $note, string $content, string $content_type, array $process_note_content_extra_args = []): EventResult
{ {
@ -150,7 +152,12 @@ class Link extends Component
public const URL_SCHEME_NO_DOMAIN = 4; public const URL_SCHEME_NO_DOMAIN = 4;
public const URL_SCHEME_COLON_COORDINATES = 8; public const URL_SCHEME_COLON_COORDINATES = 8;
public function URLSchemes($filter = null) /**
* @param self::URL_SCHEME_COLON_COORDINATES|self::URL_SCHEME_COLON_DOUBLE_SLASH|self::URL_SCHEME_NO_DOMAIN|self::URL_SCHEME_SINGLE_COLON $filter
*
* @return string[]
*/
public function URLSchemes(?int $filter = null): array
{ {
// TODO: move these to config // TODO: move these to config
$schemes = [ $schemes = [
@ -197,6 +204,7 @@ class Link extends Component
* Intermediate callback for `replaceURLs()`, which helps resolve some * Intermediate callback for `replaceURLs()`, which helps resolve some
* ambiguous link forms before passing on to the final callback. * ambiguous link forms before passing on to the final callback.
* *
* @param string[] $matches
* @param callable(string $text): string $callback: return replacement text * @param callable(string $text): string $callback: return replacement text
*/ */
private function callbackHelper(array $matches, callable $callback): string private function callbackHelper(array $matches, callable $callback): string

View File

@ -44,6 +44,8 @@ class Feed extends Controller
{ {
/** /**
* Everything with attention to current user * Everything with attention to current user
*
* @return ControllerResultType
*/ */
public function notifications(Request $request): array public function notifications(Request $request): array
{ {

View File

@ -117,7 +117,7 @@ class Notification extends Entity
/** /**
* Pull the complete list of known activity context notifications for this activity. * Pull the complete list of known activity context notifications for this activity.
* *
* @return array of integer actor ids (also group profiles) * @return int[] actor ids (also group profiles)
*/ */
public static function getNotificationTargetIdsByActivity(int|Activity $activity_id): array public static function getNotificationTargetIdsByActivity(int|Activity $activity_id): array
{ {
@ -129,11 +129,17 @@ class Notification extends Entity
return $targets; return $targets;
} }
/**
* @return int[]
*/
public function getNotificationTargetsByActivity(int|Activity $activity_id): array public function getNotificationTargetsByActivity(int|Activity $activity_id): array
{ {
return DB::findBy(Actor::class, ['id' => $this->getNotificationTargetIdsByActivity($activity_id)]); return DB::findBy(Actor::class, ['id' => $this->getNotificationTargetIdsByActivity($activity_id)]);
} }
/**
* @return int[]
*/
public static function getAllActivitiesTargetedAtActor(Actor $actor): array public static function getAllActivitiesTargetedAtActor(Actor $actor): array
{ {
return DB::dql(<<<'EOF' return DB::dql(<<<'EOF'

View File

@ -73,7 +73,7 @@ class Notification extends Component
* *
* @param Actor $sender The one responsible for this activity, take care not to include it in targets * @param Actor $sender The one responsible for this activity, take care not to include it in targets
* @param Activity $activity The activity responsible for the object being given to known to targets * @param Activity $activity The activity responsible for the object being given to known to targets
* @param array $targets Attentions, Mentions, any other source. Should never be empty, you usually want to register an attention to every $sender->getSubscribers() * @param non-empty-array<Actor|int> $targets Attentions, Mentions, any other source. Should never be empty, you usually want to register an attention to every $sender->getSubscribers()
* @param null|string $reason An optional reason explaining why this notification exists * @param null|string $reason An optional reason explaining why this notification exists
*/ */
public function onNewNotification(Actor $sender, Activity $activity, array $targets, ?string $reason = null): EventResult public function onNewNotification(Actor $sender, Activity $activity, array $targets, ?string $reason = null): EventResult
@ -103,12 +103,19 @@ class Notification extends Component
return Event::next; return Event::next;
} }
/**
* @param mixed[] $retry_args
*/
public function onQueueNotificationLocal(Actor $sender, Activity $activity, Actor $target, ?string $reason, array &$retry_args): EventResult public function onQueueNotificationLocal(Actor $sender, Activity $activity, Actor $target, ?string $reason, array &$retry_args): EventResult
{ {
// TODO: use https://symfony.com/doc/current/notifier.html // TODO: use https://symfony.com/doc/current/notifier.html
return Event::stop; return Event::stop;
} }
/**
* @param Actor[] $targets
* @param mixed[] $retry_args
*/
public function onQueueNotificationRemote(Actor $sender, Activity $activity, array $targets, ?string $reason, array &$retry_args): EventResult public function onQueueNotificationRemote(Actor $sender, Activity $activity, array $targets, ?string $reason, array &$retry_args): EventResult
{ {
if (FreeNetwork::notify($sender, $activity, $targets, $reason)) { if (FreeNetwork::notify($sender, $activity, $targets, $reason)) {
@ -122,7 +129,9 @@ class Notification extends Component
* Bring given Activity to Targets' knowledge. * Bring given Activity to Targets' knowledge.
* This will flush a Notification to DB. * This will flush a Notification to DB.
* *
* @return true if successful, false otherwise * @param Actor[] $targets
*
* @return bool true if successful, false otherwise
*/ */
public static function notify(Actor $sender, Activity $activity, array $targets, ?string $reason = null): bool public static function notify(Actor $sender, Activity $activity, array $targets, ?string $reason = null): bool
{ {

View File

@ -34,11 +34,16 @@ use App\Util\HTML\Heading;
use Component\Collection\Util\Controller\FeedController; use Component\Collection\Util\Controller\FeedController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/**
* @extends FeedController<\App\Entity\Note>
*/
class PersonFeed extends FeedController class PersonFeed extends FeedController
{ {
/** /**
* @throws ClientException * @throws ClientException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function personViewId(Request $request, int $id): array public function personViewId(Request $request, int $id): array
{ {
@ -62,6 +67,8 @@ class PersonFeed extends FeedController
* *
* @throws ClientException * @throws ClientException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function personViewNickname(Request $request, string $nickname): array public function personViewNickname(Request $request, string $nickname): array
{ {
@ -73,6 +80,9 @@ class PersonFeed extends FeedController
return $this->personView($request, $person); return $this->personView($request, $person);
} }
/**
* @return ControllerResultType
*/
public function personView(Request $request, Actor $person): array public function personView(Request $request, Actor $person): array
{ {
return [ return [

View File

@ -88,6 +88,8 @@ class PersonSettings extends Controller
* @throws NoLoggedInUser * @throws NoLoggedInUser
* @throws RedirectException * @throws RedirectException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function allSettings(Request $request, LanguageController $language): array public function allSettings(Request $request, LanguageController $language): array
{ {
@ -205,6 +207,8 @@ class PersonSettings extends Controller
* @throws \Doctrine\DBAL\Exception * @throws \Doctrine\DBAL\Exception
* @throws NoLoggedInUser * @throws NoLoggedInUser
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType[]
*/ */
private static function notifications(Request $request): array private static function notifications(Request $request): array
{ {

View File

@ -44,11 +44,13 @@ use App\Util\Exception\ServerException;
use App\Util\Formatting; use App\Util\Formatting;
use App\Util\HTML; use App\Util\HTML;
use Component\Attachment\Entity\ActorToAttachment; use Component\Attachment\Entity\ActorToAttachment;
use Component\Attachment\Entity\Attachment;
use Component\Attachment\Entity\AttachmentToNote; use Component\Attachment\Entity\AttachmentToNote;
use Component\Conversation\Conversation; use Component\Conversation\Conversation;
use Component\Language\Entity\Language; use Component\Language\Entity\Language;
use Component\Notification\Entity\Attention; use Component\Notification\Entity\Attention;
use EventResult; use EventResult;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -66,6 +68,8 @@ class Posting extends Component
* HTML render event handler responsible for adding and handling * HTML render event handler responsible for adding and handling
* the result of adding the note submission form, only if a user is logged in * the result of adding the note submission form, only if a user is logged in
* *
* @param array{post_form?: FormInterface} $res
*
* @throws BugFoundException * @throws BugFoundException
* @throws ClientException * @throws ClientException
* @throws DuplicateFoundException * @throws DuplicateFoundException
@ -84,9 +88,25 @@ class Posting extends Component
} }
/** /**
* @param Actor $actor The Actor responsible for the creation of this Note
* @param null|string $content The raw text content
* @param string $content_type Indicating one of the various supported content format (Plain Text, Markdown, LaTeX...)
* @param null|string $locale Note's written text language, set by the default Actor language or upon filling
* @param null|VisibilityScope $scope The visibility of this Note
* @param Actor[]|int[] $attentions Actor|int[]: In Group/To Person or Bot, registers an attention between note and target
* @param null|int|Note $reply_to The soon-to-be Note parent's id, if it's a Reply itself
* @param UploadedFile[] $attachments UploadedFile[] to be stored as GSFiles associated to this note
* @param array<array{Attachment, string}> $processed_attachments Array of [Attachment, Attachment's name][] to be associated to this $actor and Note
* @param array{note?: Note, content?: string, content_type?: string, extra_args?: array<string, mixed>} $process_note_content_extra_args Extra arguments for the event ProcessNoteContent
* @param bool $flush_and_notify True if the newly created Note activity should be passed on as a Notification
* @param null|string $rendered The Note's content post RenderNoteContent event, which sanitizes and processes the raw content sent
* @param string $source The source of this Note
*
* @throws ClientException * @throws ClientException
* @throws DuplicateFoundException * @throws DuplicateFoundException
* @throws ServerException * @throws ServerException
*
* @return array{\App\Entity\Activity, \App\Entity\Note, array<int, \App\Entity\Actor>}
*/ */
public static function storeLocalArticle( public static function storeLocalArticle(
Actor $actor, Actor $actor,
@ -149,11 +169,11 @@ class Posting extends Component
* @param string $content_type Indicating one of the various supported content format (Plain Text, Markdown, LaTeX...) * @param string $content_type Indicating one of the various supported content format (Plain Text, Markdown, LaTeX...)
* @param null|string $locale Note's written text language, set by the default Actor language or upon filling * @param null|string $locale Note's written text language, set by the default Actor language or upon filling
* @param null|VisibilityScope $scope The visibility of this Note * @param null|VisibilityScope $scope The visibility of this Note
* @param array $attentions Actor|int[]: In Group/To Person or Bot, registers an attention between note and target * @param Actor[]|int[] $attentions Actor|int[]: In Group/To Person or Bot, registers an attention between note and targte
* @param null|int|Note $reply_to The soon-to-be Note parent's id, if it's a Reply itself * @param null|int|Note $reply_to The soon-to-be Note parent's id, if it's a Reply itself
* @param array $attachments UploadedFile[] to be stored as GSFiles associated to this note * @param UploadedFile[] $attachments UploadedFile[] to be stored as GSFiles associated to this note
* @param array $processed_attachments Array of [Attachment, Attachment's name][] to be associated to this $actor and Note * @param array<array{Attachment, string}> $processed_attachments Array of [Attachment, Attachment's name][] to be associated to this $actor and Note
* @param array $process_note_content_extra_args Extra arguments for the event ProcessNoteContent * @param array{note?: Note, content?: string, content_type?: string, extra_args?: array<string, mixed>} $process_note_content_extra_args Extra arguments for the event ProcessNoteContent
* @param bool $flush_and_notify True if the newly created Note activity should be passed on as a Notification * @param bool $flush_and_notify True if the newly created Note activity should be passed on as a Notification
* @param null|string $rendered The Note's content post RenderNoteContent event, which sanitizes and processes the raw content sent * @param null|string $rendered The Note's content post RenderNoteContent event, which sanitizes and processes the raw content sent
* @param string $source The source of this Note * @param string $source The source of this Note
@ -162,7 +182,7 @@ class Posting extends Component
* @throws DuplicateFoundException * @throws DuplicateFoundException
* @throws ServerException * @throws ServerException
* *
* @return array [Activity, Note, Effective Attentions] * @return array{\App\Entity\Activity, \App\Entity\Note, array<int, \App\Entity\Actor>}
*/ */
public static function storeLocalNote( public static function storeLocalNote(
Actor $actor, Actor $actor,
@ -302,6 +322,9 @@ class Posting extends Component
return [$activity, $note, $effective_attentions]; return [$activity, $note, $effective_attentions];
} }
/**
* @param array<int, \App\Entity\Actor> $mentions
*/
public function onRenderNoteContent(string $content, string $content_type, ?string &$rendered, Actor $author, ?string $language = null, array &$mentions = []): EventResult public function onRenderNoteContent(string $content, string $content_type, ?string &$rendered, Actor $author, ?string $language = null, array &$mentions = []): EventResult
{ {
switch ($content_type) { switch ($content_type) {

View File

@ -38,12 +38,17 @@ use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/**
* @extends FeedController<\App\Entity\Note>
*/
class Search extends FeedController class Search extends FeedController
{ {
/** /**
* Handle a search query * Handle a search query
*
* @return ControllerResultType
*/ */
public function handle(Request $request) public function handle(Request $request): array
{ {
$actor = Common::actor(); $actor = Common::actor();
$language = !\is_null($actor) ? $actor->getTopLanguage()->getLocale() : null; $language = !\is_null($actor) ? $actor->getTopLanguage()->getLocale() : null;

View File

@ -134,6 +134,8 @@ class Search extends Component
/** /**
* Add the search form to the site header * Add the search form to the site header
* *
* @param string[] $elements
*
* @throws RedirectException * @throws RedirectException
*/ */
public function onPrependRightPanelBlock(Request $request, array &$elements): EventResult public function onPrependRightPanelBlock(Request $request, array &$elements): EventResult
@ -145,7 +147,7 @@ class Search extends Component
/** /**
* Output our dedicated stylesheet * Output our dedicated stylesheet
* *
* @param array $styles stylesheets path * @param string[] $styles stylesheets path
*/ */
public function onEndShowStyles(array &$styles, string $route): EventResult public function onEndShowStyles(array &$styles, string $route): EventResult
{ {

View File

@ -45,6 +45,8 @@ class Subscribers extends CircleController
{ {
/** /**
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function subscribersByActor(Request $request, Actor $actor): array public function subscribersByActor(Request $request, Actor $actor): array
{ {
@ -61,6 +63,8 @@ class Subscribers extends CircleController
/** /**
* @throws ClientException * @throws ClientException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function subscribersByActorId(Request $request, int $id): array public function subscribersByActorId(Request $request, int $id): array
{ {
@ -78,6 +82,8 @@ class Subscribers extends CircleController
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
* @throws ClientException * @throws ClientException
* @throws RedirectException * @throws RedirectException
*
* @return ControllerResultType
*/ */
public function subscribersAdd(Request $request, int $object_id): array public function subscribersAdd(Request $request, int $object_id): array
{ {
@ -126,6 +132,8 @@ class Subscribers extends CircleController
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
* @throws ClientException * @throws ClientException
* @throws RedirectException * @throws RedirectException
*
* @return ControllerResultType
*/ */
public function subscribersRemove(Request $request, int $object_id): array public function subscribersRemove(Request $request, int $object_id): array
{ {

View File

@ -38,6 +38,8 @@ class Subscriptions extends CircleController
/** /**
* @throws ClientException * @throws ClientException
* @throws ServerException * @throws ServerException
*
* @return ControllerResultType
*/ */
public function subscriptionsByActorId(Request $request, int $id): array public function subscriptionsByActorId(Request $request, int $id): array
{ {
@ -48,7 +50,10 @@ class Subscriptions extends CircleController
return $this->subscriptionsByActor($request, $actor); return $this->subscriptionsByActor($request, $actor);
} }
public function subscriptionsByActor(Request $request, Actor $actor) /**
* @return ControllerResultType
*/
public function subscriptionsByActor(Request $request, Actor $actor): array
{ {
return [ return [
'_template' => 'collection/actors.html.twig', '_template' => 'collection/actors.html.twig',

View File

@ -58,6 +58,8 @@ class Subscription extends Component
* *
* @param Actor|int|LocalUser $subject The Actor who subscribed or unsubscribed * @param Actor|int|LocalUser $subject The Actor who subscribed or unsubscribed
* @param Actor|int|LocalUser $object The Actor who was subscribed or unsubscribed from * @param Actor|int|LocalUser $object The Actor who was subscribed or unsubscribed from
*
* @return array{bool, bool}
*/ */
public static function refreshSubscriptionCount(int|Actor|LocalUser $subject, int|Actor|LocalUser $object): array public static function refreshSubscriptionCount(int|Actor|LocalUser $subject, int|Actor|LocalUser $object): array
{ {
@ -178,7 +180,8 @@ class Subscription extends Component
* **unsubscribe** a given **Actor**. * **unsubscribe** a given **Actor**.
* *
* @param Actor $object The Actor on which the action is to be performed * @param Actor $object The Actor on which the action is to be performed
* @param array $actions An array containing all actions added to the * @param array<array{url: string, title: string, classes: string, id: string}> $actions
* An array containing all actions added to the
* current profile, this event adds an action to it * current profile, this event adds an action to it
* *
* @throws DuplicateFoundException * @throws DuplicateFoundException

View File

@ -15,7 +15,12 @@ class Tag extends Controller
// TODO: Use Feed::query // TODO: Use Feed::query
// TODO: If ?canonical=something, respect // TODO: If ?canonical=something, respect
// TODO: Allow to set locale of tag being selected // TODO: Allow to set locale of tag being selected
private function process(null|string|array $tag_single_or_multi, string $key, string $query, string $template, bool $include_locale = false) /**
* @param (null|string|string[]) $tag_single_or_multi
*
* @return ControllerResultType
*/
private function process(null|string|array $tag_single_or_multi, string $key, string $query, string $template, bool $include_locale = false): array
{ {
$actor = Common::actor(); $actor = Common::actor();
$page = $this->int('page') ?: 1; $page = $this->int('page') ?: 1;
@ -46,7 +51,10 @@ class Tag extends Controller
]; ];
} }
public function single_note_tag(string $tag) /**
* @return ControllerResultType
*/
public function single_note_tag(string $tag): array
{ {
return $this->process( return $this->process(
tag_single_or_multi: $tag, tag_single_or_multi: $tag,
@ -57,7 +65,10 @@ class Tag extends Controller
); );
} }
public function multi_note_tags(string $tags) /**
* @return ControllerResultType
*/
public function multi_note_tags(string $tags): array
{ {
return $this->process( return $this->process(
tag_single_or_multi: explode(',', $tags), tag_single_or_multi: explode(',', $tags),

View File

@ -134,6 +134,9 @@ class NoteTag extends Entity
return "note-tags-{$note_id}"; return "note-tags-{$note_id}";
} }
/**
* @return NoteTag[]
*/
public static function getByNoteId(int $note_id): array public static function getByNoteId(int $note_id): array
{ {
return Cache::getList(self::cacheKey($note_id), fn () => DB::dql('SELECT nt FROM note_tag AS nt JOIN note AS n WITH n.id = nt.note_id WHERE n.id = :id', ['id' => $note_id])); return Cache::getList(self::cacheKey($note_id), fn () => DB::dql('SELECT nt FROM note_tag AS nt JOIN note AS n WITH n.id = nt.note_id WHERE n.id = :id', ['id' => $note_id]));

View File

@ -119,6 +119,8 @@ class NoteTagBlock extends Entity
/** /**
* Check whether $note_tag is considered blocked by one of * Check whether $note_tag is considered blocked by one of
* $note_tag_blocks * $note_tag_blocks
*
* @param NoteTagBlock[] $note_tag_blocks
*/ */
public static function checkBlocksNoteTag(NoteTag $note_tag, array $note_tag_blocks): bool public static function checkBlocksNoteTag(NoteTag $note_tag, array $note_tag_blocks): bool
{ {

View File

@ -61,13 +61,16 @@ class Tag extends Component
public const TAG_REGEX = '/(^|\\s)(#[\\pL\\pN_\\-]{1,64})/u'; // Brion Vibber 2011-02-23 v2:classes/Notice.php:367 function saveTags public const TAG_REGEX = '/(^|\\s)(#[\\pL\\pN_\\-]{1,64})/u'; // Brion Vibber 2011-02-23 v2:classes/Notice.php:367 function saveTags
public const TAG_SLUG_REGEX = '[A-Za-z0-9]{1,64}'; public const TAG_SLUG_REGEX = '[A-Za-z0-9]{1,64}';
public function onAddRoute($r): EventResult public function onAddRoute(Router $r): EventResult
{ {
$r->connect('single_note_tag', '/note-tag/{tag<' . self::TAG_SLUG_REGEX . '>}', [Controller\Tag::class, 'single_note_tag']); $r->connect('single_note_tag', '/note-tag/{tag<' . self::TAG_SLUG_REGEX . '>}', [Controller\Tag::class, 'single_note_tag']);
$r->connect('multi_note_tags', '/note-tags/{tags<(' . self::TAG_SLUG_REGEX . ',)+' . self::TAG_SLUG_REGEX . '>}', [Controller\Tag::class, 'multi_note_tags']); $r->connect('multi_note_tags', '/note-tags/{tags<(' . self::TAG_SLUG_REGEX . ',)+' . self::TAG_SLUG_REGEX . '>}', [Controller\Tag::class, 'multi_note_tags']);
return Event::next; return Event::next;
} }
/**
* @param array{tag_use_canonical?: bool} $extra_args
*/
public static function maybeCreateTag(string $tag, int $note_id, ?int $lang_id, array $extra_args = []): ?NoteTag public static function maybeCreateTag(string $tag, int $note_id, ?int $lang_id, array $extra_args = []): ?NoteTag
{ {
if (!self::validate($tag)) { if (!self::validate($tag)) {
@ -118,6 +121,8 @@ class Tag extends Component
/** /**
* Process note by extracting any tags present * Process note by extracting any tags present
*
* @param array{TagProcessed?: bool} $extra_args
*/ */
public function onProcessNoteContent(Note $note, string $content, string $content_type, array $extra_args): EventResult public function onProcessNoteContent(Note $note, string $content, string $content_type, array $extra_args): EventResult
{ {
@ -213,6 +218,9 @@ class Tag extends Component
* Populate $note_expr with an expression to match a tag, if the term looks like a tag * Populate $note_expr with an expression to match a tag, if the term looks like a tag
* *
* $term /^(note|tag|people|actor)/ means we want to match only either a note or an actor * $term /^(note|tag|people|actor)/ means we want to match only either a note or an actor
*
* @param mixed $note_expr
* @param mixed $actor_expr
*/ */
public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult
{ {
@ -264,12 +272,19 @@ class Tag extends Component
return Event::next; return Event::next;
} }
/**
* @param array{string, class-string, array<string, mixed>} $form_params
*/
public function onPostingAddFormEntries(Request $request, Actor $actor, array &$form_params): EventResult public function onPostingAddFormEntries(Request $request, Actor $actor, array &$form_params): EventResult
{ {
$form_params[] = ['tag_use_canonical', CheckboxType::class, ['required' => false, 'data' => true, 'label' => _m('Make note tags canonical'), 'help' => _m('Canonical tags will be treated as a version of an existing tag with the same root/stem (e.g. \'#great_tag\' will be considered as a version of \'#great\', if it already exists)')]]; $form_params[] = ['tag_use_canonical', CheckboxType::class, ['required' => false, 'data' => true, 'label' => _m('Make note tags canonical'), 'help' => _m('Canonical tags will be treated as a version of an existing tag with the same root/stem (e.g. \'#great_tag\' will be considered as a version of \'#great\', if it already exists)')]];
return Event::next; return Event::next;
} }
/**
* @param array{tag_use_canonical?: bool} $data
* @param array{tag_use_canonical?: bool} $extra_args
*/
public function onAddExtraArgsToNoteContent(Request $request, Actor $actor, array $data, array &$extra_args): EventResult public function onAddExtraArgsToNoteContent(Request $request, Actor $actor, array $data, array &$extra_args): EventResult
{ {
if (!isset($data['tag_use_canonical'])) { if (!isset($data['tag_use_canonical'])) {

View File

@ -1,5 +1,7 @@
parameters: parameters:
level: 5 level: 6
tmpDir: /var/www/social/var/cache/phpstan
inferPrivatePropertyTypeFromConstructor: true
bootstrapFiles: bootstrapFiles:
- config/bootstrap.php - config/bootstrap.php
paths: paths:
@ -16,10 +18,11 @@ parameters:
App\Core\Log: App\Core\Log:
- unexpected_exception - unexpected_exception
typeAliases: typeAliases:
ControllerResultType: 'array{_template: string} & array<string, mixed>' ControllerResultType: '(array{_template: string} | array{_redirect: string}) & array<string, mixed>'
CacheKeysType: 'array<string, string>' CacheKeysType: 'array<string, string>'
SettingsTabsType: 'array<array{title: string, desc: string, id: string, controller: ControllerResultType}>' SettingsTabsType: 'array<array{title: string, desc: string, id: string, controller: ControllerResultType}>'
OrderByType: "'ASC' | 'DESC' | 'asc' | 'desc'" OrderByType: "'ASC' | 'DESC' | 'asc' | 'desc'"
ModuleVersionType: 'array{name: string, version: string, author: string, rawdescription: string}'
ignoreErrors: ignoreErrors:
- -
@ -41,10 +44,41 @@ parameters:
paths: paths:
- * - *
# - -
# message: '/has no return typehint specified/' message: '/::onCollectionQueryCreateExpression\(\) has parameter \$(actor|note)_expr with no type specified\./'
# paths: paths:
# - tests/* - *
-
message: '/::schemaDef\(\) return type has no value type specified in iterable type array\./'
paths:
- *
-
message: '/has no return type specified\./'
paths:
- *
-
message: '/with no value type specified in iterable type (array|iterable)\.|type has no value type specified in iterable type (array|iterable)\./'
paths:
- *
-
message: '/never returns array{_redirect: string} so it can be removed from the return type\./'
paths:
- *
-
message: '/but returns array<string, array<int, mixed>\|string>\./'
paths:
- plugins/AttachmentCollections/Controller/AttachmentCollections.php
- plugins/Bundles/Controller/BundleCollection.php
-
message: '/has parameter \$.+ with no type specified./'
paths:
- tests/*
services: services:
- -

View File

@ -49,9 +49,14 @@ use Symfony\Component\HttpFoundation\Request;
class AttachmentCollections extends Plugin class AttachmentCollections extends Plugin
{ {
/** @phpstan-use MetaCollectionTrait<AttachmentCollection> */
use MetaCollectionTrait; use MetaCollectionTrait;
protected const SLUG = 'collection'; protected const SLUG = 'collection';
protected const PLURAL_SLUG = 'collections'; protected const PLURAL_SLUG = 'collections';
/**
* @param array<string, mixed> $vars
*/
protected function createCollection(Actor $owner, array $vars, string $name): void protected function createCollection(Actor $owner, array $vars, string $name): void
{ {
$col = AttachmentCollection::create([ $col = AttachmentCollection::create([
@ -65,6 +70,12 @@ class AttachmentCollections extends Plugin
'attachment_collection_id' => $col->getId(), 'attachment_collection_id' => $col->getId(),
])); ]));
} }
/**
* @param array<string, mixed> $vars
* @param int[] $items
* @param array<string, mixed> $collections
*/
protected function removeItem(Actor $owner, array $vars, array $items, array $collections): bool protected function removeItem(Actor $owner, array $vars, array $items, array $collections): bool
{ {
return DB::dql(<<<'EOF' return DB::dql(<<<'EOF'
@ -83,6 +94,11 @@ class AttachmentCollections extends Plugin
]); ]);
} }
/**
* @param array<string, mixed> $vars
* @param int[] $items
* @param array<string, mixed> $collections
*/
protected function addItem(Actor $owner, array $vars, array $items, array $collections): void protected function addItem(Actor $owner, array $vars, array $items, array $collections): void
{ {
foreach ($items as $id) { foreach ($items as $id) {
@ -97,14 +113,18 @@ class AttachmentCollections extends Plugin
} }
} }
protected function shouldAddToRightPanel(Actor $user, $vars, Request $request): bool /**
* @param array<string, mixed> $vars
*/
protected function shouldAddToRightPanel(Actor $user, array $vars, Request $request): bool
{ {
return $vars['path'] === 'note_attachment_show'; return $vars['path'] === 'note_attachment_show';
} }
/** /**
* @param array<string, mixed> $vars * @param array<string, mixed> $vars
* @return int[] *
* @return ($ids_only is true ? int[] : AttachmentCollection[])
*/ */
protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array
{ {

View File

@ -28,6 +28,9 @@ use App\Core\Router;
use Component\Collection\Util\Controller\MetaCollectionController; use Component\Collection\Util\Controller\MetaCollectionController;
use Plugin\AttachmentCollections\Entity\AttachmentCollection; use Plugin\AttachmentCollections\Entity\AttachmentCollection;
/**
* @extends MetaCollectionController<AttachmentCollection>
*/
class AttachmentCollections extends MetaCollectionController class AttachmentCollections extends MetaCollectionController
{ {
public function createCollection(int $owner_id, string $name): bool public function createCollection(int $owner_id, string $name): bool
@ -36,6 +39,8 @@ class AttachmentCollections extends MetaCollectionController
'name' => $name, 'name' => $name,
'actor_id' => $owner_id, 'actor_id' => $owner_id,
])); ]));
return true;
} }
public function getCollectionUrl(int $owner_id, ?string $owner_nickname, int $collection_id): string public function getCollectionUrl(int $owner_id, ?string $owner_nickname, int $collection_id): string
@ -51,7 +56,12 @@ class AttachmentCollections extends MetaCollectionController
['nickname' => $owner_nickname, 'cid' => $collection_id], ['nickname' => $owner_nickname, 'cid' => $collection_id],
); );
} }
public function getCollectionItems(int $owner_id, $collection_id): array
/**
* FIXME return value not consistent with base class
*/
// @phpstan-disable-next-line
public function getCollectionItems(int $owner_id, int $collection_id): array
{ {
[$attachs, $notes] = DB::dql( [$attachs, $notes] = DB::dql(
<<<'EOF' <<<'EOF'
@ -64,28 +74,30 @@ class AttachmentCollections extends MetaCollectionController
EOF, EOF,
['cid' => $collection_id], ['cid' => $collection_id],
); );
return [
'_template' => 'AttachmentCollections/collection_entry_view.html.twig', return ['_template' => 'AttachmentCollections/collection_entry_view.html.twig', 'attachments' => array_values($attachs), 'bare_notes' => array_values($notes)];
'attachments' => array_values($attachs),
'bare_notes' => array_values($notes),
];
} }
/**
* @return AttachmentCollection[]
*/
public function getCollectionsByActorId(int $owner_id): array public function getCollectionsByActorId(int $owner_id): array
{ {
return DB::findBy(AttachmentCollection::class, ['actor_id' => $owner_id], order_by: ['id' => 'desc']); return DB::findBy(AttachmentCollection::class, ['actor_id' => $owner_id], order_by: ['id' => 'desc']);
} }
public function getCollectionBy(int $owner_id, int $collection_id): AttachmentCollection public function getCollectionBy(int $owner_id, int $collection_id): AttachmentCollection
{ {
return DB::findOneBy(AttachmentCollection::class, ['id' => $collection_id]); return DB::findOneBy(AttachmentCollection::class, ['id' => $collection_id]);
} }
public function setCollectionName(int $actor_id, string $actor_nickname, AttachmentCollection $collection, string $name) public function setCollectionName(int $actor_id, string $actor_nickname, AttachmentCollection $collection, string $name): void
{ {
$collection->setName($name); $collection->setName($name);
DB::persist($collection); DB::persist($collection);
} }
public function removeCollection(int $actor_id, string $actor_nickname, AttachmentCollection $collection) public function removeCollection(int $actor_id, string $actor_nickname, AttachmentCollection $collection): void
{ {
DB::remove($collection); DB::remove($collection);
} }

View File

@ -55,7 +55,7 @@ class AttachmentShowRelated extends Plugin
/** /**
* Output our dedicated stylesheet * Output our dedicated stylesheet
* *
* @param array $styles stylesheets path * @param string[] $styles stylesheets path
*/ */
public function onEndShowStyles(array &$styles, string $path): EventResult public function onEndShowStyles(array &$styles, string $path): EventResult
{ {

View File

@ -54,6 +54,9 @@ class AudioEncoder extends Plugin
return GSFile::mimetypeMajor($mimetype) === 'audio'; return GSFile::mimetypeMajor($mimetype) === 'audio';
} }
/**
* @param array<string, callable> $event_map
*/
public function onFileMetaAvailable(array &$event_map, string $mimetype): EventResult public function onFileMetaAvailable(array &$event_map, string $mimetype): EventResult
{ {
if (!self::shouldHandle($mimetype)) { if (!self::shouldHandle($mimetype)) {
@ -90,6 +93,9 @@ class AudioEncoder extends Plugin
/** /**
* Generates the view for attachments of type Video * Generates the view for attachments of type Video
*
* @param (array{attachment: \Component\Attachment\Entity\Attachment, note: \App\Entity\Note, title: string} & array<string, mixed>) $vars
* @param array<string> $res
*/ */
public function onViewAttachment(array $vars, array &$res): EventResult public function onViewAttachment(array $vars, array &$res): EventResult
{ {
@ -109,6 +115,8 @@ class AudioEncoder extends Plugin
} }
/** /**
* @param ModuleVersionType[] $versions
*
* @throws ServerException * @throws ServerException
*/ */
public function onPluginVersion(array &$versions): EventResult public function onPluginVersion(array &$versions): EventResult

View File

@ -39,6 +39,10 @@ class Blog extends Plugin
return Event::next; return Event::next;
} }
/**
* @param (array{actor: \App\Entity\Actor} & array<string, mixed>) $vars
* @param array<string> $res
*/
public function onAppendCardProfile(array $vars, array &$res): EventResult public function onAppendCardProfile(array $vars, array &$res): EventResult
{ {
$actor = Common::actor(); $actor = Common::actor();

View File

@ -32,6 +32,9 @@ use Symfony\Component\HttpFoundation\Request;
class Bundles extends Plugin class Bundles extends Plugin
{ {
/**
* @phpstan-use MetaCollectionTrait<BundleCollection>
*/
use MetaCollectionTrait; use MetaCollectionTrait;
protected const SLUG = 'bundle'; protected const SLUG = 'bundle';
protected const PLURAL_SLUG = 'bundles'; protected const PLURAL_SLUG = 'bundles';
@ -55,6 +58,7 @@ class Bundles extends Plugin
/** /**
* @param array<string, mixed> $vars * @param array<string, mixed> $vars
* @param array<int> $items * @param array<int> $items
* @param array<mixed> $collections
*/ */
protected function removeItem(Actor $owner, array $vars, array $items, array $collections): bool protected function removeItem(Actor $owner, array $vars, array $items, array $collections): bool
{ {
@ -101,8 +105,11 @@ class Bundles extends Plugin
} }
/** /**
* @param array<string, mixed> $vars * FIXME incompatible return type
* @retrun int[] *
* @param null|array<string, mixed> $vars
*
* @return BundleCollection[]|int[]
*/ */
protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array
{ {

View File

@ -26,9 +26,12 @@ namespace Plugin\Bundles\Controller;
use App\Core\DB; use App\Core\DB;
use App\Core\Router; use App\Core\Router;
use Component\Collection\Util\Controller\MetaCollectionController; use Component\Collection\Util\Controller\MetaCollectionController;
use Plugin\Bundles\Entity\BundleCollection; use Plugin\Bundles\Entity\BundleCollection as BundleCollectionEntity;
class BundleCollections extends MetaCollectionController /**
* @extends MetaCollectionController<BundleCollectionEntity>
*/
class BundleCollection extends MetaCollectionController
{ {
public function getCollectionUrl(int $owner_id, ?string $owner_nickname, int $collection_id): string public function getCollectionUrl(int $owner_id, ?string $owner_nickname, int $collection_id): string
{ {
@ -44,7 +47,8 @@ class BundleCollections extends MetaCollectionController
); );
} }
public function getCollectionItems(int $owner_id, $collection_id): array // FIXME
public function getCollectionItems(int $owner_id, int $collection_id): array
{ {
[$notes] = DB::dql( [$notes] = DB::dql(
<<<'EOF' <<<'EOF'
@ -65,17 +69,17 @@ class BundleCollections extends MetaCollectionController
public function getCollectionsByActorId(int $owner_id): array public function getCollectionsByActorId(int $owner_id): array
{ {
return DB::findBy(BundleCollection::class, ['actor_id' => $owner_id], order_by: ['id' => 'desc']); return DB::findBy(BundleCollectionEntity::class, ['actor_id' => $owner_id], order_by: ['id' => 'desc']);
} }
public function getCollectionBy(int $owner_id, int $collection_id): BundleCollection public function getCollectionBy(int $owner_id, int $collection_id): BundleCollectionEntity
{ {
return DB::findOneBy(BundleCollection::class, ['id' => $collection_id]); return DB::findOneBy(BundleCollectionEntity::class, ['id' => $collection_id]);
} }
public function createCollection(int $owner_id, string $name): bool public function createCollection(int $owner_id, string $name): bool
{ {
DB::persist(BundleCollection::create([ DB::persist(BundleCollectionEntity::create([
'name' => $name, 'name' => $name,
'actor_id' => $owner_id, 'actor_id' => $owner_id,
])); ]));

View File

@ -58,7 +58,7 @@ class Cover
* @throws ClientException Invalid form * @throws ClientException Invalid form
* @throws ServerException Invalid file type * @throws ServerException Invalid file type
* *
* @return array template * @return ControllerResultType
*/ */
public static function coverSettings(Request $request): array public static function coverSettings(Request $request): array
{ {
@ -113,7 +113,7 @@ class Cover
// Only delete files if the commit went through // Only delete files if the commit went through
if ($old_file != null) { if ($old_file != null) {
foreach ($old_file as $f) { foreach ($old_file as $f) {
@unlink($f); @unlink($f->getPath());
} }
} }
throw new RedirectException(); throw new RedirectException();
@ -131,7 +131,7 @@ class Cover
DB::remove($cover); DB::remove($cover);
DB::flush(); DB::flush();
foreach ($old_file as $f) { foreach ($old_file as $f) {
@unlink($f); @unlink($f->getPath());
} }
throw new RedirectException(); throw new RedirectException();
} }

View File

@ -90,7 +90,7 @@ class Cover extends Plugin
/** /**
* Output our dedicated stylesheet * Output our dedicated stylesheet
* *
* @param array $styles stylesheets path * @param string[] $styles stylesheets path
*/ */
public function onStartShowStyles(array &$styles): EventResult public function onStartShowStyles(array &$styles): EventResult
{ {

View File

@ -117,7 +117,7 @@ class Cover extends Entity
/** /**
* Delete this cover and the corresponding attachment and thumbnails, which this owns * Delete this cover and the corresponding attachment and thumbnails, which this owns
* *
* @return array attachments deleted (if delete_attachments_now is true) * @return Attachment[] attachments deleted (if delete_attachments_now is true)
*/ */
public function delete(bool $flush = false, bool $delete_attachments_now = false, bool $cascading = false): array public function delete(bool $flush = false, bool $delete_attachments_now = false, bool $cascading = false): array
{ {

View File

@ -150,6 +150,8 @@ class DeleteNote extends NoteHandlerPlugin
* @throws \App\Util\Exception\DuplicateFoundException * @throws \App\Util\Exception\DuplicateFoundException
* @throws \App\Util\Exception\NotFoundException * @throws \App\Util\Exception\NotFoundException
* @throws \App\Util\Exception\ServerException * @throws \App\Util\Exception\ServerException
*
* @params string[] $actions
*/ */
public function onAddExtraNoteActions(Request $request, Note $note, array &$actions): EventResult public function onAddExtraNoteActions(Request $request, Note $note, array &$actions): EventResult
{ {

View File

@ -40,7 +40,7 @@ use EventResult;
class EmailNotifications extends Plugin class EmailNotifications extends Plugin
{ {
public function onAddNotificationTransport(&$form_defs): EventResult public function onAddNotificationTransport(array &$form_defs): EventResult
{ {
$form_defs['Email'] = $form_defs['placeholder']; $form_defs['Email'] = $form_defs['placeholder'];
$form_defs['Email'][] = $form_defs['placeholder']['save']('Email', 'save_email'); $form_defs['Email'][] = $form_defs['placeholder']['save']('Email', 'save_email');

View File

@ -216,7 +216,7 @@ class OEmbed extends Controller
/** /**
* Placeholder * Placeholder
*/ */
public function init_document($type) public function init_document(string $type): void
{ {
throw new NotImplementedException; throw new NotImplementedException;
// switch ($type) { // switch ($type) {
@ -243,7 +243,7 @@ class OEmbed extends Controller
/** /**
* Placeholder * Placeholder
*/ */
public function end_document($type) public function end_document(string $type): void
{ {
throw new NotImplementedException; throw new NotImplementedException;
// switch ($type) { // switch ($type) {

View File

@ -26,6 +26,7 @@ namespace Plugin\Favourite\Controller;
use App\Core\DB; use App\Core\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router; use App\Core\Router;
use App\Entity\Activity; use App\Entity\Activity;
@ -41,10 +42,12 @@ use App\Util\Exception\RedirectException;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
use Component\Collection\Util\Controller\FeedController; use Component\Collection\Util\Controller\FeedController;
use Component\Notification\Entity\Attention; use Component\Notification\Entity\Attention;
use function App\Core\I18n\_m;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/**
* @extends FeedController<Note>
*/
class Favourite extends FeedController class Favourite extends FeedController
{ {
/** /**

View File

@ -44,7 +44,8 @@ class LatexNotes extends Plugin
$types['LaTeX'] = 'application/x-latex'; $types['LaTeX'] = 'application/x-latex';
return Event::next; return Event::next;
} }
public function onRenderNoteContent($content, $content_type, &$rendered): EventResult
public function onRenderNoteContent(string $content, string $content_type, string &$rendered): EventResult
{ {
if ($content_type !== 'application/x-latex') { if ($content_type !== 'application/x-latex') {
return Event::next; return Event::next;

View File

@ -43,7 +43,8 @@ class MarkdownNotes extends Plugin
$types['Markdown'] = 'text/markdown'; $types['Markdown'] = 'text/markdown';
return Event::next; return Event::next;
} }
public function onRenderNoteContent($content, $content_type, &$rendered): EventResult
public function onRenderNoteContent(string $content, string $content_type, string &$rendered): EventResult
{ {
if ($content_type !== 'text/markdown') { if ($content_type !== 'text/markdown') {
return Event::next; return Event::next;

View File

@ -140,7 +140,7 @@ class NoteTypeFeedFilter extends Plugin
/** /**
* Draw the media feed navigation. * Draw the media feed navigation.
*/ */
public function onAddFeedActions(Request $request, bool $is_not_empty, &$res): EventResult public function onAddFeedActions(Request $request, bool $is_not_empty, array &$res): EventResult
{ {
$qs = []; $qs = [];
$query_string = $request->getQueryString(); $query_string = $request->getQueryString();

View File

@ -36,6 +36,9 @@ use League\OAuth2\Server\CryptKey;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use Plugin\OAuth2\Util\Token; use Plugin\OAuth2\Util\Token;
/**
* @extends Token<AccessToken>
*/
class AccessToken extends Token implements AccessTokenEntityInterface class AccessToken extends Token implements AccessTokenEntityInterface
{ {
// {{{ Autocode // {{{ Autocode

View File

@ -36,6 +36,9 @@ use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use Plugin\OAuth2\Repository; use Plugin\OAuth2\Repository;
use Plugin\OAuth2\Util\Token; use Plugin\OAuth2\Util\Token;
/**
* @extends Token<AuthCode>
*/
class AuthCode extends Token implements AuthCodeEntityInterface class AuthCode extends Token implements AuthCodeEntityInterface
{ {
// {{{ Autocode // {{{ Autocode

View File

@ -45,11 +45,17 @@ class RefreshToken implements RefreshTokenRepositoryInterface
DB::persist($refreshTokenEntity); DB::persist($refreshTokenEntity);
} }
/**
* @param string $tokenId
*/
public function revokeRefreshToken($tokenId) public function revokeRefreshToken($tokenId)
{ {
// Some logic to revoke the auth token in a database // Some logic to revoke the auth token in a database
} }
/**
* @param string $tokenId
*/
public function isRefreshtokenRevoked($tokenId): bool public function isRefreshtokenRevoked($tokenId): bool
{ {
return false; // The auth token has not been revoked return false; // The auth token has not been revoked

View File

@ -29,6 +29,7 @@ use function App\Core\I18n\_m;
use App\Core\Router; use App\Core\Router;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\LocalUser; use App\Entity\LocalUser;
use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\NoSuchNoteException; use App\Util\Exception\NoSuchNoteException;
@ -39,6 +40,9 @@ use Plugin\PinnedNotes\Entity as E;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
/**
* @extends FeedController<Note>
*/
class PinnedNotes extends FeedController class PinnedNotes extends FeedController
{ {
public function listPinsByNickname(Request $request, string $nickname) public function listPinsByNickname(Request $request, string $nickname)

View File

@ -16,7 +16,8 @@ class PinnedNotes extends Entity
{ {
return $this->id; return $this->id;
} }
public function setId($id)
public function setId(int $id): self
{ {
$this->id = $id; $this->id = $id;
return $this; return $this;
@ -26,7 +27,8 @@ class PinnedNotes extends Entity
{ {
return $this->actor_id; return $this->actor_id;
} }
public function setActorId($actor_id)
public function setActorId(int $actor_id): self
{ {
$this->actor_id = $actor_id; $this->actor_id = $actor_id;
return $this; return $this;
@ -36,7 +38,8 @@ class PinnedNotes extends Entity
{ {
return $this->note_id; return $this->note_id;
} }
public function setNoteId($note_id)
public function setNoteId(int $note_id): self
{ {
$this->note_id = $note_id; $this->note_id = $note_id;
return $this; return $this;

View File

@ -74,7 +74,7 @@ class PinnedNotes extends Plugin
return Event::next; return Event::next;
} }
public function onBeforeFeed(Request $request, &$res): EventResult public function onBeforeFeed(Request $request, array &$res): EventResult
{ {
$path = $request->attributes->get('_route'); $path = $request->attributes->get('_route');
if ($path === 'actor_view_nickname') { if ($path === 'actor_view_nickname') {
@ -160,7 +160,7 @@ class PinnedNotes extends Plugin
return Event::next; return Event::next;
} }
public function onActivityPubAddActivityStreamsTwoData(string $type_name, &$type): EventResult public function onActivityPubAddActivityStreamsTwoData(string $type_name, object &$type): EventResult
{ {
if ($type_name === 'Person') { if ($type_name === 'Person') {
$actor = \Plugin\ActivityPub\Util\Explorer::getOneFromUri($type->get('id')); $actor = \Plugin\ActivityPub\Util\Explorer::getOneFromUri($type->get('id'));

View File

@ -83,7 +83,7 @@ class UnboundGroup extends Plugin
return Event::next; return Event::next;
} }
public function onActivityPubAddActivityStreamsTwoData(string $type_name, &$type): EventResult public function onActivityPubAddActivityStreamsTwoData(string $type_name, object &$type): EventResult
{ {
if ($type_name === 'Group' || $type_name === 'Organization') { if ($type_name === 'Group' || $type_name === 'Organization') {
$actor = \Plugin\ActivityPub\Util\Explorer::getOneFromUri($type->getId()); $actor = \Plugin\ActivityPub\Util\Explorer::getOneFromUri($type->getId());

View File

@ -63,9 +63,6 @@ class WebMonetization extends Plugin
if (\is_null($user)) { if (\is_null($user)) {
return Event::next; return Event::next;
} }
if (\is_null($vars)) {
return Event::next;
}
$is_self = null; $is_self = null;
$receiver_id = null; $receiver_id = null;
@ -214,7 +211,7 @@ class WebMonetization extends Plugin
]; ];
} }
public function onAppendToHead(Request $request, &$res): EventResult public function onAppendToHead(Request $request, array &$res): EventResult
{ {
$user = Common::user(); $user = Common::user();
if (\is_null($user)) { if (\is_null($user)) {
@ -257,7 +254,7 @@ class WebMonetization extends Plugin
return Event::next; return Event::next;
} }
public function onActivityPubAddActivityStreamsTwoData(string $type_name, &$type): EventResult public function onActivityPubAddActivityStreamsTwoData(string $type_name, object &$type): EventResult
{ {
if ($type_name === 'Person') { if ($type_name === 'Person') {
$actor = \Plugin\ActivityPub\Util\Explorer::getOneFromUri($type->getId()); $actor = \Plugin\ActivityPub\Util\Explorer::getOneFromUri($type->getId());

View File

@ -40,7 +40,7 @@ use EventResult;
class XMPPNotifications extends Plugin class XMPPNotifications extends Plugin
{ {
public function onAddNotificationTransport(&$form_defs): EventResult public function onAddNotificationTransport(array &$form_defs): EventResult
{ {
$form_defs['XMPP'] = $form_defs['placeholder']; $form_defs['XMPP'] = $form_defs['placeholder'];
$form_defs['XMPP'][] = $form_defs['placeholder']['save']('XMPP', 'save_xmpp'); $form_defs['XMPP'][] = $form_defs['placeholder']['save']('XMPP', 'save_xmpp');

View File

@ -40,8 +40,12 @@ use Symfony\Component\Cache\CacheItem;
abstract class Cache abstract class Cache
{ {
protected static $pools; protected static array $pools;
protected static $redis;
/**
* @property ?Redis $redis
*/
protected static mixed $redis;
/** /**
* Configure a cache pool, with adapters taken from `ENV_VAR`. * Configure a cache pool, with adapters taken from `ENV_VAR`.
@ -77,8 +81,10 @@ abstract class Cache
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
// This requires extra server configuration, but the code was tested // This requires extra server configuration, but the code was tested
// manually and works, so it'll be excluded from automatic tests, for now, at least // manually and works, so it'll be excluded from automatic tests, for now, at least
if (F\Every($dsns, function ($str) { [$scheme, $rest] = explode('://', $str); if (F\Every($dsns, function ($str) {
return str_contains($rest, ':'); }) == false) { [$scheme, $rest] = explode('://', $str);
return str_contains($rest, ':');
}) == false) {
throw new ConfigurationException('The configuration of a redis cluster requires specifying the ports to use'); throw new ConfigurationException('The configuration of a redis cluster requires specifying the ports to use');
} }
$class = RedisCluster::class; // true for persistent connection $class = RedisCluster::class; // true for persistent connection

View File

@ -153,7 +153,8 @@ abstract class Controller extends AbstractController implements EventSubscriberI
$controller = $controller[0]; $controller = $controller[0];
} }
if (is_subclass_of($controller, FeedController::class)) { if (is_subclass_of($controller, FeedController::class)) {
$this->vars = $controller->postProcess($this->vars); // XXX
$this->vars = $controller->postProcess($this->vars); // @phpstan-ignore-line
} }
// Respond in the most preferred acceptable content type // Respond in the most preferred acceptable content type

View File

@ -45,6 +45,7 @@ use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Doctrine\ORM\Query\ResultSetMappingBuilder; use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
@ -89,8 +90,8 @@ use Functional as F;
*/ */
class DB class DB
{ {
private static ?EntityManagerInterface $em; private static null|\Doctrine\ORM\EntityManagerInterface|\Doctrine\Persistence\ObjectManager $em;
public static function setManager($m): void public static function setManager(EntityManagerInterface|\Doctrine\Persistence\ObjectManager $m): void
{ {
self::$em = $m; self::$em = $m;
} }
@ -104,6 +105,7 @@ class DB
private static ?array $dql_table_name_patterns = null; private static ?array $dql_table_name_patterns = null;
public static function initTableMap() public static function initTableMap()
{ {
/** @var ClassMetadataInfo[] $all */ // @phpstan-ignore-next-line
$all = self::$em->getMetadataFactory()->getAllMetadata(); $all = self::$em->getMetadataFactory()->getAllMetadata();
foreach ($all as $meta) { foreach ($all as $meta) {
self::$table_map[$meta->getTableName()] = $meta->getMetadataValue('name'); self::$table_map[$meta->getTableName()] = $meta->getMetadataValue('name');
@ -130,7 +132,7 @@ class DB
public static function dql(string $query, array $params = [], array $options = []) public static function dql(string $query, array $params = [], array $options = [])
{ {
$query = preg_replace(self::$dql_table_name_patterns, self::$table_map, $query); $query = preg_replace(self::$dql_table_name_patterns, self::$table_map, $query);
$q = new Query(self::$em); $q = new Query(self::$em); // @phpstan-ignore-line
$q->setDQL($query); $q->setDQL($query);
if (isset($options['limit'])) { if (isset($options['limit'])) {
@ -192,6 +194,7 @@ class DB
if ($_ENV['APP_ENV'] === 'dev' && str_starts_with($query, 'select *')) { if ($_ENV['APP_ENV'] === 'dev' && str_starts_with($query, 'select *')) {
throw new Exception('Cannot use `select *`, use `select {select}` (see ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT)'); throw new Exception('Cannot use `select *`, use `select {select}` (see ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT)');
} }
// @phpstan-ignore-next-line
$rsmb = new ResultSetMappingBuilder(self::$em, \is_null($entities) ? ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT : ResultSetMappingBuilder::COLUMN_RENAMING_NONE); $rsmb = new ResultSetMappingBuilder(self::$em, \is_null($entities) ? ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT : ResultSetMappingBuilder::COLUMN_RENAMING_NONE);
if (\is_null($entities)) { if (\is_null($entities)) {
$matches = []; $matches = [];
@ -205,6 +208,7 @@ class DB
$rsmb->addRootEntityFromClassMetadata($entity, $alias); $rsmb->addRootEntityFromClassMetadata($entity, $alias);
} }
$query = preg_replace('/{select}/', $rsmb->generateSelectClause(), $query); $query = preg_replace('/{select}/', $rsmb->generateSelectClause(), $query);
// @phpstan-ignore-next-line
$q = self::$em->createNativeQuery($query, $rsmb); $q = self::$em->createNativeQuery($query, $rsmb);
foreach ($params as $k => $v) { foreach ($params as $k => $v) {
$q->setParameter($k, $v); $q->setParameter($k, $v);
@ -263,7 +267,7 @@ class DB
{ {
$criteria = array_change_key_case($criteria, \CASE_LOWER); $criteria = array_change_key_case($criteria, \CASE_LOWER);
$ops = array_intersect(array_keys($criteria), self::$find_by_ops); $ops = array_intersect(array_keys($criteria), self::$find_by_ops);
/** @var EntityRepository */ /** @var EntityRepository */ // @phpstan-ignore-next-line
$repo = self::getRepository($table); $repo = self::getRepository($table);
if (empty($ops)) { if (empty($ops)) {
return $repo->findBy($criteria, $order_by, $limit, $offset); return $repo->findBy($criteria, $order_by, $limit, $offset);
@ -307,7 +311,7 @@ class DB
public static function count(string $table, array $criteria) public static function count(string $table, array $criteria)
{ {
/** @var EntityRepository */ /** @var EntityRepository */ // @phpstan-ignore-next-line
$repo = self::getRepository($table); $repo = self::getRepository($table);
return $repo->count($criteria); return $repo->count($criteria);
} }

View File

@ -32,9 +32,7 @@ declare(strict_types = 1);
namespace App\Core; namespace App\Core;
use App\Core\DB;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Router;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
@ -82,7 +80,7 @@ use Symfony\Component\HttpFoundation\Request;
abstract class Form abstract class Form
{ {
private static ?FormFactoryInterface $form_factory; private static ?FormFactoryInterface $form_factory;
public static function setFactory($ff): void public static function setFactory(FormFactoryInterface $ff): void
{ {
self::$form_factory = $ff; self::$form_factory = $ff;
} }

View File

@ -204,7 +204,7 @@ class GSFile
* Throw a client exception if the cache key $id doesn't contain * Throw a client exception if the cache key $id doesn't contain
* exactly one entry * exactly one entry
*/ */
public static function error($exception, $id, array $res) public static function error(string $exception, int $id, array $res): mixed
{ {
switch (\count($res)) { switch (\count($res)) {
case 0: case 0:

View File

@ -66,7 +66,7 @@ abstract class I18n
{ {
public static ?TranslatorInterface $translator = null; public static ?TranslatorInterface $translator = null;
public static function setTranslator($trans): void public static function setTranslator(TranslatorInterface $trans): void
{ {
self::$translator = $trans; self::$translator = $trans;
} }
@ -306,9 +306,11 @@ abstract class I18n
* _m(string|string[] $msg, array $params) -- parameterized message * _m(string|string[] $msg, array $params) -- parameterized message
* _m(string $ctx, string|string[] $msg, array $params) -- combination of the previous two * _m(string $ctx, string|string[] $msg, array $params) -- combination of the previous two
* *
* @throws ServerException
*
* @todo add parameters * @todo add parameters
*
* @param array|int|string ...$args
*
* @throws ServerException
*/ */
function _m(...$args): string function _m(...$args): string
{ {

View File

@ -127,6 +127,8 @@ class TransExtractor extends AbstractFileExtractor implements ExtractorInterface
/** /**
* Normalizes a token. * Normalizes a token.
*
* @param string $token
*/ */
protected function normalizeToken($token): ?string protected function normalizeToken($token): ?string
{ {
@ -186,6 +188,8 @@ class TransExtractor extends AbstractFileExtractor implements ExtractorInterface
/** /**
* {@inheritDoc} * {@inheritDoc}
*
* @param string $directory
*/ */
protected function extractFromDirectory($directory): iterable protected function extractFromDirectory($directory): iterable
{ {

View File

@ -53,7 +53,7 @@ abstract class Log
{ {
private static ?LoggerInterface $logger; private static ?LoggerInterface $logger;
public static function setLogger($l): void public static function setLogger(LoggerInterface $l): void
{ {
self::$logger = $l; self::$logger = $l;
} }
@ -62,6 +62,7 @@ abstract class Log
* Log a critical error when a really unexpected exception occured. This indicates a bug in the software * Log a critical error when a really unexpected exception occured. This indicates a bug in the software
* *
* @throws ServerException * @throws ServerException
*
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public static function unexpected_exception(Exception $e) public static function unexpected_exception(Exception $e)

View File

@ -52,11 +52,11 @@ use Symfony\Component\DependencyInjection\Reference;
class ModuleManager class ModuleManager
{ {
protected static $loader; protected static \Composer\Autoload\ClassLoader $loader;
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public static function setLoader($l) public static function setLoader(\Composer\Autoload\ClassLoader $l)
{ {
self::$loader = $l; self::$loader = $l;
} }
@ -161,7 +161,7 @@ class ModuleManager
/** /**
* Serialize this class, for dumping into the cache * Serialize this class, for dumping into the cache
*/ */
public static function __set_state($state) public static function __set_state(array $state): self
{ {
$obj = new self(); $obj = new self();
$obj->modules = $state['modules']; $obj->modules = $state['modules'];

View File

@ -54,7 +54,7 @@ abstract class Module
/** /**
* Serialize the class to store in the cache * Serialize the class to store in the cache
*/ */
public static function __set_state($state) public static function __set_state(array $state)
{ {
$obj = new (static::class); $obj = new (static::class);
foreach ($state as $k => $v) { foreach ($state as $k => $v) {

View File

@ -40,7 +40,7 @@ abstract class Queue
{ {
private static ?MessageBusInterface $message_bus; private static ?MessageBusInterface $message_bus;
public static function setMessageBus($mb): void public static function setMessageBus(MessageBusInterface $mb): void
{ {
self::$message_bus = $mb; self::$message_bus = $mb;
} }
@ -50,7 +50,7 @@ abstract class Queue
* *
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public static function enqueue($payload, string $queue, bool $priority = false, array $stamps = []) public static function enqueue(mixed $payload, string $queue, bool $priority = false, array $stamps = []): void
{ {
if ($priority) { if ($priority) {
self::$message_bus->dispatch(new MessageHigh($payload, $queue), $stamps); self::$message_bus->dispatch(new MessageHigh($payload, $queue), $stamps);

View File

@ -32,8 +32,6 @@ declare(strict_types = 1);
namespace App\Core; namespace App\Core;
use App\Core\Event;
use App\Core\Log;
use App\Util\Common; use App\Util\Common;
use Symfony\Component\Config\Loader\Loader; use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\ResourceNotFoundException;
@ -41,6 +39,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Router as SymfonyRouter; use Symfony\Component\Routing\Router as SymfonyRouter;
use Symfony\Component\Routing\RouterInterface;
/** /**
* @mixin SymfonyRouter * @mixin SymfonyRouter
@ -70,9 +69,9 @@ class Router extends Loader
*/ */
public const NETWORK_PATH = UrlGeneratorInterface::NETWORK_PATH; public const NETWORK_PATH = UrlGeneratorInterface::NETWORK_PATH;
public static ?SymfonyRouter $router = null; public static ?RouterInterface $router = null;
public static function setRouter($rtr): void public static function setRouter(RouterInterface $rtr): void
{ {
self::$router = $rtr; self::$router = $rtr;
} }
@ -122,6 +121,7 @@ class Router extends Loader
* *
* Must conform to symfony's interface, but the $resource is unused * Must conform to symfony's interface, but the $resource is unused
* and $type must not be null * and $type must not be null
* @param string $resource
*/ */
public function load($resource, ?string $type = null): RouteCollection public function load($resource, ?string $type = null): RouteCollection
{ {

View File

@ -50,6 +50,8 @@ class RouteLoader extends Loader
* *
* Must conform to symfony's interface, but the $resource is unused * Must conform to symfony's interface, but the $resource is unused
* and $type must not be null * and $type must not be null
*
* @param resource $resource
*/ */
public function load($resource, ?string $type = null): RouteCollection public function load($resource, ?string $type = null): RouteCollection
{ {

View File

@ -46,6 +46,7 @@ use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
* HtmlSanitizer\SanitizerInterface, calling the first existing method, in that order * HtmlSanitizer\SanitizerInterface, calling the first existing method, in that order
* *
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @mixin SymfonySecurity * @mixin SymfonySecurity
* *
* @method static LocalUser getUser() * @method static LocalUser getUser()
@ -53,7 +54,7 @@ use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
class Security implements EventSubscriberInterface //implements AuthenticatorInterface class Security implements EventSubscriberInterface //implements AuthenticatorInterface
{ {
private static ?SymfonySecurity $security; private static ?SymfonySecurity $security;
public static function setHelper($sec): void public static function setHelper(SymfonySecurity $sec): void
{ {
self::$security = $sec; self::$security = $sec;
} }

View File

@ -94,6 +94,9 @@ class SchemaDefDriver extends StaticPHPDriver implements CompilerPassInterface
* Fill in the database $metadata for $class_name * Fill in the database $metadata for $class_name
* *
* @param class-string $class_name * @param class-string $class_name
*
* @phpstan-ignore-next-line
*
* @param ClassMetadataInfo $metadata ClassMetadataInfo is the real type, but we need to override the method * @param ClassMetadataInfo $metadata ClassMetadataInfo is the real type, but we need to override the method
*/ */
public function loadMetadataForClass($class_name, ClassMetadata $metadata): void public function loadMetadataForClass($class_name, ClassMetadata $metadata): void
@ -213,6 +216,8 @@ class SchemaDefDriver extends StaticPHPDriver implements CompilerPassInterface
* Override StaticPHPDriver's method, * Override StaticPHPDriver's method,
* we care about classes that have the method `schemaDef`, * we care about classes that have the method `schemaDef`,
* instead of `loadMetadata`. * instead of `loadMetadata`.
*
* @param mixed $class_name
*/ */
public function isTransient($class_name): bool public function isTransient($class_name): bool
{ {

View File

@ -550,6 +550,10 @@ class Actor extends Entity
} }
} }
public function hasBlocked(self $other): bool {
return false;
}
public function __call(string $name, array $arguments): mixed public function __call(string $name, array $arguments): mixed
{ {
if (Formatting::startsWith($name, 'is')) { if (Formatting::startsWith($name, 'is')) {

View File

@ -17,6 +17,8 @@ use SymfonyCasts\Bundle\ResetPassword\Persistence\ResetPasswordRequestRepository
* @method null|ResetPasswordRequest findOneBy(array $criteria, array $orderBy = null) * @method null|ResetPasswordRequest findOneBy(array $criteria, array $orderBy = null)
* @method ResetPasswordRequest[] findAll() * @method ResetPasswordRequest[] findAll()
* @method ResetPasswordRequest[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) * @method ResetPasswordRequest[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*
* @extends ServiceEntityRepository<ResetPasswordRequest>
*/ */
class ResetPasswordRequestRepository extends ServiceEntityRepository implements ResetPasswordRequestRepositoryInterface class ResetPasswordRequestRepository extends ServiceEntityRepository implements ResetPasswordRequestRepositoryInterface
{ {

View File

@ -116,6 +116,8 @@ class Runtime implements RuntimeExtensionInterface, EventSubscriberInterface
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param null|string ...$args
*/ */
public function getConfig(...$args) public function getConfig(...$args)
{ {
@ -125,10 +127,11 @@ class Runtime implements RuntimeExtensionInterface, EventSubscriberInterface
/** /**
* get stylesheets * get stylesheets
* *
* @return array|mixed
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @return array<string>
*/ */
public function getShowStylesheets($route) public function getShowStylesheets(string $route): array
{ {
$styles = []; $styles = [];
Event::handle('EndShowStyles', [&$styles, $route]); Event::handle('EndShowStyles', [&$styles, $route]);
@ -137,8 +140,11 @@ class Runtime implements RuntimeExtensionInterface, EventSubscriberInterface
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
*
* @param mixed ...$args
* @return mixed[]
*/ */
public function handleEvent(string $event, ...$args) public function handleEvent(string $event, ...$args): array
{ {
$res = []; $res = [];
$args[] = &$res; $args[] = &$res;
@ -164,7 +170,7 @@ class Runtime implements RuntimeExtensionInterface, EventSubscriberInterface
&& (preg_match(pattern: $re_has_gecko, subject: $this->request->headers->get('User-Agent')) === 1); && (preg_match(pattern: $re_has_gecko, subject: $this->request->headers->get('User-Agent')) === 1);
} }
public function isInstanceOf($value, string $type): bool public function isInstanceOf(mixed $value, string $type): bool
{ {
return (\function_exists($func = 'is_' . $type) && $func($value)) || $value instanceof $type; return (\function_exists($func = 'is_' . $type) && $func($value)) || $value instanceof $type;
} }

View File

@ -108,7 +108,7 @@ abstract class Common
* *
* @param bool $transient keep this setting in memory only * @param bool $transient keep this setting in memory only
*/ */
public static function setConfig(string $section, string $setting, $value, bool $transient = false): void public static function setConfig(string $section, string $setting, mixed $value, bool $transient = false): void
{ {
self::$config[$section][$setting] = $value; self::$config[$section][$setting] = $value;
if (!$transient) { if (!$transient) {
@ -184,8 +184,13 @@ abstract class Common
/** /**
* A recursive `array_diff`, while PHP itself doesn't provide one * A recursive `array_diff`, while PHP itself doesn't provide one
*
* @param mixed[] $array1
* @param mixed[] $array2
*
* @return mixed[]
*/ */
public static function arrayDiffRecursive($array1, $array2): array public static function arrayDiffRecursive(array $array1, array $array2): array
{ {
$diff = []; $diff = [];
foreach ($array1 as $key => $value) { foreach ($array1 as $key => $value) {

View File

@ -191,7 +191,7 @@ abstract class Formatting
/** /**
* Convert scalars, objects implementing __toString or arrays to strings * Convert scalars, objects implementing __toString or arrays to strings
*/ */
public static function toString($value, string $join_type = self::JOIN_BY_COMMA): string public static function toString(mixed $value, string $join_type = self::JOIN_BY_COMMA): string
{ {
if (!\in_array($join_type, [static::JOIN_BY_SPACE, static::JOIN_BY_COMMA])) { if (!\in_array($join_type, [static::JOIN_BY_SPACE, static::JOIN_BY_COMMA])) {
throw new Exception('Formatting::toString received invalid join option'); throw new Exception('Formatting::toString received invalid join option');
@ -209,7 +209,7 @@ abstract class Formatting
* *
* @param static::SPLIT_BY_BOTH|static::SPLIT_BY_COMMA|static::SPLIT_BY_SPACE $split_type * @param static::SPLIT_BY_BOTH|static::SPLIT_BY_COMMA|static::SPLIT_BY_SPACE $split_type
*/ */
public static function toArray(string $input, &$output, string $split_type = self::SPLIT_BY_COMMA): bool public static function toArray(string $input, array &$output, string $split_type = self::SPLIT_BY_COMMA): bool
{ {
if ($input == '') { if ($input == '') {
$output = []; $output = [];

View File

@ -57,7 +57,7 @@ abstract class HTML
public const SELF_CLOSING_TAG = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'link', 'meta', 'param', 'source', 'track', 'wbr']; public const SELF_CLOSING_TAG = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
private static ?SanitizerInterface $sanitizer; private static ?SanitizerInterface $sanitizer;
public static function setSanitizer($sanitizer): void public static function setSanitizer(SanitizerInterface $sanitizer): void
{ {
self::$sanitizer = $sanitizer; self::$sanitizer = $sanitizer;
} }

View File

@ -42,7 +42,9 @@ use Symfony\Component\Mime\MimeTypes;
*/ */
class TemporaryFile extends SplFileInfo class TemporaryFile extends SplFileInfo
{ {
// Cannot type annotate currently. `resource` is the expected type, but it's not a builtin type /**
* @var null|false|resource $resource
*/
protected $resource; protected $resource;
/** /**