Skip to content

Commit

Permalink
Add support for filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
lyrixx committed Jan 15, 2024
1 parent f0c20b6 commit 6e89577
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 7 deletions.
4 changes: 2 additions & 2 deletions assets/bootstrap.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { startStimulusApp } from '@symfony/stimulus-bundle';
import Carousel from 'stimulus-carousel';

const app = startStimulusApp();
app.register('carousel', Carousel);
const application = startStimulusApp();
application.register('carousel', Carousel);
10 changes: 10 additions & 0 deletions assets/controllers/form-auto-submit-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
connect() {
const form = this.element.querySelector('form');
form.addEventListener('change', () => {
form.requestSubmit();
});
}
}
1 change: 0 additions & 1 deletion config/packages/framework.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ framework:
#fragments: true
php_errors:
log: true
ide: '%env(IDE)%'
trusted_proxies: '%env(TRUSTED_PROXIES)%'
trusted_headers: ['forwarded', 'x-forwarded-for', 'x-forwarded-proto']

Expand Down
24 changes: 21 additions & 3 deletions src/Controller/QotdController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace App\Controller;

use App\Entity\Qotd;
use App\Form\Model\QotdFilters;
use App\Form\Type\QotdFiltersType;
use App\Form\Type\QotdType;
use App\Repository\Model\QotdDirection;
use App\Repository\Model\QotdVote;
Expand All @@ -28,17 +30,33 @@ public function __construct(
#[Route('/', name: 'qotd_index', defaults: ['direction' => QotdDirection::Latest->value])]
#[Route('/top', name: 'qotd_index_top', defaults: ['direction' => QotdDirection::Top->value])]
#[Route('/flop', name: 'qotd_index_flop', defaults: ['direction' => QotdDirection::Flop->value])]
public function index(Request $request, QotdDirection $direction): Response
{
public function index(
Request $request,
QotdDirection $direction,
): Response {
$valid = false;
$filters = new QotdFilters();
$form = $this->createForm(QotdFiltersType::class, $filters);

if ($form->handleRequest($request)->isSubmitted()) {
if ($form->isValid()) {
$valid = true;
} else {
$filters = null;
}
}

$page = max(1, $request->query->getInt('page', 1));
$pagination = $this
->qotdRepository
->findForHomepage($page, $direction)
->findForHomepage($page, $direction, $filters)
;

return $this->render('qotd/index.html.twig', [
'pagination' => $pagination,
'direction' => $direction,
'form' => $form,
'valid' => $valid,
]);
}

Expand Down
10 changes: 10 additions & 0 deletions src/Form/Model/QotdFilters.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace App\Form\Model;

class QotdFilters
{
public ?string $author = null;
public ?bool $withImage = null;
public ?bool $withVideo = null;
}
58 changes: 58 additions & 0 deletions src/Form/Type/QotdFiltersType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace App\Form\Type;

use App\Repository\QotdRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class QotdFiltersType extends AbstractType
{
public function __construct(
private readonly QotdRepository $qotdRepository,
) {
}

public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('author', ChoiceType::class, [
'required' => false,
'placeholder' => 'Any',
'choices' => array_combine($authors = $this->qotdRepository->getAuthors(), $authors),
])
->add('withImage', ChoiceType::class, [
'required' => false,
'placeholder' => 'Any',
'choices' => [
'Yes' => true,
'No' => false,
],
])
->add('withVideo', ChoiceType::class, [
'required' => false,
'placeholder' => 'Any',
'choices' => [
'Yes' => true,
'No' => false,
],
])
;
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'method' => 'GET',
'csrf_protection' => false,
'allow_extra_fields' => true,
]);
}

public function getBlockPrefix(): string
{
return '';
}
}
32 changes: 31 additions & 1 deletion src/Repository/QotdRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
namespace App\Repository;

use App\Entity\Qotd;
use App\Form\Model\QotdFilters;
use App\Paginator\Mode\NativeQuery;
use App\Repository\Model\QotdDirection;
use App\Repository\Model\QotdVote;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Knp\Component\Pager\Pagination\PaginationInterface;
Expand Down Expand Up @@ -54,10 +56,26 @@ public function findLast(): ?Qotd
/**
* @return PaginationInterface<string, Qotd>
*/
public function findForHomepage(int $page, QotdDirection $direction): PaginationInterface
public function findForHomepage(int $page, QotdDirection $direction, QotdFilters $filters = null): PaginationInterface
{
$qb = $this->createQueryBuilder('q');

if ($filters) {
if ($filters->author) {
$qb->andWhere('q.username = :author')->setParameter('author', $filters->author);
}
match ($filters->withImage) {
true => $qb->andWhere('q.images != \'[]\''),
false => $qb->andWhere('q.images = \'[]\''),
null => null,
};
match ($filters->withVideo) {
true => $qb->andWhere('q.videos != \'[]\''),
false => $qb->andWhere('q.videos = \'[]\''),
null => null,
};
}

match ($direction) {
QotdDirection::Top => $qb->addOrderBy('q.vote', 'DESC')->addOrderBy('q.date', 'DESC'),
QotdDirection::Flop => $qb->addOrderBy('q.vote', 'ASC')->addOrderBy('q.date', 'DESC'),
Expand Down Expand Up @@ -330,4 +348,16 @@ public function findBestsOver(string $period): array
->getResult()
;
}

public function getAuthors(): array
{
return $this->createQueryBuilder('q')
->select('q.username', 'count(q.username) as HIDDEN count')
->addOrderBy('count', 'DESC')
->addOrderBy('q.username', 'ASC')
->groupBy('q.username')
->getQuery()
->getResult(Query::HYDRATE_SCALAR_COLUMN)
;
}
}
12 changes: 12 additions & 0 deletions templates/qotd/index.html.twig
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
{% extends 'base.html.twig' %}

{% form_theme form 'bootstrap_5_horizontal_layout.html.twig' %}

{% set active = direction.toTwigActiveSection %}

{% block title %}{{ direction.toTitle }}{% endblock %}

{% block body %}
<details {{ valid ? 'open' }}>
<summary>Filters</summary>
<div class="mb-3" {{ stimulus_controller('form-auto-submit') }}>
{{ form(form, { attr: { id: 'qotd-filters' } } ) }}
<noscript>
<button type="submit" class="btn btn-primary" form="qotd-filters">Filters</button>
</noscript>
</div>
</details>

{% for qotd in pagination %}
{{ include('qotd/_qotd.html.twig', { qotd }, with_context = false) }}
{% else %}
Expand Down

0 comments on commit 6e89577

Please sign in to comment.