Implement tag filtering
This commit is contained in:
parent
e2bd1a7c3b
commit
b8ae8bb8a7
@ -15,6 +15,7 @@ readonly class SnipFilterRequest implements CachableDtoInterface
|
||||
public function __construct(
|
||||
public ?string $visibility = self::VISIBILITY_VISIBLE,
|
||||
public ?string $sort = self::SORT_DATE,
|
||||
public ?string $tag = null,
|
||||
) {}
|
||||
|
||||
public function toArray(): array
|
||||
@ -22,6 +23,7 @@ readonly class SnipFilterRequest implements CachableDtoInterface
|
||||
return [
|
||||
'visibility' => $this->visibility,
|
||||
'sort' => $this->sort,
|
||||
'tag' => $this->tag,
|
||||
];
|
||||
}
|
||||
}
|
@ -79,6 +79,13 @@ class SnipRepository extends ServiceEntityRepository
|
||||
throw new \InvalidArgumentException('Invalid sort option: ', $request->sort);
|
||||
}
|
||||
|
||||
if ($request->tag) {
|
||||
$qb->innerJoin('s.tags', 't')
|
||||
->andWhere('t.name = :tag')
|
||||
->setParameter('tag', $request->tag)
|
||||
;
|
||||
}
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ namespace App\Repository;
|
||||
use App\Entity\Tag;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Tag>
|
||||
@ -22,28 +23,8 @@ class TagRepository extends ServiceEntityRepository
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Tag[] Returns an array of Tag objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('t')
|
||||
// ->andWhere('t.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('t.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?Tag
|
||||
// {
|
||||
// return $this->createQueryBuilder('t')
|
||||
// ->andWhere('t.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
public function findAllByUser(UserInterface $user): array
|
||||
{
|
||||
return $this->findBy(['user' => $user]);
|
||||
}
|
||||
}
|
||||
|
35
src/Twig/Extension/SnipFilterExtension.php
Normal file
35
src/Twig/Extension/SnipFilterExtension.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Twig\Extension;
|
||||
|
||||
use App\Repository\TagRepository;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class SnipFilterExtension extends AbstractExtension
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TagRepository $tagRepository,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('snipSortOptions', fn() => ['name', 'date']),
|
||||
new TwigFunction('snipFilterOptions', fn() => ['all', 'visible', 'hidden', 'archived']),
|
||||
new TwigFunction('snipTagOptions', fn() => $this->getSnipTagOptions()),
|
||||
];
|
||||
}
|
||||
|
||||
private function getSnipTagOptions(): array
|
||||
{
|
||||
$tags[null] = 'All tags';
|
||||
foreach ($this->tagRepository->findAllByUser($this->security->getUser()) as $tag) {
|
||||
$tags[(string)$tag] = (string)$tag;
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
}
|
17
templates/base/two.column.8-4.html.twig
Normal file
17
templates/base/two.column.8-4.html.twig
Normal file
@ -0,0 +1,17 @@
|
||||
{% extends 'base/container.html.twig' %}
|
||||
|
||||
{% block container %}
|
||||
<div class="row">
|
||||
<div class="col-sm mx-auto">
|
||||
{% if title is defined %}<h3>{{ title }}</h3>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
{% block column1 %}{% endblock %}
|
||||
</div>
|
||||
<div class="col-4">
|
||||
{% block column2 %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,4 +1,4 @@
|
||||
{% extends 'base/two.column.html.twig' %}
|
||||
{% extends 'base/two.column.8-4.html.twig' %}
|
||||
|
||||
{% set title = 'My Snips' %}
|
||||
|
||||
@ -15,6 +15,9 @@
|
||||
<span>
|
||||
{{ include('snip/badge.html.twig', {snip: snip}) }}
|
||||
{{ snip }}
|
||||
{% for tag in snip.tags %}
|
||||
<span class="badge bg-secondary">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
@ -24,12 +27,12 @@
|
||||
{% block column2 %}
|
||||
<h3>Filters</h3>
|
||||
|
||||
<h5>Ordering</h5>
|
||||
<h5>Sort by</h5>
|
||||
<div class="list-group">
|
||||
{% for sortOption in ['name', 'date'] %}
|
||||
{% for sortOption in snipSortOptions() %}
|
||||
<a href="{{ path('snip_index', {sort: sortOption}) }}"
|
||||
class="list-group-item list-group-item-action {% if sortOption is same as(request.sort) %}list-group-item-primary{% endif %}">
|
||||
Sort by {{ sortOption|capitalize }}
|
||||
{{ sortOption|capitalize }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@ -37,11 +40,22 @@
|
||||
<br>
|
||||
<h5>Visibility</h5>
|
||||
<div class="list-group">
|
||||
{% for visibilityOption in ['all', 'visible', 'hidden', 'archived'] %}
|
||||
{% for visibilityOption in snipFilterOptions() %}
|
||||
<a href="{{ path('snip_index', {visibility: visibilityOption}) }}"
|
||||
class="list-group-item list-group-item-action {% if request.visibility is same as(visibilityOption) %}list-group-item-primary{% endif %}">
|
||||
Show {{ visibilityOption|capitalize }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h5>Tags</h5>
|
||||
<div class="list-group">
|
||||
{% for key,tagOption in snipTagOptions() %}
|
||||
<a href="{{ path('snip_index', {tag: key}) }}"
|
||||
class="list-group-item list-group-item-action {% if request.tag is same as(key) %}list-group-item-primary{% endif %}">
|
||||
{{ tagOption|capitalize }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
@ -37,10 +37,7 @@
|
||||
<div class="card" style="width: 100%;">
|
||||
<h4 class="card-header">
|
||||
{{ include('snip/badge.html.twig', {snip: snip}) }}
|
||||
{{ snip }} <small class="text-muted">#{{ snip.id }}</small><br>
|
||||
{% for tag in snip.tags %}
|
||||
<span class="badge bg-secondary">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
{{ snip }} <small class="text-muted">#{{ snip.id }}</small>
|
||||
</h4>
|
||||
<div class="card-body">
|
||||
{{ content|raw }}
|
||||
@ -53,6 +50,9 @@
|
||||
Created at {{ snip.activeVersion.id.dateTime|date('Y-m-d H:i:s') }}
|
||||
|
||||
{{ include('user/badge.html.twig', {user: snip.createdBy}) }}
|
||||
{% for tag in snip.tags %}
|
||||
<span class="badge bg-secondary">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends 'base/two.column.html.twig' %}
|
||||
{% extends 'base/two.column.6-6.html.twig' %}
|
||||
|
||||
{% set title = app.user.name %}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user