[TOOLS] Continue raising PHPStan level to 6
This commit is contained in:
parent
c31f3d4997
commit
2fd46ca886
@ -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.
|
||||
'no_spaces_inside_parenthesis' => true,
|
||||
// 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.
|
||||
'no_trailing_comma_in_list_call' => true,
|
||||
// PHP single-line arrays should not have trailing comma.
|
||||
|
@ -54,7 +54,7 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
*/
|
||||
class Circle extends Component
|
||||
{
|
||||
/** @phpstan-use MetaCollectionTrait<Circle> */
|
||||
/** @phpstan-use MetaCollectionTrait<ActorCircle> */
|
||||
use MetaCollectionTrait;
|
||||
public const TAG_CIRCLE_REGEX = '/' . Nickname::BEFORE_MENTIONS . '@#([\pL\pN_\-\.]{1,64})/';
|
||||
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 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
|
||||
{
|
||||
|
@ -90,14 +90,12 @@ class Circles extends MetaCollectionController
|
||||
return $this->getCollectionItems($tagger_id, $circle_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ActorCircle[]
|
||||
*/
|
||||
public function getCollectionsByActorId(int $owner_id): array
|
||||
{
|
||||
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]);
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ class Collection extends Component
|
||||
*
|
||||
* @param array<string, OrderByType> $note_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
|
||||
{
|
||||
@ -84,6 +85,9 @@ class Collection extends Component
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param mixed $note_expr
|
||||
* @param mixed $actor_expr
|
||||
*/
|
||||
public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult
|
||||
{
|
||||
@ -91,50 +95,50 @@ class Collection extends Component
|
||||
$term = explode(':', $term);
|
||||
if (Formatting::startsWith($term[0], 'note')) {
|
||||
switch ($term[0]) {
|
||||
case 'notes-all':
|
||||
$note_expr = $eb->neq('note.created', null);
|
||||
break;
|
||||
case 'note-local':
|
||||
$note_expr = $eb->eq('note.is_local', filter_var($term[1], \FILTER_VALIDATE_BOOLEAN));
|
||||
break;
|
||||
case 'note-types':
|
||||
case 'notes-include':
|
||||
case 'note-filter':
|
||||
if (\is_null($note_expr)) {
|
||||
$note_expr = [];
|
||||
}
|
||||
if (array_intersect(explode(',', $term[1]), ['text', 'words']) !== []) {
|
||||
$note_expr[] = $eb->neq('note.content', null);
|
||||
} else {
|
||||
$note_expr[] = $eb->eq('note.content', null);
|
||||
}
|
||||
break;
|
||||
case 'note-conversation':
|
||||
$note_expr = $eb->eq('note.conversation_id', (int) trim($term[1]));
|
||||
break;
|
||||
case 'note-from':
|
||||
case 'notes-from':
|
||||
$subscribed_expr = $eb->eq('subscription.subscriber_id', $actor->getId());
|
||||
$type_consts = [];
|
||||
if ($term[1] === 'subscribed') {
|
||||
$type_consts = null;
|
||||
}
|
||||
foreach (explode(',', $term[1]) as $from) {
|
||||
if (str_starts_with($from, 'subscribed-')) {
|
||||
[, $type] = explode('-', $from);
|
||||
if (\in_array($type, ['actor', 'actors'])) {
|
||||
$type_consts = null;
|
||||
} else {
|
||||
$type_consts[] = \constant(Actor::class . '::' . mb_strtoupper($type === 'organisation' ? 'group' : $type));
|
||||
case 'notes-all':
|
||||
$note_expr = $eb->neq('note.created', null);
|
||||
break;
|
||||
case 'note-local':
|
||||
$note_expr = $eb->eq('note.is_local', filter_var($term[1], \FILTER_VALIDATE_BOOLEAN));
|
||||
break;
|
||||
case 'note-types':
|
||||
case 'notes-include':
|
||||
case 'note-filter':
|
||||
if (\is_null($note_expr)) {
|
||||
$note_expr = [];
|
||||
}
|
||||
if (array_intersect(explode(',', $term[1]), ['text', 'words']) !== []) {
|
||||
$note_expr[] = $eb->neq('note.content', null);
|
||||
} else {
|
||||
$note_expr[] = $eb->eq('note.content', null);
|
||||
}
|
||||
break;
|
||||
case 'note-conversation':
|
||||
$note_expr = $eb->eq('note.conversation_id', (int) trim($term[1]));
|
||||
break;
|
||||
case 'note-from':
|
||||
case 'notes-from':
|
||||
$subscribed_expr = $eb->eq('subscription.subscriber_id', $actor->getId());
|
||||
$type_consts = [];
|
||||
if ($term[1] === 'subscribed') {
|
||||
$type_consts = null;
|
||||
}
|
||||
foreach (explode(',', $term[1]) as $from) {
|
||||
if (str_starts_with($from, 'subscribed-')) {
|
||||
[, $type] = explode('-', $from);
|
||||
if (\in_array($type, ['actor', 'actors'])) {
|
||||
$type_consts = null;
|
||||
} else {
|
||||
$type_consts[] = \constant(Actor::class . '::' . mb_strtoupper($type === 'organisation' ? 'group' : $type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (\is_null($type_consts)) {
|
||||
$note_expr = $subscribed_expr;
|
||||
} elseif (!empty($type_consts)) {
|
||||
$note_expr = $eb->andX($subscribed_expr, $eb->in('note_actor.type', $type_consts));
|
||||
}
|
||||
break;
|
||||
if (\is_null($type_consts)) {
|
||||
$note_expr = $subscribed_expr;
|
||||
} elseif (!empty($type_consts)) {
|
||||
$note_expr = $eb->andX($subscribed_expr, $eb->in('note_actor.type', $type_consts));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} elseif (Formatting::startsWith($term, 'actor-')) {
|
||||
switch ($term[0]) {
|
||||
@ -148,8 +152,8 @@ class Collection extends Component
|
||||
foreach (
|
||||
[
|
||||
Actor::PERSON => ['person', 'people'],
|
||||
Actor::GROUP => ['group', 'groups', 'org', 'orgs', 'organisation', 'organisations', 'organization', 'organizations'],
|
||||
Actor::BOT => ['bot', 'bots'],
|
||||
Actor::GROUP => ['group', 'groups', 'org', 'orgs', 'organisation', 'organisations', 'organization', 'organizations'],
|
||||
Actor::BOT => ['bot', 'bots'],
|
||||
] as $type => $match) {
|
||||
if (array_intersect(explode(',', $term[1]), $match) !== []) {
|
||||
$actor_expr[] = $eb->eq('actor.type', $type);
|
||||
|
@ -4,6 +4,9 @@ declare(strict_types = 1);
|
||||
|
||||
namespace Component\Collection\Util\Controller;
|
||||
|
||||
/**
|
||||
* @extends OrderedCollection<\Component\Circle\Entity\ActorCircle>
|
||||
*/
|
||||
class CircleController extends OrderedCollection
|
||||
{
|
||||
}
|
||||
|
@ -6,18 +6,20 @@ namespace Component\Collection\Util\Controller;
|
||||
|
||||
use App\Core\Controller;
|
||||
use App\Entity\Actor;
|
||||
use App\Entity\Note;
|
||||
use App\Util\Common;
|
||||
use Component\Collection\Collection as CollectionComponent;
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Collection extends Controller
|
||||
abstract class Collection extends Controller
|
||||
{
|
||||
/**
|
||||
* @param array<string, OrderByType> $note_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
|
||||
{
|
||||
|
@ -38,6 +38,11 @@ use App\Entity\Note;
|
||||
use App\Util\Common;
|
||||
use Functional as F;
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*
|
||||
* @extends OrderedCollection<T>
|
||||
*/
|
||||
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
|
||||
* list of notes into a usable format
|
||||
*
|
||||
* @template T of Note|Actor
|
||||
* @param T[] $result
|
||||
* @return T[]
|
||||
* @template NA of Note|Actor
|
||||
*
|
||||
* @param NA[] $result
|
||||
*
|
||||
* @return NA[]
|
||||
*/
|
||||
protected function postProcess(array $result): array
|
||||
{
|
||||
|
@ -39,10 +39,13 @@ use App\Util\Common;
|
||||
use App\Util\Exception\RedirectException;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template T of object
|
||||
*
|
||||
* @extends FeedController<T>
|
||||
*/
|
||||
abstract class MetaCollectionController extends FeedController
|
||||
{
|
||||
@ -70,7 +73,7 @@ abstract class MetaCollectionController extends FeedController
|
||||
abstract public function createCollection(int $owner_id, string $name): bool;
|
||||
|
||||
/**
|
||||
* @return T[]
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
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
|
||||
{
|
||||
@ -135,34 +138,23 @@ abstract class MetaCollectionController extends FeedController
|
||||
// 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
|
||||
$fn = new class($id, $nickname, $request, $this, static::SLUG) {
|
||||
private $id;
|
||||
private $nick;
|
||||
private $request;
|
||||
private $parent;
|
||||
private $slug;
|
||||
|
||||
public function __construct($id, $nickname, $request, $parent, $slug)
|
||||
public function __construct(private int $id, private string $nickname, private Request $request, private object $parent, private string $slug)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->nick = $nickname;
|
||||
$this->request = $request;
|
||||
$this->parent = $parent;
|
||||
$this->slug = $slug;
|
||||
}
|
||||
// there's already an injected function called path,
|
||||
// that maps to Router::url(name, args), but since
|
||||
// I want to preserve nicknames, I think it's better
|
||||
// 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
|
||||
// forms for each one of them: one form to edit the collection's
|
||||
// name and another to remove the collection.
|
||||
|
||||
// creating the edit form
|
||||
public function editForm($collection)
|
||||
public function editForm(object $collection): FormView
|
||||
{
|
||||
$edit = Form::create([
|
||||
['name', TextType::class, [
|
||||
@ -181,7 +173,7 @@ abstract class MetaCollectionController extends FeedController
|
||||
]);
|
||||
$edit->handleRequest($this->request);
|
||||
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();
|
||||
throw new RedirectException();
|
||||
}
|
||||
@ -189,7 +181,7 @@ abstract class MetaCollectionController extends FeedController
|
||||
}
|
||||
|
||||
// creating the remove form
|
||||
public function rmForm($collection)
|
||||
public function rmForm(object $collection): FormView
|
||||
{
|
||||
$rm = Form::create([
|
||||
['remove_' . $collection->getId(), SubmitType::class, [
|
||||
@ -202,7 +194,7 @@ abstract class MetaCollectionController extends FeedController
|
||||
]);
|
||||
$rm->handleRequest($this->request);
|
||||
if ($rm->isSubmitted()) {
|
||||
$this->parent->removeCollection($this->id, $this->nick, $collection);
|
||||
$this->parent->removeCollection($this->id, $this->nickname, $collection);
|
||||
DB::flush();
|
||||
throw new RedirectException();
|
||||
}
|
||||
@ -220,12 +212,18 @@ abstract class MetaCollectionController extends FeedController
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function collectionsEntryViewNotesByNickname(Request $request, string $nickname, int $cid): array
|
||||
{
|
||||
$user = DB::findOneBy(LocalUser::class, ['nickname' => $nickname]);
|
||||
return self::collectionsEntryViewNotesByActorId($request, $user->getId(), $cid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function collectionsEntryViewNotesByActorId(Request $request, int $id, int $cid): array
|
||||
{
|
||||
$collection = $this->getCollectionBy($id, $cid);
|
||||
|
@ -4,6 +4,11 @@ declare(strict_types = 1);
|
||||
|
||||
namespace Component\Collection\Util\Controller;
|
||||
|
||||
class OrderedCollection extends Collection
|
||||
/**
|
||||
* @template T
|
||||
*
|
||||
* @extends Collection<T>
|
||||
*/
|
||||
abstract class OrderedCollection extends Collection
|
||||
{
|
||||
}
|
||||
|
@ -56,9 +56,9 @@ trait MetaCollectionTrait
|
||||
/**
|
||||
* create a collection owned by Actor $owner.
|
||||
*
|
||||
* @param Actor $owner The collection's owner
|
||||
* @param array<string, mixed> $vars Page vars sent by AppendRightPanelBlock event
|
||||
* @param string $name Collection's name
|
||||
* @param Actor $owner The collection's owner
|
||||
* @param array<string, mixed> $vars Page vars sent by AppendRightPanelBlock event
|
||||
* @param string $name Collection's name
|
||||
*/
|
||||
abstract protected function createCollection(Actor $owner, array $vars, string $name): void;
|
||||
/**
|
||||
@ -82,6 +82,7 @@ trait MetaCollectionTrait
|
||||
|
||||
/**
|
||||
* Check the route to determine whether the widget should be added
|
||||
*
|
||||
* @param array<string, mixed> $vars
|
||||
*/
|
||||
abstract protected function shouldAddToRightPanel(Actor $user, array $vars, Request $request): bool;
|
||||
@ -91,7 +92,8 @@ trait MetaCollectionTrait
|
||||
* @param Actor $owner Collection's owner
|
||||
* @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
|
||||
* @return T[]|int[]
|
||||
*
|
||||
* @return int[]|T[]
|
||||
*/
|
||||
abstract protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array;
|
||||
|
||||
@ -101,7 +103,7 @@ trait MetaCollectionTrait
|
||||
* the current item to, and another to create a new collection.
|
||||
*
|
||||
* @param array<string, mixed> $vars
|
||||
* @param string[] $res
|
||||
* @param string[] $res
|
||||
*/
|
||||
public function onAppendRightPanelBlock(Request $request, array $vars, array &$res): EventResult
|
||||
{
|
||||
@ -146,7 +148,7 @@ trait MetaCollectionTrait
|
||||
if ($add_form->isSubmitted() && $add_form->isValid()) {
|
||||
$selected = $add_form->getData()['collections'];
|
||||
$removed = array_filter($already_selected, fn ($x) => !\in_array($x, $selected));
|
||||
$added = array_filter($selected, fn ($x) => !\in_array($x, $already_selected));
|
||||
$added = array_filter($selected, fn ($x) => !\in_array($x, $already_selected));
|
||||
if (\count($removed) > 0) {
|
||||
$this->removeItem($user, $vars, $removed, $collections);
|
||||
}
|
||||
@ -196,7 +198,7 @@ trait MetaCollectionTrait
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[]
|
||||
* @param string[] $styles
|
||||
*/
|
||||
public function onEndShowStyles(array &$styles, string $route): EventResult
|
||||
{
|
||||
|
@ -32,6 +32,9 @@ abstract class Parser
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
|
@ -46,6 +46,9 @@ use Component\Conversation\Entity\ConversationMute;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @extends FeedController<\App\Entity\Note>
|
||||
*/
|
||||
class Conversation extends FeedController
|
||||
{
|
||||
/**
|
||||
@ -55,7 +58,10 @@ class Conversation extends FeedController
|
||||
*
|
||||
* @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
|
||||
{
|
||||
@ -83,7 +89,7 @@ class Conversation extends FeedController
|
||||
* @throws NoSuchNoteException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return array
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function addReply(Request $request)
|
||||
{
|
||||
@ -103,7 +109,7 @@ class Conversation extends FeedController
|
||||
* @throws \App\Util\Exception\RedirectException
|
||||
* @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)
|
||||
{
|
||||
|
@ -95,11 +95,13 @@ class Conversation extends Component
|
||||
* HTML rendering event that adds a reply link as a note
|
||||
* action, if a user is logged in.
|
||||
*
|
||||
* @param \App\Entity\Note $note The Note being rendered
|
||||
* @param array $actions Contains keys 'url' (linking 'conversation_reply_to'
|
||||
* route), 'title' (used as title for aforementioned url),
|
||||
* 'classes' (CSS styling 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)
|
||||
* @param \App\Entity\Note $note The Note being rendered
|
||||
* @param array{url: string, title: string, classes: string, id: string} $actions
|
||||
* Contains keys 'url' (linking 'conversation_reply_to' route),
|
||||
* 'title' (used as title for aforementioned url), 'classes' (CSS styling
|
||||
* 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
|
||||
*/
|
||||
@ -138,8 +140,11 @@ class Conversation extends Component
|
||||
/**
|
||||
* Append on note information about user actions.
|
||||
*
|
||||
* @param array $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<string, mixed> $vars Contains information related to Note currently being rendered
|
||||
* @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
|
||||
{
|
||||
@ -206,7 +211,7 @@ class Conversation extends Component
|
||||
/**
|
||||
* 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\NoSuchNoteException
|
||||
@ -224,6 +229,8 @@ class Conversation extends Component
|
||||
|
||||
/**
|
||||
* Add minimal Note card to RightPanel template
|
||||
*
|
||||
* @param string[] $elements
|
||||
*/
|
||||
public function onPrependPostingForm(Request $request, array &$elements): EventResult
|
||||
{
|
||||
@ -250,8 +257,10 @@ class Conversation extends Component
|
||||
/**
|
||||
* Adds extra actions related to Conversation Component, that act upon/from the given Note.
|
||||
*
|
||||
* @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 \App\Entity\Note $note Current Note being rendered
|
||||
* @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
|
||||
*/
|
||||
|
@ -41,10 +41,15 @@ use App\Util\HTML\Heading;
|
||||
use Component\Collection\Util\Controller\FeedController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @extends FeedController<\App\Entity\Note>
|
||||
*/
|
||||
class Feeds extends FeedController
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
@ -60,6 +65,8 @@ class Feeds extends FeedController
|
||||
|
||||
/**
|
||||
* The Home feed represents everything that concerns a certain actor (its subscriptions)
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function home(Request $request): array
|
||||
{
|
||||
|
@ -244,6 +244,8 @@ class FreeNetwork extends Component
|
||||
|
||||
/**
|
||||
* Add a link header for LRDD Discovery
|
||||
*
|
||||
* @param mixed $action
|
||||
*/
|
||||
public function onStartShowHTML($action): EventResult
|
||||
{
|
||||
@ -344,6 +346,7 @@ class FreeNetwork extends Component
|
||||
* @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
|
||||
*
|
||||
* @example.com/mublog/user
|
||||
*/
|
||||
public static function extractUrlMentions(string $text, string $preMention = '@'): array
|
||||
@ -375,6 +378,7 @@ class FreeNetwork extends Component
|
||||
* @param $mentions
|
||||
*
|
||||
* @return bool hook return value
|
||||
*
|
||||
* @example.com/mublog/user
|
||||
*/
|
||||
public function onEndFindMentions(Actor $sender, string $text, array &$mentions): EventResult
|
||||
@ -496,6 +500,9 @@ class FreeNetwork extends Component
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Actor[] $targets
|
||||
*/
|
||||
public static function notify(Actor $sender, Activity $activity, array $targets, ?string $reason = null): bool
|
||||
{
|
||||
foreach (self::$protocols as $protocol) {
|
||||
@ -517,6 +524,9 @@ class FreeNetwork extends Component
|
||||
/**
|
||||
* Add fediverse: query expression
|
||||
* // 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
|
||||
{
|
||||
|
@ -61,6 +61,8 @@ class Group extends Controller
|
||||
*
|
||||
* @throws RedirectException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function groupCreate(Request $request): array
|
||||
{
|
||||
@ -89,6 +91,8 @@ class Group extends Controller
|
||||
* @throws NicknameTooLongException
|
||||
* @throws NotFoundException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function groupSettings(Request $request, int $id): array
|
||||
{
|
||||
|
@ -40,10 +40,15 @@ use Component\Subscription\Entity\ActorSubscription;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @extends FeedController<\App\Entity\Note>
|
||||
*/
|
||||
class GroupFeed extends FeedController
|
||||
{
|
||||
/**
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function groupView(Request $request, Actor $group): array
|
||||
{
|
||||
@ -96,6 +101,8 @@ class GroupFeed extends FeedController
|
||||
/**
|
||||
* @throws ClientException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function groupViewId(Request $request, int $id): array
|
||||
{
|
||||
@ -119,6 +126,8 @@ class GroupFeed extends FeedController
|
||||
*
|
||||
* @throws ClientException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function groupViewNickname(Request $request, string $nickname): array
|
||||
{
|
||||
|
@ -50,6 +50,8 @@ class Group extends Component
|
||||
/**
|
||||
* Enqueues a notification for an Actor (such as person or group) which means
|
||||
* 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
|
||||
{
|
||||
@ -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
|
||||
*
|
||||
* @param array<string, mixed> $vars
|
||||
* @param string[] $res
|
||||
*/
|
||||
public function onAppendCardProfile(array $vars, array &$res): EventResult
|
||||
{
|
||||
@ -109,6 +114,9 @@ class Group extends Component
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Actor[] $targets
|
||||
*/
|
||||
public function onPostingFillTargetChoices(Request $request, Actor $actor, array &$targets): EventResult
|
||||
{
|
||||
$group = $this->getGroupFromContext($request);
|
||||
|
@ -70,7 +70,7 @@ class Language extends Controller
|
||||
['actor_id' => $user->getId()],
|
||||
);
|
||||
|
||||
$new_langs = array_udiff($selected_langs, $existing_langs, fn ($l, $r) => $l->getId() <=> $r->getId());
|
||||
$new_langs = array_udiff($selected_langs, $existing_langs, fn ($l, $r) => $l->getId() <=> $r->getId());
|
||||
$removing_langs = array_udiff($existing_langs, $selected_langs, fn ($l, $r) => $l->getId() <=> $r->getId());
|
||||
foreach ($new_langs as $l) {
|
||||
DB::persist(ActorLanguage::create(['actor_id' => $user->getId(), 'language_id' => $l->getId(), 'ordering' => 0]));
|
||||
@ -100,6 +100,8 @@ class Language extends Controller
|
||||
* @throws NoLoggedInUser
|
||||
* @throws RedirectException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function sortLanguages(Request $request): array
|
||||
{
|
||||
|
@ -119,6 +119,9 @@ class ActorLanguage extends Entity
|
||||
) ?: [Language::getByLocale(Common::config('site', 'language'))];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public static function getActorRelatedLanguagesIds(Actor $actor): array
|
||||
{
|
||||
return Cache::getList(
|
||||
|
@ -134,6 +134,9 @@ class Language extends Entity
|
||||
return self::getById($note->getLanguageId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function getLanguageChoices(): array
|
||||
{
|
||||
$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<string, string> */
|
||||
public function toChoiceFormat(): array
|
||||
{
|
||||
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
|
||||
* 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
|
||||
{
|
||||
|
@ -45,6 +45,9 @@ class Language extends Component
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Note[] $notes
|
||||
*/
|
||||
public function onFilterNoteList(?Actor $actor, array &$notes, Request $request): EventResult
|
||||
{
|
||||
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
|
||||
*
|
||||
* @param mixed $note_expr
|
||||
* @param mixed $actor_expr
|
||||
*/
|
||||
public function onCollectionQueryCreateExpression(ExpressionBuilder $eb, string $term, ?string $locale, ?Actor $actor, &$note_expr, &$actor_expr): EventResult
|
||||
{
|
||||
|
@ -43,6 +43,8 @@ class LeftPanel extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $route_params
|
||||
*
|
||||
* @throws \App\Util\Exception\DuplicateFoundException
|
||||
* @throws \App\Util\Exception\ServerException
|
||||
* @throws ClientException
|
||||
|
@ -84,6 +84,8 @@ class NoteToLink extends Entity
|
||||
* Create an instance of NoteToLink or fill in the
|
||||
* properties of $obj with the associative array $args. Doesn't
|
||||
* 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
|
||||
{
|
||||
|
@ -54,6 +54,8 @@ class Link extends Component
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
@ -150,7 +152,12 @@ class Link extends Component
|
||||
public const URL_SCHEME_NO_DOMAIN = 4;
|
||||
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
|
||||
$schemes = [
|
||||
@ -197,6 +204,7 @@ class Link extends Component
|
||||
* Intermediate callback for `replaceURLs()`, which helps resolve some
|
||||
* ambiguous link forms before passing on to the final callback.
|
||||
*
|
||||
* @param string[] $matches
|
||||
* @param callable(string $text): string $callback: return replacement text
|
||||
*/
|
||||
private function callbackHelper(array $matches, callable $callback): string
|
||||
|
@ -44,6 +44,8 @@ class Feed extends Controller
|
||||
{
|
||||
/**
|
||||
* Everything with attention to current user
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function notifications(Request $request): array
|
||||
{
|
||||
|
@ -117,7 +117,7 @@ class Notification extends Entity
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
@ -129,11 +129,17 @@ class Notification extends Entity
|
||||
return $targets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getNotificationTargetsByActivity(int|Activity $activity_id): array
|
||||
{
|
||||
return DB::findBy(Actor::class, ['id' => $this->getNotificationTargetIdsByActivity($activity_id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public static function getAllActivitiesTargetedAtActor(Actor $actor): array
|
||||
{
|
||||
return DB::dql(<<<'EOF'
|
||||
|
@ -71,10 +71,10 @@ class Notification extends Component
|
||||
* Example of $targets:
|
||||
* [42, $actor_alice, $actor_bob] // Avoid repeating actors or ids
|
||||
*
|
||||
* @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 array $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 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 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
|
||||
*/
|
||||
public function onNewNotification(Actor $sender, Activity $activity, array $targets, ?string $reason = null): EventResult
|
||||
{
|
||||
@ -103,12 +103,19 @@ class Notification extends Component
|
||||
return Event::next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $retry_args
|
||||
*/
|
||||
public function onQueueNotificationLocal(Actor $sender, Activity $activity, Actor $target, ?string $reason, array &$retry_args): EventResult
|
||||
{
|
||||
// TODO: use https://symfony.com/doc/current/notifier.html
|
||||
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
|
||||
{
|
||||
if (FreeNetwork::notify($sender, $activity, $targets, $reason)) {
|
||||
@ -122,7 +129,9 @@ class Notification extends Component
|
||||
* Bring given Activity to Targets' knowledge.
|
||||
* 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
|
||||
{
|
||||
@ -134,7 +143,7 @@ class Notification extends Component
|
||||
continue;
|
||||
}
|
||||
if (Event::handle('NewNotificationShould', [$activity, $target]) === Event::next) {
|
||||
if ($sender->getId() === $target->getId()
|
||||
if ($sender->getId() === $target->getId()
|
||||
|| $activity->getActorId() === $target->getId()) {
|
||||
// The target already knows about this, no need to bother with a notification
|
||||
continue;
|
||||
|
@ -34,11 +34,16 @@ use App\Util\HTML\Heading;
|
||||
use Component\Collection\Util\Controller\FeedController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @extends FeedController<\App\Entity\Note>
|
||||
*/
|
||||
class PersonFeed extends FeedController
|
||||
{
|
||||
/**
|
||||
* @throws ClientException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function personViewId(Request $request, int $id): array
|
||||
{
|
||||
@ -62,6 +67,8 @@ class PersonFeed extends FeedController
|
||||
*
|
||||
* @throws ClientException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function personViewNickname(Request $request, string $nickname): array
|
||||
{
|
||||
@ -73,6 +80,9 @@ class PersonFeed extends FeedController
|
||||
return $this->personView($request, $person);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function personView(Request $request, Actor $person): array
|
||||
{
|
||||
return [
|
||||
|
@ -88,6 +88,8 @@ class PersonSettings extends Controller
|
||||
* @throws NoLoggedInUser
|
||||
* @throws RedirectException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType
|
||||
*/
|
||||
public function allSettings(Request $request, LanguageController $language): array
|
||||
{
|
||||
@ -205,6 +207,8 @@ class PersonSettings extends Controller
|
||||
* @throws \Doctrine\DBAL\Exception
|
||||
* @throws NoLoggedInUser
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return ControllerResultType[]
|
||||
*/
|
||||
private static function notifications(Request $request): array
|
||||
{
|
||||
@ -251,7 +255,7 @@ class PersonSettings extends Controller
|
||||
// @codeCoverageIgnoreStart
|
||||
Log::critical("Structure of table user_notification_prefs changed in a way not accounted to in notification settings ({$name}): " . $type_str);
|
||||
throw new ServerException(_m('Internal server error'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,11 +44,13 @@ use App\Util\Exception\ServerException;
|
||||
use App\Util\Formatting;
|
||||
use App\Util\HTML;
|
||||
use Component\Attachment\Entity\ActorToAttachment;
|
||||
use Component\Attachment\Entity\Attachment;
|
||||
use Component\Attachment\Entity\AttachmentToNote;
|
||||
use Component\Conversation\Conversation;
|
||||
use Component\Language\Entity\Language;
|
||||
use Component\Notification\Entity\Attention;
|
||||
use EventResult;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
@ -66,6 +68,8 @@ class Posting extends Component
|
||||
* HTML render event handler responsible for adding and handling
|
||||
* the result of adding the note submission form, only if a user is logged in
|
||||
*
|
||||
* @param array{post_form?: FormInterface} $res
|
||||
*
|
||||
* @throws BugFoundException
|
||||
* @throws ClientException
|
||||
* @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 DuplicateFoundException
|
||||
* @throws ServerException
|
||||
*
|
||||
* @return array{\App\Entity\Activity, \App\Entity\Note, array<int, \App\Entity\Actor>}
|
||||
*/
|
||||
public static function storeLocalArticle(
|
||||
Actor $actor,
|
||||
@ -144,25 +164,25 @@ class Posting extends Component
|
||||
* $actor_id, possibly as a reply to note $reply_to and with flag
|
||||
* $is_local. Sanitizes $content and $attachments
|
||||
*
|
||||
* @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 array $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 array $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 $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
|
||||
* @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 targte
|
||||
* @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 DuplicateFoundException
|
||||
* @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(
|
||||
Actor $actor,
|
||||