. // }}} /** * Collections Controller for GNU social * * @package GNUsocial * @category Plugin * * @author Phablulo * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ namespace Component\Collection\Util\Controller; use App\Core\DB\DB; use App\Core\Form; use function App\Core\I18n\_m; use App\Entity\LocalUser; 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\HttpFoundation\Request; abstract class MetaCollectionController extends FeedController { protected string $slug = 'collectionsEntry'; protected string $plural_slug = 'collectionsList'; protected string $page_title = 'Collections'; abstract public function getCollectionUrl(int $owner_id, string $owner_nickname, int $collection_id): string; abstract public function getCollectionItems(int $owner_id, $collection_id): array; abstract public function getCollectionsByActorId(int $owner_id): array; abstract public function getCollectionBy(int $owner_id, int $collection_id); abstract public function createCollection(int $owner_id, string $name); public function collectionsViewByActorNickname(Request $request, string $nickname): array { $user = DB::findOneBy(LocalUser::class, ['nickname' => $nickname]); return self::collectionsView($request, $user->getId(), $nickname); } public function collectionsViewByActorId(Request $request, int $id): array { return self::collectionsView($request, $id, null); } /** * Generate Collections page * * @param int $id actor id * @param ?string $nickname actor nickname * * @return array twig template options */ public function collectionsView(Request $request, int $id, ?string $nickname): array { $collections = $this->getCollectionsByActorId($id); $create_title = _m('Create a ' . mb_strtolower(preg_replace('/([a-z0-9])([A-Z])/', '$1 $2', $this->slug))); $collections_title = _m('Your ' . mb_strtolower(preg_replace('/([a-z0-9])([A-Z])/', '$1 $2', $this->plural_slug))); // create collection form $create = null; if (Common::user()?->getId() === $id) { $create = Form::create([ ['name', TextType::class, [ 'label' => $create_title, 'attr' => [ 'placeholder' => _m('Name'), 'required' => 'required', ], 'data' => '', ]], ['add_collection', SubmitType::class, [ 'label' => $create_title, 'attr' => [ 'title' => $create_title, ], ]], ]); $create->handleRequest($request); if ($create->isSubmitted() && $create->isValid()) { $this->createCollection($id, $create->getData()['name']); DB::flush(); throw new RedirectException(); } } // We need to inject some functions in twig, // but I don't want to create an environment for this // as twig docs suggest in https://twig.symfony.com/doc/2.x/advanced.html#functions. // // Instead, I'm using an anonymous class to encapsulate // the functions and passing that class to the template. // This is suggested at https://stackoverflow.com/a/50364502. $fn = new class($id, $nickname, $request, $this, $this->slug) { private $id; private $nick; private $request; private $parent; private $slug; public function __construct($id, $nickname, $request, $parent, $slug) { $this->id = $id; $this->nick = $nickname; $this->request = $request; $this->parent = $parent; $this->slug = $slug; } // there's already a 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) { return $this->parent->getCollectionUrl($this->id, $this->nick, $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) { $edit = Form::create([ ['name', TextType::class, [ 'attr' => [ 'placeholder' => 'New name', 'required' => 'required', ], 'data' => '', ]], ['update_' . $collection->getId(), SubmitType::class, [ 'label' => _m('Save'), 'attr' => [ 'title' => _m('Save'), ], ]], ]); $edit->handleRequest($this->request); if ($edit->isSubmitted() && $edit->isValid()) { $collection->setName($edit->getData()['name']); DB::persist($collection); DB::flush(); throw new RedirectException(); } return $edit->createView(); } // creating the remove form public function rmForm($collection) { $rm = Form::create([ ['remove_' . $collection->getId(), SubmitType::class, [ 'label' => _m('Delete ' . $this->slug), 'attr' => [ 'title' => _m('Delete ' . $this->slug), 'class' => 'danger', ], ]], ]); $rm->handleRequest($this->request); if ($rm->isSubmitted()) { DB::remove($collection); DB::flush(); throw new RedirectException(); } return $rm->createView(); } }; return [ '_template' => 'collection/meta_collections.html.twig', 'page_title' => $this->page_title, 'list_title' => $collections_title, 'add_collection' => $create?->createView(), 'fn' => $fn, 'collections' => $collections, ]; } public function collectionsEntryViewNotesByNickname(Request $request, string $nickname, int $cid): array { $user = DB::findOneBy(LocalUser::class, ['nickname' => $nickname]); return self::collectionsEntryViewNotesByActorId($request, $user->getId(), $cid); } public function collectionsEntryViewNotesByActorId(Request $request, int $id, int $cid): array { $collection = $this->getCollectionBy($id, $cid); $vars = $this->getCollectionItems($id, $cid); return array_merge([ '_template' => 'collections/collection_entry_view.html.twig', 'page_title' => $collection->getName(), ], $vars); } }