[TOOLS] Fix errors pointed out by PHPStan level 4

This commit is contained in:
Hugo Sales 2022-10-19 22:38:49 +01:00
parent 4d7742e0e1
commit edeee49af9
No known key found for this signature in database
GPG Key ID: 7D0C7EAFC9D835A0
37 changed files with 168 additions and 198 deletions

View File

@ -102,8 +102,6 @@ class Conversation extends Component
* 'id' (HTML markup id used to redirect user to this anchor upon performing the action)
*
* @throws \App\Util\Exception\ServerException
*
* @return bool EventHook
*/
public function onAddNoteActions(Request $request, Note $note, array &$actions): EventResult
{
@ -142,8 +140,6 @@ class Conversation extends Component
*
* @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'])
*
* @return bool EventHook
*/
public function onAppendCardNote(array $vars, array &$result): EventResult
{
@ -195,8 +191,6 @@ class Conversation extends Component
*
* @param \App\Entity\Actor $actor The Actor currently attempting to post a Note
* @param null|\App\Entity\Actor $context_actor The 'owner' of the current route (e.g. Group or Actor), used to target it
*
* @return bool EventHook
*/
public function onPostingGetContextActor(Request $request, Actor $actor, ?Actor &$context_actor): EventResult
{
@ -216,8 +210,6 @@ class Conversation extends Component
*
* @throws \App\Util\Exception\ClientException
* @throws \App\Util\Exception\NoSuchNoteException
*
* @return bool EventHook
*/
public function onPostingModifyData(Request $request, Actor $actor, array &$data): EventResult
{
@ -245,8 +237,6 @@ class Conversation extends Component
*
* @param \App\Entity\Note $note Note being deleted
* @param \App\Entity\Actor $actor Actor that performed the delete action
*
* @return bool EventHook
*/
public function onNoteDeleteRelated(Note &$note, Actor $actor): EventResult
{
@ -264,8 +254,6 @@ class Conversation extends Component
* @param array $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
*
* @return bool EventHook
*/
public function onAddExtraNoteActions(Request $request, Note $note, array &$actions): EventResult
{
@ -300,8 +288,6 @@ class Conversation extends Component
* Prevents new Notifications to appear for muted conversations
*
* @param Activity $activity Notification Activity
*
* @return bool EventHook
*/
public function onNewNotificationShould(Activity $activity, Actor $actor): EventResult
{

View File

@ -119,7 +119,6 @@ class EditFeeds extends Controller
/** @var SubmitButton $remove_button */
$remove_button = $form->get($remove_id);
if ($remove_button->isClicked()) {
// @phpstan-ignore-next-line -- Doesn't quite understand that _this_ $opts for the current $form_definitions does have 'data'
DB::remove(DB::getReference('feed', ['actor_id' => $user->getId(), 'url' => $opts['data']]));
DB::flush();
Cache::delete($key);

View File

@ -39,12 +39,12 @@ class Link extends Component
/**
* Note that this persists both a Link and a NoteToLink
*
* @return [Entity\Link, NoteToLink]
* @return array{ link: ?Entity\Link, note_to_link: ?NoteToLink }
*/
public static function maybeCreateLink(string $url, int $note_id): array
{
try {
$link = Entity\Link::getOrCreate($url);
$link = Entity\Link::getOrCreate($url);
DB::persist($note_link = NoteToLink::create(['link_id' => $link->getId(), 'note_id' => $note_id]));
return ['link' => $link, 'note_to_link' => $note_link];
} catch (InvalidArgumentException) {
@ -66,7 +66,7 @@ class Link extends Component
if (\in_array($match, $ignore)) {
continue;
}
self::maybeCreateLink($match, $note_id);
self::maybeCreateLink($match, $note->getId());
}
}
return Event::next;

View File

@ -33,6 +33,7 @@ use App\Core\Router;
use App\Core\VisibilityScope;
use App\Entity\Activity;
use App\Entity\Actor;
use App\Entity\LocalUser;
use App\Entity\Note;
use App\Util\Common;
use App\Util\Exception\BugFoundException;
@ -180,7 +181,9 @@ class Posting extends Component
): array {
$scope ??= VisibilityScope::EVERYWHERE; // TODO: If site is private, default to LOCAL
$reply_to_id = \is_null($reply_to) ? null : (\is_int($reply_to) ? $reply_to : $reply_to->getId());
$mentions = [];
/** @var array<int, array{ mentioned?: array<int, Actor|LocalUser> }> $mentions */
$mentions = [];
if (\is_null($rendered) && !empty($content)) {
Event::handle('RenderNoteContent', [$content, $content_type, &$rendered, $actor, $locale, &$mentions]);
}

View File

@ -146,8 +146,6 @@ class Search extends Component
* Output our dedicated stylesheet
*
* @param array $styles stylesheets path
*
* @return bool hook value; true means continue processing, false means stop
*/
public function onEndShowStyles(array &$styles, string $route): EventResult
{

View File

@ -98,7 +98,7 @@ class Subscription extends Component
$activity = null;
if (\is_null($subscription)) {
DB::persist($subscription = Entity\ActorSubscription::create($opts));
$activity = Activity::create([
$activity = Activity::create([
'actor_id' => $subscriber_id,
'verb' => 'subscribe',
'object_type' => Actor::schemaName(),
@ -184,8 +184,6 @@ class Subscription extends Component
* @throws DuplicateFoundException
* @throws NotFoundException
* @throws ServerException
*
* @return bool EventHook
*/
public function onAddProfileActions(Request $request, Actor $object, array &$actions): EventResult
{

View File

@ -68,12 +68,12 @@ class Tag extends Component
return Event::next;
}
public static function maybeCreateTag(string $tag, int $note_id, ?int $lang_id): ?NoteTag
public static function maybeCreateTag(string $tag, int $note_id, ?int $lang_id, array $extra_args = []): ?NoteTag
{
if (!self::validate($tag)) {
return null; // Ignore invalid tag candidates
}
$canonical_tag = self::canonicalTag($tag, \is_null($lang_id) ? null : Language::getById($lang_id)->getLocale());
$canonical_tag = self::canonicalTag($tag, \is_null($lang_id) ? null : Language::getById($lang_id)->getLocale());
DB::persist($note_tag = NoteTag::create([
'tag' => $tag,
'canonical' => $canonical_tag,

View File

@ -52,8 +52,6 @@ class AttachmentShowRelated extends Plugin
* Output our dedicated stylesheet
*
* @param array $styles stylesheets path
*
* @return bool hook value; true means continue processing, false means stop
*/
public function onEndShowStyles(array &$styles, string $path): EventResult
{

View File

@ -30,7 +30,7 @@ use Plugin\Bundles\Entity\BundleCollection;
class BundleCollections 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
{
if (\is_null($owner_nickname)) {
return Router::url(

View File

@ -45,8 +45,6 @@ class Cover extends Plugin
{
/**
* Map URLs to actions
*
* @return bool hook value; true means continue processing, false means stop
*/
public function onAddRoute(Router $r): EventResult
{
@ -90,8 +88,6 @@ class Cover extends Plugin
* Output our dedicated stylesheet
*
* @param array $styles stylesheets path
*
* @return bool hook value; true means continue processing, false means stop
*/
public function onStartShowStyles(array &$styles): EventResult
{

View File

@ -133,8 +133,6 @@ class DeleteNote extends NoteHandlerPlugin
/**
* Adds and connects the _delete_note_action_ route to
* Controller\DeleteNote::class
*
* @return bool Event hook
*/
public function onAddRoute(Router $r): EventResult
{
@ -152,8 +150,6 @@ class DeleteNote extends NoteHandlerPlugin
* @throws \App\Util\Exception\DuplicateFoundException
* @throws \App\Util\Exception\NotFoundException
* @throws \App\Util\Exception\ServerException
*
* @return bool Event hook
*/
public function onAddExtraNoteActions(Request $request, Note $note, array &$actions): EventResult
{
@ -193,10 +189,8 @@ class DeleteNote extends NoteHandlerPlugin
* @param \ActivityPhp\Type\AbstractObject $type_activity Activity Streams 2.0 Activity
* @param mixed $type_object Activity's Object
* @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
private function activitypub_handler(Actor $actor, AbstractObject $type_activity, mixed $type_object, ?ActivitypubActivity &$ap_act): bool
private function activitypub_handler(Actor $actor, AbstractObject $type_activity, mixed $type_object, ?ActivitypubActivity &$ap_act): EventResult
{
if ($type_activity->get('type') !== 'Delete'
|| !($type_object instanceof Note)) {
@ -225,8 +219,6 @@ class DeleteNote extends NoteHandlerPlugin
* @param \ActivityPhp\Type\AbstractObject $type_activity Activity Streams 2.0 Activity
* @param \ActivityPhp\Type\AbstractObject $type_object Activity Streams 2.0 Object
* @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onNewActivityPubActivity(Actor $actor, AbstractObject $type_activity, AbstractObject $type_object, ?ActivitypubActivity &$ap_act): EventResult
{
@ -240,8 +232,6 @@ class DeleteNote extends NoteHandlerPlugin
* @param \ActivityPhp\Type\AbstractObject $type_activity Activity Streams 2.0 Activity
* @param mixed $type_object Object
* @param null|\Plugin\ActivityPub\Entity\ActivitypubActivity $ap_act Resulting ActivitypubActivity
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onNewActivityPubActivityWithObject(Actor $actor, AbstractObject $type_activity, mixed $type_object, ?ActivitypubActivity &$ap_act): EventResult
{
@ -253,8 +243,6 @@ class DeleteNote extends NoteHandlerPlugin
*
* @param string $verb GNU social's internal verb
* @param null|string $gs_verb_to_activity_stream_two_verb Resulting Activity Streams 2.0 verb
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onGSVerbToActivityStreamsTwoActivityType(string $verb, ?string &$gs_verb_to_activity_stream_two_verb): EventResult
{

View File

@ -38,8 +38,6 @@ class Directory extends Plugin
{
/**
* Map Directory routes to its corresponding Controllers
*
* @return bool
*/
public function onAddRoute(Router $r): EventResult
{
@ -53,8 +51,6 @@ class Directory extends Plugin
* Add Links to main navigation card
*
* @param array $res out menu items
*
* @return bool hook value; true means continue processing, false means stop
*/
public function onAddMainNavigationItem(array $vars, array &$res): EventResult
{
@ -70,8 +66,6 @@ class Directory extends Plugin
*
* @throws RedirectException
* @throws ServerException
*
* @return bool EventHook
*/
public function onPrependActorsCollection(Request $request, array &$elements): EventResult
{

View File

@ -387,8 +387,6 @@ class Embed extends Plugin
* @param array $versions inherited from parent
*
* @throws ServerException
*
* @return bool true hook value
*/
public function onPluginVersion(array &$versions): EventResult
{

View File

@ -123,8 +123,6 @@ class Favourite extends NoteHandlerPlugin
*
* @param Note $note Current Note being rendered
* @param array $actions Array containing all Note actions to be rendered
*
* @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers
*/
public function onAddNoteActions(Request $request, Note $note, array &$actions): EventResult
{
@ -169,8 +167,6 @@ class Favourite extends NoteHandlerPlugin
*
* @param array $vars Array containing necessary info to process event. In this case, contains the current Note being rendered
* @param array $result Contains a hashmap for each Activity performed on Note (object)
*
* @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers
*/
public function onAppendCardNote(array $vars, array &$result): EventResult
{
@ -271,10 +267,8 @@ class Favourite extends NoteHandlerPlugin
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
private function activitypub_handler(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool
private function activitypub_handler(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): EventResult
{
if (!\in_array($type_activity->get('type'), ['Like', 'Undo'])) {
return Event::next;
@ -364,8 +358,6 @@ class Favourite extends NoteHandlerPlugin
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onNewActivityPubActivity(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, \ActivityPhp\Type\AbstractObject $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): EventResult
{
@ -388,8 +380,6 @@ class Favourite extends NoteHandlerPlugin
* @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
* @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onNewActivityPubActivityWithObject(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): EventResult
{
@ -401,8 +391,6 @@ class Favourite extends NoteHandlerPlugin
*
* @param string $verb GNU social's internal verb
* @param null|string $gs_verb_to_activity_stream_two_verb Resulting Activity Streams 2.0 verb
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onGSVerbToActivityStreamsTwoActivityType(string $verb, ?string &$gs_verb_to_activity_stream_two_verb): EventResult
{

View File

@ -37,6 +37,7 @@ use EventResult;
* Check attachment file size quotas
*
* @package GNUsocial
*
* @ccategory Attachment
*
* @author Hugo Sales <hugo@hsal.es>
@ -102,8 +103,6 @@ class FileQuota extends Plugin
* Adds this plugin's version information to $versions array
*
* @param array $versions inherited from parent
*
* @return bool true hook value
*/
public function onPluginVersion(array &$versions): EventResult
{

View File

@ -258,8 +258,6 @@ class ImageEncoder extends Plugin
* Adds this plugin's version information to $versions array
*
* @param array $versions inherited from parent
*
* @return bool true hook value
*/
public function onPluginVersion(array &$versions): EventResult
{

View File

@ -111,20 +111,20 @@ class NoteTypeFeedFilter extends Plugin
$is_negate = $type[0] === '!';
$type = Formatting::removePrefix($type, '!');
switch ($type) {
case 'text':
$ret = !\is_null($note->getContent());
break;
case 'media':
$ret = !empty($note->getAttachments());
break;
case 'link':
$ret = !empty($note->getLinks());
break;
case 'tag':
$ret = !empty($note->getTags());
break;
default:
throw new BugFoundException("Unkown note type requested {$type}", previous: $this->unknownType($type));
case 'text':
$ret = !\is_null($note->getContent());
break;
case 'media':
$ret = !empty($note->getAttachments());
break;
case 'link':
$ret = !empty($note->getLinks());
break;
case 'tag':
$ret = !empty($note->getTags());
break;
default:
throw new BugFoundException("Unkown note type requested {$type}", previous: $this->unknownType($type));
}
if ($is_negate && $ret) {
return false;
@ -182,8 +182,6 @@ class NoteTypeFeedFilter extends Plugin
* Output our dedicated stylesheet
*
* @param array $styles stylesheets path
*
* @return bool hook value; true means continue processing, false means stop
*/
public function onEndShowStyles(array &$styles, string $route): EventResult
{

View File

@ -14,6 +14,7 @@ use App\Entity\LocalUser;
use App\Entity\Note;
use App\Util\Exception\BugFoundException;
use App\Util\Exception\ClientException;
use App\Util\Exception\InvalidRequestException;
use App\Util\Exception\ServerException;
use App\Util\Formatting;
use Component\Conversation\Conversation;
@ -68,11 +69,13 @@ class APIv1 extends Controller
// $encoder = new XmlEncoder();
// $xml = $encoder->encode($result, 'xml');
[$tag_names, $keys] = F\zip(...F\map(array_keys($result), fn (string $k) => explode('_', $k)));
$xml = new SimpleXMLElement('<' . $tag_names[0] . '/>');
dd($tag_names, $keys, $result, $xml, (string) $xml);
$xml->addChild();
dd($xml);
return new Response(content: $xml, status: $statis);
$xml = new SimpleXMLElement('<' . $tag_names[0] . '/>');
// dd($tag_names, $keys, $result, $xml, (string) $xml);
// $xml->addChild();
// dd($xml);
return new Response(content: $xml, status: $status);
} else {
throw new InvalidRequestException;
}
}
@ -308,7 +311,7 @@ class APIv1 extends Controller
} elseif (!\is_null($day)) {
$day = new DateTimeImmutable($day);
$pins = DB::findBy(Pin::class, ['actor_id' => $user->getId(), 'gte' => ['modified' => $day], 'lt' => ['modified' => $day->modify('+1 day')]]);
} elseif (!\is_null($url)) {
} elseif (!\is_null($url)) { // @phpstan-ignore-line this is here for clarity
$pins = DB::findBy(Pin::class, ['actor_id' => $user->getId(), 'url_hash' => hash('sha256', $url)]);
} else {
throw new BugFoundException('Wonky logic in pinboard/posts/get');

View File

@ -53,19 +53,21 @@ class Settings extends Controller
$enable_button = $form->get('enable');
/** @var SubmitButton $regenerate_button */
$regenerate_button = $form->get('regenerate');
/** @var Token $token */
$token = $params['token'];
if ($enable_button->isClicked()) {
if ($params['was_enabled']) {
if (\is_null($params['token'])) {
throw new BugFoundException('Pinboard API can not be enabled if no token is present');
} else {
$token = DB::refetch($parms['token']);
DB::refresh($token);
$token->setEnabled(false);
}
} else {
if (\is_null($params['token'])) {
DB::persist($token = Token::create(['actor_id' => $user->getId(), 'token' => Token::generateTokenString(), 'enabled' => true]));
} else {
$token = DB::refetch($parms['token']);
DB::refresh($params['token']);
$token->setEnabled(true);
}
}
@ -73,7 +75,7 @@ class Settings extends Controller
if (\is_null($params['token'])) {
throw new ClientException(_m('Can not regenerate token when no token exists. Enable Pinboard first'));
} else {
$token = DB::refetch($params['token']);
DB::refresh($params['token']);
$token->setToken(Token::generateTokenString());
}
} else {

View File

@ -107,6 +107,8 @@ class Token extends Entity
options: ['limit' => 1],
),
);
} else {
return null;
}
}

View File

@ -49,8 +49,6 @@ class ProfileColor extends Plugin
{
/**
* Map URLs to actions
*
* @return bool hook value; true means continue processing, false means stop
*/
public function onAddRoute(Router $r): EventResult
{

View File

@ -81,7 +81,7 @@ class RepeatNote extends NoteHandlerPlugin
$original_note_id = $note->getId();
// Create a new note with the same content as the original
[, $repeat, ] = Posting::storeLocalNote(
[, $repeat] = Posting::storeLocalNote(
actor: $actor = Actor::getById($actor_id),
content: $note->getContent(),
content_type: $note->getContentType(),
@ -186,10 +186,10 @@ class RepeatNote extends NoteHandlerPlugin
} else {
// Either was undoed already
if (!\is_null($already_repeated_activity = DB::findOneBy(Activity::class, [
'actor_id' => $actor_id,
'verb' => 'repeat',
'actor_id' => $actor_id,
'verb' => 'repeat',
'object_type' => 'note',
'object_id' => $note_id,
'object_id' => $note_id,
], return_null: true))) {
return DB::findOneBy(Activity::class, [
'actor_id' => $actor_id,
@ -209,8 +209,6 @@ class RepeatNote extends NoteHandlerPlugin
* original Note on Actor feed
*
* @param array $notes List of Notes to be filtered
*
* @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers
*/
public function onFilterNoteList(?Actor $actor, array &$notes, Request $request): EventResult
{
@ -234,8 +232,6 @@ class RepeatNote extends NoteHandlerPlugin
/**
* HTML rendering event that adds the repeat form as a note
* action, if a user is logged in
*
* @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers
*/
public function onAddNoteActions(Request $request, Note $note, array &$actions): EventResult
{
@ -278,8 +274,6 @@ class RepeatNote extends NoteHandlerPlugin
* @param array $vars Contains the Note currently being rendered
* @param array $result Rendered String containing anchors for Actors that
* repeated the Note
*
* @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers
*/
public function onAppendCardNote(array $vars, array &$result): EventResult
{
@ -316,8 +310,6 @@ class RepeatNote extends NoteHandlerPlugin
*
* @param Note $note Note to be deleted
* @param Actor $actor Who performed the Delete action
*
* @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers
*/
public function onNoteDeleteRelated(Note &$note, Actor $actor): EventResult
{
@ -338,8 +330,6 @@ class RepeatNote extends NoteHandlerPlugin
*
* - **repeat_remove**
* same as above, except that it undoes the aforementioned action
*
* @return bool Event hook, Event::next (true) is returned to allow Event to be handled by other handlers
*/
public function onAddRoute(Router $r): EventResult
{
@ -369,10 +359,8 @@ class RepeatNote extends NoteHandlerPlugin
* @throws ClientException
* @throws DuplicateFoundException
* @throws ServerException
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
private function activitypub_handler(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): bool
private function activitypub_handler(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): EventResult
{
if (!\in_array($type_activity->get('type'), ['Announce', 'Undo']) || !$actor->isPerson()) {
return Event::next;
@ -463,8 +451,6 @@ class RepeatNote extends NoteHandlerPlugin
* @throws ClientException
* @throws DuplicateFoundException
* @throws ServerException
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onNewActivityPubActivity(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, \ActivityPhp\Type\AbstractObject $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): EventResult
{
@ -488,8 +474,6 @@ class RepeatNote extends NoteHandlerPlugin
* @throws ClientException
* @throws DuplicateFoundException
* @throws ServerException
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onNewActivityPubActivityWithObject(Actor $actor, \ActivityPhp\Type\AbstractObject $type_activity, mixed $type_object, ?\Plugin\ActivityPub\Entity\ActivitypubActivity &$ap_act): EventResult
{
@ -501,8 +485,6 @@ class RepeatNote extends NoteHandlerPlugin
*
* @param string $verb GNU social's internal verb
* @param null|string $gs_verb_to_activity_stream_two_verb Resulting Activity Streams 2.0 verb
*
* @return bool Returns `Event::stop` if handled, `Event::next` otherwise
*/
public function onGSVerbToActivityStreamsTwoActivityType(string $verb, ?string &$gs_verb_to_activity_stream_two_verb): EventResult
{

View File

@ -234,8 +234,6 @@ class StoreRemoteMedia extends Plugin
* Adds this plugin's version information to $versions array
*
* @param array $versions inherited from parent
*
* @return bool true hook value
*/
public function onPluginVersion(array &$versions): EventResult
{

View File

@ -40,6 +40,10 @@ use Plugin\WebHooks\Controller as C;
use Plugin\WebHooks\Entity as E;
use Symfony\Component\HttpFoundation\Request;
/**
* @phpstan-type AliasNotifications array{ sender: Actor, activity: Activity, effective_targets: array<Actor>, reason: ?string }
* @phpstan-type AliasSubscriptions array{ subscriber: Actor, activity: Activity, target: Actor, reason: ?string }
*/
class WebHooks extends Plugin
{
public const controller_route = 'webhook';
@ -86,33 +90,33 @@ class WebHooks extends Plugin
}
/**
* @param array<Actor $sender, Activity $activity, array $effective_targets, ?string $reason> $args
* @param AliasNotifications|AliasSubscriptions $args
*/
public function onQueueWebhook(string $type, string $hook_target, Actor $actor, array $args): EventResult
{
switch ($type) {
case 'notifications':
[$sender, $activity, $targets, $reason] = $args;
$data = [
'type' => 'notification',
'activity' => '%activity%',
'actor' => ['id' => $sender->getId(), 'nickname' => $sender->getNickname()],
'targets' => F\map(array_values($targets), fn (Actor $actor) => ['id' => $actor->getId(), 'nickname' => $actor->getNickname()]),
'reason' => $reason,
];
break;
case 'subscriptions':
[$subscriber, $activity, $target, $reason] = $args;
$data = [
'type' => 'subscription',
'activity' => '%activity%',
'actor' => ['id' => $subscriber->getId(), 'nickname' => $subscriber->getNickname()],
'targets' => [['id' => $target->getId(), 'nickname' => $target->getNickname()]],
'reason' => $reason,
];
break;
default:
throw new ServerException("Webhook notification handler for event {$type} not implemented");
case 'notifications':
['sender' => $sender, 'activity' => $activity, 'effective_targets' => $targets, 'reason' => $reason] = $args;
$data = [
'type' => 'notification',
'activity' => '%activity%',
'actor' => ['id' => $sender->getId(), 'nickname' => $sender->getNickname()],
'targets' => F\map(array_values($targets), fn (Actor $actor) => ['id' => $actor->getId(), 'nickname' => $actor->getNickname()]),
'reason' => $reason,
];
break;
case 'subscriptions':
['subscriber' => $subscriber, 'activity' => $activity, 'target' => $target, 'reason' => $reason] = $args;
$data = [
'type' => 'subscription',
'activity' => '%activity%',
'actor' => ['id' => $subscriber->getId(), 'nickname' => $subscriber->getNickname()],
'targets' => [['id' => $target->getId(), 'nickname' => $target->getNickname()]],
'reason' => $reason,
];
break;
default:
throw new ServerException("Webhook notification handler for event {$type} not implemented");
}
// toJson(Activity) is already JSON (hopefully that's obvious :') ), so replace it after converting the rest to JSON

View File

@ -50,6 +50,7 @@ use Functional as F;
/**
* @mixin EntityManager
*
* @template T of Entity
*
* Finds an Entity by its identifier. You probably want to use DB::findBy instead.
@ -77,6 +78,9 @@ use Functional as F;
*
* Executes a function in a transaction. Warning: suppresses exceptions. Returns the result of the callable.
* @method mixed wrapInTransaction(callable $func)
*
* Refetch the given entity
* @method static T refetch(T $entity)
*/
class DB
{
@ -272,17 +276,17 @@ class DB
{
$res = self::findBy($table, $criteria, $order_by, 2, $offset); // Use limit 2 to check for consistency
switch (\count($res)) {
case 0:
if ($return_null) {
return null;
} else {
throw new NotFoundException("No value in table {$table} matches the requested criteria");
}
// no break
case 1:
return $res[0];
default:
throw new DuplicateFoundException("Multiple values in table {$table} match the requested criteria");
case 0:
if ($return_null) {
return null;
} else {
throw new NotFoundException("No value in table {$table} matches the requested criteria");
}
// no break
case 1:
return $res[0];
default:
throw new DuplicateFoundException("Multiple values in table {$table} match the requested criteria");
}
}
@ -313,7 +317,8 @@ class DB
$seqName = $metadata->getSequenceName($conn->getDatabasePlatform());
self::persist($owner);
$id = (int) $conn->lastInsertId($seqName);
F\map(\is_array($others) ? $others : [$others], function ($o) use ($id) { $o->setId($id); self::persist($o); });
F\map(\is_array($others) ? $others : [$others], function ($o) use ($id) { $o->setId($id);
self::persist($o); });
if (!\is_null($extra)) {
$extra($id);
}

View File

@ -152,6 +152,8 @@ abstract class Entity
* Entity::getByPK(['key1' => 42, 'key2' => 'foo'])
*
* @throws \App\Util\Exception\DuplicateFoundException
*
* @return $this
*/
public static function getByPK(mixed $values): ?self
{

View File

@ -47,8 +47,9 @@ abstract class Event
* EventResult::stop - Stop other handlers from processing the event
* EventResult::next - Allow the other handlers to process the event
*/
public const stop = EventResult::stop;
public const next = EventResult::next;
public const stop = EventResult::stop;
public const next = EventResult::next;
public const unhandled = EventResult::unhandled;
private static EventDispatcherInterface $dispatcher;
@ -87,9 +88,9 @@ abstract class Event
$ns . $name,
function ($event, $event_name, $dispatcher) use ($handler) {
$result = $handler(...$event->getArguments());
if (\is_null($result) || !isset($result)) {
dd($handler, $event_name);
throw new BugFoundException("Events must return an \\EventResult, which a handler for {$event_name} does not");
if (!isset($result)) {
$handler_file = (new ReflectionFunction($handler))->getFileName();
throw new BugFoundException("Events must return an \\EventResult, which {$handler_file} for {$event_name} does not");
}
$event->setResult($result);
@ -115,9 +116,6 @@ abstract class Event
* @param string $name Name of the event that's happening
* @param array $args Arguments for handlers
* @param string $ns Namspace for the event
*
* @return bool flag saying whether to continue processing, based
* on results of handlers
*/
public static function handle(string $name, array $args = [], string $ns = 'GNUsocial.'): EventResult
{

View File

@ -23,7 +23,6 @@ declare(strict_types = 1);
namespace App\Core;
use App\Core\DB;
use function App\Core\I18n\_m;
use App\Util\Common;
use App\Util\Exception\DuplicateFoundException;
@ -109,7 +108,7 @@ class GSFile
// The following properly gets the mimetype with `file` or other
// available methods, so should be safe
$mimetype = mb_substr($file->getMimeType(), 0, 64);
$width = $height = null;
$width = $height = null;
$event_map[$mimetype] = [];
$major_mime = self::mimetypeMajor($mimetype);
$event_map[$major_mime] = [];
@ -120,6 +119,7 @@ class GSFile
}
// Always prefer specific encoders
$encoders = array_merge($event_map[$mimetype], $event_map[$major_mime]);
// @phpstan-ignore-next-line
foreach ($encoders as $encoder) {
if ($encoder($file, $mimetype, $width, $height)) {
break; // One successful sanitizer is enough
@ -315,7 +315,7 @@ class GSFile
$fallback = function ($title) use ($ext) {
if (!\is_null($ext)) {
return ($title) . ".{$ext}";
return $title . ".{$ext}";
}
};

View File

@ -90,7 +90,6 @@ class ModuleManager
function (string $method) use ($obj) {
if (((string) (new ReflectionMethod($obj, $method))->getReturnType()) !== 'EventResult') {
$class = $obj::class;
dd("Return type of {$class}::{$method} is not the required EventResult");
throw new BugFoundException("Return type of {$class}::{$method} is not the required EventResult");
}
$event_name = mb_substr($method, 2);
@ -183,7 +182,7 @@ class ModuleManager
} else {
$rdi = new AppendIterator();
$rdi->append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(INSTALLDIR . '/components', FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS)));
$rdi->append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(INSTALLDIR . '/plugins', FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS)));
$rdi->append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(INSTALLDIR . '/plugins', FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS)));
$time = file_exists(MODULE_CACHE_FILE) ? filemtime(MODULE_CACHE_FILE) : 0;
if ($_ENV['APP_ENV'] === 'test' || F\some($rdi, fn ($e) => $e->getMTime() > $time)) {

View File

@ -42,8 +42,6 @@ abstract class NoteHandlerPlugin extends Plugin
*
* @throws InvalidFormException
* @throws NoSuchNoteException
*
* @return bool|void
*/
public static function noteActionHandle(Request $request, Form $form, Note $note, string $form_name, callable $handle)
{

View File

@ -43,6 +43,7 @@ use Component\Language\Entity\ActorLanguage;
use Component\Language\Entity\Language;
use Component\Subscription\Entity\ActorSubscription;
use Component\Tag\Tag;
use Component\Tag\Entity\NoteTag;
use Functional as F;
/**

View File

@ -55,6 +55,10 @@ use Symfony\Component\Security\Core\User\UserInterface;
* @author Hugo Sales <hugo@hsal.es>
* @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*
*
* @method bool hasNickname()
* @method bool hasPassword()
*/
class LocalUser extends Entity implements UserInterface, PasswordAuthenticatedUserInterface
{

View File

@ -223,36 +223,36 @@ abstract class Common
*
* @return int the php.ini upload limit in machine-readable format
*/
public static function sizeStrToInt(string $size): int
public static function sizeStrToInt(string|null $size): int
{
// `memory_limit` can be -1 and `post_max_size` can be 0
// for unlimited. Consistency.
if (empty($size) || $size === '-1' || $size === '0') {
if (!isset($size) || $size === '-1' || $size === '0') {
$size = '3M';
}
$suffix = mb_substr($size, -1);
$size = (int) mb_substr($size, 0, -1);
switch (mb_strtoupper($suffix)) {
case 'P':
$size *= 1024;
// no break
case 'T':
$size *= 1024;
// no break
case 'G':
$size *= 1024;
// no break
case 'M':
$size *= 1024;
// no break
case 'K':
$size *= 1024;
break;
default:
if ($suffix >= '0' && $suffix <= '9') {
$size = (int) "{$size}{$suffix}";
}
case 'P':
$size *= 1024;
// no break
case 'T':
$size *= 1024;
// no break
case 'G':
$size *= 1024;
// no break
case 'M':
$size *= 1024;
// no break
case 'K':
$size *= 1024;
break;
default:
if ($suffix >= '0' && $suffix <= '9') {
$size = (int) "{$size}{$suffix}";
}
}
return $size;
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types = 1);
// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
// }}}
namespace App\Util\Exception;
use function App\Core\I18n\_m;
class InvalidRequestException extends ClientException
{
public function __construct()
{
parent::__construct(_m('Invalid request'));
}
}

View File

@ -121,7 +121,7 @@ class ActorForms
foreach ($cache_keys as $key) {
Cache::delete($key);
}
Event::handle('ActorFormInvalidateRelated', [$target, $local]);
Event::handle('ActorFormInvalidateRelated', [$target, $local ?? null]);
};
return Form::handle(

View File

@ -314,8 +314,7 @@ abstract class Formatting
$mentions = [];
// XXX: We remove <span> because when content is in html the tag comes as #<span>hashtag</span>
$text = str_replace('<span>', '', $text);
if (Event::handle('StartFindMentions', [$actor, $text, &$mentions])) {
if (Event::handle('StartFindMentions', [$actor, $text, &$mentions]) !== Event::stop) {
// @person mentions
$person_matches = self::findMentionsRaw($text, '@');
foreach ($person_matches as $match) {

View File

@ -39,7 +39,7 @@ class EntityTest extends GNUsocialTestCase
$user = LocalUser::create(['nickname' => 'foo']);
static::assertTrue($user->hasNickname());
static::assertFalse($user->hasPassword());
static::assertThrows(BadMethodCallException::class, fn () => $user->nonExistantMethod());
static::assertThrows(BadMethodCallException::class, fn () => $user->nonExistantMethod()); // @phpstan-ignore-line
}
public function testCreate()