diff --git a/components/Group/Controller/Group.php b/components/Group/Controller/Group.php index 71e17ed97b..cb5b3802a0 100644 --- a/components/Group/Controller/Group.php +++ b/components/Group/Controller/Group.php @@ -39,6 +39,7 @@ use Component\Collection\Util\ActorControllerTrait; use Component\Collection\Util\Controller\FeedController; use Component\Group\Entity\GroupMember; use Component\Group\Entity\LocalGroup; +use Component\Subscription\Entity\Subscription; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpFoundation\Request; @@ -91,7 +92,7 @@ class Group extends FeedController 'group_id' => $group->getId(), 'nickname' => $nickname, ])); - DB::persist(E\Subscription::create([ + DB::persist(Subscription::create([ 'subscriber' => $group->getId(), 'subscribed' => $group->getId(), ])); @@ -115,7 +116,7 @@ class Group extends FeedController } else { if (!\is_null($actor) && \is_null(Cache::get( - E\Subscription::cacheKeys($actor, $group)['subscribed'], + Subscription::cacheKeys($actor, $group)['subscribed'], fn () => DB::findOneBy('subscription', [ 'subscriber' => $actor->getId(), 'subscribed' => $group->getId(), @@ -125,14 +126,14 @@ class Group extends FeedController $subscribe_form = Form::create([['subscribe', SubmitType::class, ['label' => _m('Subscribe to this group')]]]); $subscribe_form->handleRequest($request); if ($subscribe_form->isSubmitted() && $subscribe_form->isValid()) { - DB::persist(E\Subscription::create([ + DB::persist(Subscription::create([ 'subscriber' => $actor->getId(), 'subscribed' => $group->getId(), ])); DB::flush(); Cache::delete(E\Actor::cacheKeys($group->getId())['subscriber']); Cache::delete(E\Actor::cacheKeys($actor->getId())['subscribed']); - Cache::delete(E\Subscription::cacheKeys($actor, $group)['subscribed']); + Cache::delete(Subscription::cacheKeys($actor, $group)['subscribed']); } } } diff --git a/src/Controller/Subscribers.php b/components/Subscription/Controller/Subscribers.php similarity index 67% rename from src/Controller/Subscribers.php rename to components/Subscription/Controller/Subscribers.php index fe97589f10..2fda4ec90a 100644 --- a/src/Controller/Subscribers.php +++ b/components/Subscription/Controller/Subscribers.php @@ -21,23 +21,25 @@ declare(strict_types = 1); // }}} -namespace App\Controller; +namespace Component\Subscription\Controller; -use App\Core\Controller\ActorController; +use function App\Core\I18n\_m; +use Component\Collection\Util\ActorControllerTrait; +use Component\Collection\Util\Controller\CircleController; use Symfony\Component\HttpFoundation\Request; /** * Collection of an actor's subscribers */ -class Subscribers extends ActorController +class Subscribers extends CircleController { + use ActorControllerTrait; public function subscribersByActorId(Request $request, int $id) { return $this->handleActorById( $id, fn ($actor) => [ - '_template' => 'subscribers/view.html.twig', - 'actor' => $actor, + 'actor' => $actor, ], ); } @@ -47,8 +49,12 @@ class Subscribers extends ActorController return $this->handleActorByNickname( $nickname, fn ($actor) => [ - '_template' => 'subscribers/view.html.twig', - 'actor' => $actor, + '_template' => 'collection/actors.html.twig', + 'title' => _m('Subscribers'), + 'empty_message' => _m('No subscribers'), + 'sort_options' => [], + 'page' => $this->int('page') ?? 1, + 'actors' => $actor->getSubscribers(), ], ); } diff --git a/src/Controller/Subscriptions.php b/components/Subscription/Controller/Subscriptions.php similarity index 67% rename from src/Controller/Subscriptions.php rename to components/Subscription/Controller/Subscriptions.php index ed9f1cc93a..4764c83bec 100644 --- a/src/Controller/Subscriptions.php +++ b/components/Subscription/Controller/Subscriptions.php @@ -21,23 +21,25 @@ declare(strict_types = 1); // }}} -namespace App\Controller; +namespace Component\Subscription\Controller; -use App\Core\Controller\ActorController; +use function App\Core\I18n\_m; +use Component\Collection\Util\ActorControllerTrait; +use Component\Collection\Util\Controller\CircleController; use Symfony\Component\HttpFoundation\Request; /** * Collection of an actor's subscriptions */ -class Subscriptions extends ActorController +class Subscriptions extends CircleController { + use ActorControllerTrait; public function subscriptionsByActorId(Request $request, int $id) { return $this->handleActorById( $id, fn ($actor) => [ - '_template' => 'subscriptions/view.html.twig', - 'actor' => $actor, + 'actor' => $actor, ], ); } @@ -47,8 +49,12 @@ class Subscriptions extends ActorController return $this->handleActorByNickname( $nickname, fn ($actor) => [ - '_template' => 'subscriptions/view.html.twig', - 'actor' => $actor, + '_template' => 'collection/actors.html.twig', + 'title' => _m('Subscribers'), + 'empty_message' => _m('No subscribers'), + 'sort_options' => [], + 'page' => $this->int('page') ?? 1, + 'actors' => $actor->getSubscribers(), ], ); } diff --git a/src/DataFixtures/CoreFixtures.php b/src/DataFixtures/CoreFixtures.php index 928e77ade1..0b19fa0164 100644 --- a/src/DataFixtures/CoreFixtures.php +++ b/src/DataFixtures/CoreFixtures.php @@ -9,10 +9,10 @@ use App\Core\VisibilityScope; use App\Entity\Actor; use App\Entity\LocalUser; use App\Entity\Note; -use App\Entity\Subscription; use Component\Group\Entity\GroupInbox; use Component\Group\Entity\GroupMember; use Component\Group\Entity\LocalGroup; +use Component\Subscription\Entity\Subscription; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; diff --git a/src/Entity/Actor.php b/src/Entity/Actor.php index 8aa6f0550f..58a31ebe35 100644 --- a/src/Entity/Actor.php +++ b/src/Entity/Actor.php @@ -37,6 +37,7 @@ use App\Util\Nickname; use Component\Avatar\Avatar; use Component\Language\Entity\ActorLanguage; use Component\Language\Entity\Language; +use Component\Subscription\Entity\Subscription; use DateTimeInterface; use Functional as F; @@ -242,26 +243,26 @@ class Actor extends Entity // @codeCoverageIgnoreEnd // }}} Autocode - public const PERSON = 1; - public const GROUP = 2; + public const PERSON = 1; + public const GROUP = 2; public const ORGANIZATION = 3; - public const BUSINESS = 4; - public const BOT = 5; + public const BUSINESS = 4; + public const BOT = 5; public static function cacheKeys(int|self $actor_id, mixed $other = null): array { $actor_id = \is_int($actor_id) ? $actor_id : $actor_id->getId(); return [ - 'id' => "actor-id-{$actor_id}", - 'nickname' => "actor-nickname-id-{$actor_id}", - 'fullname' => "actor-fullname-id-{$actor_id}", - 'tags' => \is_null($other) ? "actor-tags-{$actor_id}" : "actor-tags-{$actor_id}-by-{$other}", // $other is $context_id - 'circles' => "actor-circles-{$actor_id}", - 'subscriber' => "subscriber-{$actor_id}", - 'subscribed' => "subscribed-{$actor_id}", + 'id' => "actor-id-{$actor_id}", + 'nickname' => "actor-nickname-id-{$actor_id}", + 'fullname' => "actor-fullname-id-{$actor_id}", + 'tags' => \is_null($other) ? "actor-tags-{$actor_id}" : "actor-tags-{$actor_id}-by-{$other}", // $other is $context_id + 'circles' => "actor-circles-{$actor_id}", + 'subscriber' => "subscriber-{$actor_id}", + 'subscribed' => "subscribed-{$actor_id}", 'relative-nickname' => "actor-{$actor_id}-relative-nickname-{$other}", // $other is $nickname - 'can-admin' => "actor-{$actor_id}-can-admin-{$other}", // $other is an actor id + 'can-admin' => "actor-{$actor_id}-can-admin-{$other}", // $other is an actor id ]; } @@ -286,17 +287,17 @@ class Actor extends Entity public static function getById(int $id): ?self { - return Cache::get(self::cacheKeys($id)['id'], fn () => DB::find('actor', ['id' => $id])); + return Cache::get(self::cacheKeys($id)['id'], fn() => DB::find('actor', ['id' => $id])); } public static function getNicknameById(int $id): string { - return Cache::get(self::cacheKeys($id)['nickname'], fn () => self::getById($id)->getNickname()); + return Cache::get(self::cacheKeys($id)['nickname'], fn() => self::getById($id)->getNickname()); } public static function getFullnameById(int $id): ?string { - return Cache::get(self::cacheKeys($id)['fullname'], fn () => self::getById($id)->getFullname()); + return Cache::get(self::cacheKeys($id)['fullname'], fn() => self::getById($id)->getFullname()); } /** @@ -324,8 +325,8 @@ class Actor extends Entity * - If null = All tags attributed to self by other actors (excludes self tags) * - If self = Same as getSelfTags * - otherwise = Tags that $context attributed to $this - * @param null|int $offset Offset from latest - * @param null|int $limit Max number to get + * @param null|int $offset Offset from latest + * @param null|int $limit Max number to get * * @return ActorTag[] resulting lists */ @@ -334,7 +335,7 @@ class Actor extends Entity if (\is_null($context)) { return Cache::getList( self::cacheKeys($this->getId())['tags'], - fn () => DB::dql( + fn() => DB::dql( <<< 'EOQ' SELECT tag FROM actor_tag tag @@ -349,7 +350,7 @@ class Actor extends Entity $context_id = \is_int($context) ? $context : $context->getId(); return Cache::getList( self::cacheKeys($this->getId(), $context_id)['tags'], - fn () => DB::dql( + fn() => DB::dql( <<< 'EOQ' SELECT tag FROM actor_tag tag @@ -367,7 +368,7 @@ class Actor extends Entity { return Cache::getList( self::cacheKeys($this->getId())['circles'], - fn () => DB::findBy('actor_circle', ['tagger' => $this->getId()]), + fn() => DB::findBy('actor_circle', ['tagger' => $this->getId()]), ); } @@ -375,10 +376,7 @@ class Actor extends Entity { return Cache::get( self::cacheKeys($this->getId())[$which], - fn () => DB::dql( - "select count(s) from subscription s where s.{$column} = :{$column}", // Not injecting the parameter value - [$column => $this->getId()], - )[0][1] - ($this->getIsLocal() ? 1 : 0), // Remove self subscription if local + fn() => DB::count(Subscription::class, [$column => $this->getId()]) - ($this->getIsLocal() ? 1 : 0) ); } @@ -387,11 +385,31 @@ class Actor extends Entity return $this->getSubCount(which: 'subscriber', column: 'subscribed_id'); } - public function getSubscribedCount() + public function getSubscribedCount(): int { return $this->getSubCount(which: 'subscribed', column: 'subscriber_id'); } + public function getSubscriptions(): array + { + return DB::dql(<< $this->getId()]); + } + + public function getSubscribers(): array + { + return DB::dql(<< $this->getId()]); + } + /** * Resolve an ambiguous nickname reference, checking in following order: * - Actors that $sender subscribes to diff --git a/src/Routes/Subscribers.php b/src/Routes/Subscribers.php index 1db8f7e9f6..dc1c718137 100644 --- a/src/Routes/Subscribers.php +++ b/src/Routes/Subscribers.php @@ -34,9 +34,9 @@ declare(strict_types = 1); namespace App\Routes; -use App\Controller as C; use App\Core\Router\RouteLoader; use App\Util\Nickname; +use Component\Subscription\Controller as C; abstract class Subscribers { diff --git a/src/Routes/Subscriptions.php b/src/Routes/Subscriptions.php index f91243283b..030489f1c8 100644 --- a/src/Routes/Subscriptions.php +++ b/src/Routes/Subscriptions.php @@ -34,9 +34,9 @@ declare(strict_types = 1); namespace App\Routes; -use App\Controller as C; use App\Core\Router\RouteLoader; use App\Util\Nickname; +use Component\Subscription\Controller as C; abstract class Subscriptions {