diff --git a/src/Controller/AbstractExtendedController.php b/src/Controller/AbstractExtendedController.php index ba33a59..0dd4f1d 100644 --- a/src/Controller/AbstractExtendedController.php +++ b/src/Controller/AbstractExtendedController.php @@ -3,6 +3,7 @@ use App\Form\AbstractFormManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; @@ -48,7 +49,28 @@ */ protected function createNamedCustomForm(string $name, string $type, array $options = []): AbstractFormManager { - $formBuilder = $this->container->get('form.factory')->createNamedBuilder($name, FormType::class); - return new $type($formBuilder, $options); + /** @var FormFactory $formFactory */ + $formFactory = $this->container->get('form.factory'); + $formBuilder = $formFactory->createNamedBuilder($name, FormType::class); + return new $type($formBuilder, $options, true); + } + + /** + * Create a form inherited from AbstractGenericForm with get method + * + * @param string $name + * @param string $type + * @param array $options + * @return AbstractFormManager + */ + protected function createNamedGetCustomForm(string $name, string $type, array $options = []): AbstractFormManager + { + /** @var FormFactory $formFactory */ + $formFactory = $this->container->get('form.factory'); + $formBuilder = $formFactory->createNamedBuilder($name, FormType::class, [], [ + 'csrf_protection' => false, + ]); + $formBuilder->setMethod('GET'); + return new $type($formBuilder, $options, false); } } diff --git a/src/Controller/ActivityController.php b/src/Controller/ActivityController.php index b0453a5..f7b4108 100644 --- a/src/Controller/ActivityController.php +++ b/src/Controller/ActivityController.php @@ -10,6 +10,7 @@ use App\Form\Activity\ActivityAddForm; use App\Form\Activity\ActivityDeleteForm; use App\Form\Activity\ActivityEditForm; +use App\Form\Activity\ActivityFilterForm; /** * Controller for activity related pages @@ -31,11 +32,14 @@ $activityRepository = $entityManager->getRepository(ActivityEntity::class); /** @var ActorRepository $actorRepository */ $actorRepository = $entityManager->getRepository(ActorEntity::class); + + // Get actors + $actors = $actorRepository->findAll(); // Activity add form /** @var ActivityAddForm $activityAddForm */ $activityAddForm = $this->createNamedCustomForm('activityAdd', ActivityAddForm::class, [ - 'actors' => $actorRepository->findAll() + 'actors' => $actors, ]); $activityAddForm->handleRequest($request); if ($activityAddForm->isSubmitted() && $activityAddForm->isValid()) { @@ -84,11 +88,21 @@ } } - // Get activities - $activities = $activityRepository->findAll(); + // Filter + /** @var ActivityFilterForm $activityFilterForm */ + $activityFilterForm = $this->createNamedGetCustomForm('activityFilter', ActivityFilterForm::class, [ + 'actors' => $actors, + ]); + $activityFilterForm->handleRequest($request); + if($activityFilterForm->isSubmitted() && $activityFilterForm->isValid()) { + $activities = $activityFilterForm->getActivities($activityRepository); + } else { + $activities = $activityRepository->findAll(); + } return $this->render('activity/activities.html.twig', [ 'activities' => $activities, + 'activityFilterForm' => $activityFilterForm, 'activityDeleteForm' => $activityDeleteForm, 'activityAddForm' => $activityAddForm, ]); diff --git a/src/Controller/ActorController.php b/src/Controller/ActorController.php index a23b023..7fdcaad 100644 --- a/src/Controller/ActorController.php +++ b/src/Controller/ActorController.php @@ -109,12 +109,6 @@ // Get actor $actor = $actorRepository->find($id); - // Get activities - $activities = $activityRepository->findBy([ - 'actor' => $actor, - 'status' => StatusEnum::ACTIVE_STATUS - ]); - // Actor edit form /** @var ActorEditForm $actorEditForm */ $actorEditForm = $this->createNamedCustomForm('edit', ActorEditForm::class); @@ -159,6 +153,12 @@ // Update fields $actorEditForm->updateFields($actor); + + // Get activities + $activities = $activityRepository->findBy([ + 'actor' => $actor, + 'status' => StatusEnum::ACTIVE_STATUS + ]); return $this->render('actor/actor.html.twig', [ 'actor' => $actor, diff --git a/src/Form/AbstractFormManager.php b/src/Form/AbstractFormManager.php index 5ea86d1..6e35703 100644 --- a/src/Form/AbstractFormManager.php +++ b/src/Form/AbstractFormManager.php @@ -6,6 +6,7 @@ use Symfony\Component\Form\FormView; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\HttpFoundation\Request; +use phpDocumentor\Reflection\Types\Mixed_; /** * Generic form @@ -19,22 +20,29 @@ /** @var string Unique ID of the form */ protected $id; + /** @var bool If the form uses a token to check validity */ + protected $usesToken = true; + /** * @param FormBuilderInterface $formBuilder * @param array $data Additional data + * @param bool $usesToken If the form uses a token to check validity */ - public function __construct(FormBuilderInterface $formBuilder, array $data = []) + public function __construct(FormBuilderInterface $formBuilder, array $data = [], bool $usesToken = true) { + $this->usesToken = $usesToken; $this->id = md5(json_encode([ 'class' => get_class($this), 'name' => $formBuilder->getName(), ])); $this->addFields($formBuilder, $data); - $formBuilder->add('_ID', HiddenType::class, [ - 'attr' => [ - 'value' => $this->id, - ], - ]); + if ($usesToken) { + $formBuilder->add('_ID', HiddenType::class, [ + 'attr' => [ + 'value' => $this->id, + ], + ]); + } $this->form = $formBuilder->getForm(); } @@ -71,7 +79,7 @@ { if ($this->form->isSubmitted()) { $data = $this->form->getData(); - return $data['_ID'] == $this->id; + return !$this->usesToken || $data['_ID'] == $this->id; } return false; } @@ -120,6 +128,10 @@ return Null; } + public function getNormData(): Mixed_ + { + } + /** * @param FormBuilderInterface $formBuilder * @param array $data Additional data diff --git a/src/Form/Activity/ActivityAddForm.php b/src/Form/Activity/ActivityAddForm.php index 711f018..bf464d1 100644 --- a/src/Form/Activity/ActivityAddForm.php +++ b/src/Form/Activity/ActivityAddForm.php @@ -21,10 +21,10 @@ /** * {@inheritdoc} */ - public function __construct(FormBuilderInterface $formBuilder, array $data = []) + public function __construct(FormBuilderInterface $formBuilder, array $data = [], bool $usesToken = true) { $this->actors = $data['actors']; - parent::__construct($formBuilder, $data); + parent::__construct($formBuilder, $data, $usesToken); } /** diff --git a/src/Form/Activity/ActivityEditForm.php b/src/Form/Activity/ActivityEditForm.php index 494bfbc..c3af5d6 100644 --- a/src/Form/Activity/ActivityEditForm.php +++ b/src/Form/Activity/ActivityEditForm.php @@ -21,10 +21,10 @@ /** * {@inheritdoc} */ - public function __construct(FormBuilderInterface $formBuilder, array $data = []) + public function __construct(FormBuilderInterface $formBuilder, array $data = [], bool $usesToken = true) { $this->actors = $data['actors']; - parent::__construct($formBuilder, $data); + parent::__construct($formBuilder, $data, $usesToken); } /** diff --git a/src/Form/Activity/ActivityFilterForm.php b/src/Form/Activity/ActivityFilterForm.php new file mode 100644 index 0000000..1d8dc3c --- /dev/null +++ b/src/Form/Activity/ActivityFilterForm.php @@ -0,0 +1,87 @@ +actors = $data['actors']; + + parent::__construct($formBuilder, $data, $usesToken); + } + + /** + * Create query builder + * + * @param ActivityRepository $activityRepository + * @return array + */ + public function getActivities(ActivityRepository $activityRepository): array + { + $data = $this->getData(); + + // Create filter + $criteria = new Criteria(); + + // Filter actors + if(!is_null($data['actor'])) { + $criteria->andWhere($criteria->expr()->eq('activity.actor', $data['actor'])); + } + + // Create query + $query = $activityRepository->createQueryBuilder('activity'); + $query->join(ActorEntity::class, 'actor', Join::WITH, 'activity.actor = actor'); + $query->addCriteria($criteria); + + return $query->getQuery()->execute([], Query::HYDRATE_OBJECT); + } + + /** + * {@inheritdoc} + */ + public function getTemplate(): string + { + return '_includes/html/form/activity/filter.html.twig'; + } + + /** + * {@inheritdoc} + */ + protected function addFields($formBuilder, $options): void + { + $formBuilder->add('actor', EntityType::class, [ + 'class' => ActorEntity::class, + 'choices' => $this->actors, + 'group_by' => function (ActorEntity $choice) { + if ($choice->getFollowed()) { + return 'Suivi'; + } + if ($choice->getActive()) { + return 'Actif'; + } + + return 'Inactif'; + }, + 'choice_label' => 'displayName', + 'required' => false, + ]) + ->add('submit', SubmitType::class); + } +} \ No newline at end of file diff --git a/src/Repository/ActivityRepository.php b/src/Repository/ActivityRepository.php index f9ca693..c3cbd06 100644 --- a/src/Repository/ActivityRepository.php +++ b/src/Repository/ActivityRepository.php @@ -3,9 +3,11 @@ use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Query\Expr\Join; use App\Entity\ActorEntity; use App\Enum\StatusEnum; +use Doctrine\Common\Collections\Criteria; /** * Repository for workspaces @@ -13,6 +15,32 @@ class ActivityRepository extends EntityRepository { + /** @var array Default sorting */ + public const DEFAULT_ORDER = [ + 'name' => 'asc', + ]; + + /** + * {@inheritdoc} + */ + public function findAll(): array + { + return $this->findBy([], ActivityRepository::DEFAULT_ORDER); + } + + /** + * {@inheritdoc} + */ + public function createQueryBuilder($alias, $indexBy = null): QueryBuilder + { + $queryBuilder = parent::createQueryBuilder($alias, $indexBy); + foreach ($this::DEFAULT_ORDER as $field => $order) { + $queryBuilder->addOrderBy($alias . '.' . $field, $order); + } + + return $queryBuilder; + } + /** * Find active activities of followed actors * @@ -20,11 +48,16 @@ */ public function findActiveFollowed(): array { + // Create criteria + $criteria =new Criteria(); + $criteria->andWhere($criteria->expr() + ->eq('actor.followed', true)); + $criteria->andWhere($criteria->expr() + ->in('activity.status', StatusEnum::ACTIVE_STATUS)); + $query = $this->createQueryBuilder('activity'); $query->join(ActorEntity::class, 'actor', Join::WITH, 'activity.actor = actor'); - $query->andWhere($query->expr() - ->eq('actor.followed', true)); - $query->andWhere($query->expr()->in('activity.status', StatusEnum::ACTIVE_STATUS)); + $query->addCriteria($criteria); return $query->getQuery()->execute([], Query::HYDRATE_OBJECT); } diff --git a/templates/_includes/html/form/activity/filter.html.twig b/templates/_includes/html/form/activity/filter.html.twig new file mode 100644 index 0000000..1a338f6 --- /dev/null +++ b/templates/_includes/html/form/activity/filter.html.twig @@ -0,0 +1,15 @@ +{{ form_start(form)}} +
+
+
+ {{ form_label(form.actor, 'Acteur', {label_attr: {class: 'input-text-label'}}) }} + {{ form_widget(form.actor, {attr: {class: 'w-100'}}) }} +
+
+ {{ form_widget(form.submit, {attr: {class: 'w-100'}, label: 'Filtrer'}) }} +
+
+
+

+

+{{ form_end(form) }} \ No newline at end of file diff --git a/templates/activity/activities.html.twig b/templates/activity/activities.html.twig index d40eadf..e064365 100644 --- a/templates/activity/activities.html.twig +++ b/templates/activity/activities.html.twig @@ -10,6 +10,7 @@

Activités

+ {% include '_includes/html/genericForm.html.twig' with {form: activityFilterForm} only %} {% include "_includes/html/arrays/activity.html.twig" with {activities: activities, activityDeleteForm: activityDeleteForm} only %}