MetaCollectionTrait.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. declare(strict_types = 1);
  3. // {{{ License
  4. // This file is part of GNU social - https://www.gnu.org/software/social
  5. //
  6. // GNU social is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU Affero General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // GNU social is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU Affero General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU Affero General Public License
  17. // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
  18. // }}}
  19. /**
  20. * Collections for GNU social
  21. *
  22. * @package GNUsocial
  23. * @category Plugin
  24. *
  25. * @author Phablulo <phablulo@gmail.com>
  26. * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
  27. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  28. */
  29. namespace Component\Collection\Util;
  30. use App\Core\DB\DB;
  31. use App\Core\Event;
  32. use App\Core\Form;
  33. use function App\Core\I18n\_m;
  34. use App\Entity\Actor;
  35. use App\Util\Common;
  36. use App\Util\Exception\RedirectException;
  37. use App\Util\Formatting;
  38. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  39. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  40. use Symfony\Component\Form\Extension\Core\Type\TextType;
  41. use Symfony\Component\HttpFoundation\Request;
  42. trait MetaCollectionTrait
  43. {
  44. //protected string $slug = 'collection';
  45. //protected string $plural_slug = 'collections';
  46. /**
  47. * create a collection owned by Actor $owner.
  48. *
  49. * @param Actor $owner The collection's owner
  50. * @param array $vars Page vars sent by AppendRightPanelBlock event
  51. * @param string $name Collection's name
  52. */
  53. abstract protected function createCollection(Actor $owner, array $vars, string $name);
  54. /**
  55. * remove item from collections.
  56. *
  57. * @param Actor $owner Current user
  58. * @param array $vars Page vars sent by AppendRightPanelBlock event
  59. * @param array $items Array of collections's ids to remove the current item from
  60. * @param array $collections List of ids of collections owned by $owner
  61. */
  62. abstract protected function removeItem(Actor $owner, array $vars, array $items, array $collections);
  63. /**
  64. * add item to collections.
  65. *
  66. * @param Actor $owner Current user
  67. * @param array $vars Page vars sent by AppendRightPanelBlock event
  68. * @param array $items Array of collections's ids to add the current item to
  69. * @param array $collections List of ids of collections owned by $owner
  70. */
  71. abstract protected function addItem(Actor $owner, array $vars, array $items, array $collections);
  72. /**
  73. * Check the route to determine whether the widget should be added
  74. */
  75. abstract protected function shouldAddToRightPanel(Actor $user, $vars, Request $request): bool;
  76. /**
  77. * Get array of collections's owned by $actor
  78. *
  79. * @param Actor $owner Collection's owner
  80. * @param ?array $vars Page vars sent by AppendRightPanelBlock event
  81. * @param bool $ids_only if true, the function must return only the primary key or each collections
  82. */
  83. abstract protected function getCollectionsBy(Actor $owner, ?array $vars = null, bool $ids_only = false): array;
  84. /**
  85. * Append Collections widget to the right panel.
  86. * It's compose of two forms: one to select collections to add
  87. * the current item to, and another to create a new collection.
  88. */
  89. public function onAppendRightPanelBlock(Request $request, $vars, &$res): bool
  90. {
  91. $user = Common::actor();
  92. if (\is_null($user)) {
  93. return Event::next;
  94. }
  95. if (!$this->shouldAddToRightPanel($user, $vars, $request)) {
  96. return Event::next;
  97. }
  98. $collections = $this->getCollectionsBy($user);
  99. // form: add to collection
  100. $choices = [];
  101. foreach ($collections as $col) {
  102. $choices[$col->getName()] = $col->getId();
  103. }
  104. $collections = array_map(fn ($x) => $x->getId(), $collections);
  105. $already_selected = $this->getCollectionsBy($user, $vars, true);
  106. $add_form = Form::create([
  107. ['collections', ChoiceType::class, [
  108. 'choices' => $choices,
  109. 'multiple' => true,
  110. 'required' => false,
  111. 'choice_attr' => function ($id) use ($already_selected) {
  112. if (\in_array($id, $already_selected)) {
  113. return ['selected' => 'selected'];
  114. }
  115. return [];
  116. },
  117. ]],
  118. ['add', SubmitType::class, [
  119. 'label' => _m('Add to ' . $this->plural_slug),
  120. 'attr' => [
  121. 'title' => _m('Add to ' . $this->plural_slug),
  122. ],
  123. ]],
  124. ]);
  125. $add_form->handleRequest($request);
  126. if ($add_form->isSubmitted() && $add_form->isValid()) {
  127. $selected = $add_form->getData()['collections'];
  128. $removed = array_filter($already_selected, fn ($x) => !\in_array($x, $selected));
  129. $added = array_filter($selected, fn ($x) => !\in_array($x, $already_selected));
  130. if (\count($removed) > 0) {
  131. $this->removeItem($user, $vars, $removed, $collections);
  132. }
  133. if (\count($added) > 0) {
  134. $this->addItem($user, $vars, $added, $collections);
  135. }
  136. DB::flush();
  137. throw new RedirectException();
  138. }
  139. // form: add to new collection
  140. $create_form = Form::create([
  141. ['name', TextType::class, [
  142. 'label' => _m('Add to a new ' . $this->slug),
  143. 'attr' => [
  144. 'placeholder' => _m('New ' . $this->slug . ' name'),
  145. 'required' => 'required',
  146. ],
  147. 'data' => '',
  148. ]],
  149. ['create', SubmitType::class, [
  150. 'label' => _m('Create a new ' . $this->slug),
  151. 'attr' => [
  152. 'title' => _m('Create a new ' . $this->slug),
  153. ],
  154. ]],
  155. ]);
  156. $create_form->handleRequest($request);
  157. if ($create_form->isSubmitted() && $create_form->isValid()) {
  158. $name = $create_form->getData()['name'];
  159. $this->createCollection($user, $vars, $name);
  160. DB::flush();
  161. throw new RedirectException();
  162. }
  163. $res[] = Formatting::twigRenderFile(
  164. 'collection/widget_add_to.html.twig',
  165. [
  166. 'ctitle' => _m('Add to ' . $this->plural_slug),
  167. 'user' => $user,
  168. 'has_collections' => \count($collections) > 0,
  169. 'add_form' => $add_form->createView(),
  170. 'create_form' => $create_form->createView(),
  171. ],
  172. );
  173. return Event::next;
  174. }
  175. public function onEndShowStyles(array &$styles, string $route): bool
  176. {
  177. $styles[] = 'components/Collection/assets/css/widget.css';
  178. $styles[] = 'components/Collection/assets/css/pages.css';
  179. return Event::next;
  180. }
  181. }