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 function __construct(
|
||||||
public ?string $visibility = self::VISIBILITY_VISIBLE,
|
public ?string $visibility = self::VISIBILITY_VISIBLE,
|
||||||
public ?string $sort = self::SORT_DATE,
|
public ?string $sort = self::SORT_DATE,
|
||||||
|
public ?string $tag = null,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function toArray(): array
|
public function toArray(): array
|
||||||
@ -22,6 +23,7 @@ readonly class SnipFilterRequest implements CachableDtoInterface
|
|||||||
return [
|
return [
|
||||||
'visibility' => $this->visibility,
|
'visibility' => $this->visibility,
|
||||||
'sort' => $this->sort,
|
'sort' => $this->sort,
|
||||||
|
'tag' => $this->tag,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -79,6 +79,13 @@ class SnipRepository extends ServiceEntityRepository
|
|||||||
throw new \InvalidArgumentException('Invalid sort option: ', $request->sort);
|
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();
|
return $qb->getQuery()->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ namespace App\Repository;
|
|||||||
use App\Entity\Tag;
|
use App\Entity\Tag;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @extends ServiceEntityRepository<Tag>
|
* @extends ServiceEntityRepository<Tag>
|
||||||
@ -22,28 +23,8 @@ class TagRepository extends ServiceEntityRepository
|
|||||||
$this->getEntityManager()->flush();
|
$this->getEntityManager()->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
public function findAllByUser(UserInterface $user): array
|
||||||
// * @return Tag[] Returns an array of Tag objects
|
{
|
||||||
// */
|
return $this->findBy(['user' => $user]);
|
||||||
// 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()
|
|
||||||
// ;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
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' %}
|
{% set title = 'My Snips' %}
|
||||||
|
|
||||||
@ -15,6 +15,9 @@
|
|||||||
<span>
|
<span>
|
||||||
{{ include('snip/badge.html.twig', {snip: snip}) }}
|
{{ include('snip/badge.html.twig', {snip: snip}) }}
|
||||||
{{ snip }}
|
{{ snip }}
|
||||||
|
{% for tag in snip.tags %}
|
||||||
|
<span class="badge bg-secondary">{{ tag }}</span>
|
||||||
|
{% endfor %}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -24,12 +27,12 @@
|
|||||||
{% block column2 %}
|
{% block column2 %}
|
||||||
<h3>Filters</h3>
|
<h3>Filters</h3>
|
||||||
|
|
||||||
<h5>Ordering</h5>
|
<h5>Sort by</h5>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for sortOption in ['name', 'date'] %}
|
{% for sortOption in snipSortOptions() %}
|
||||||
<a href="{{ path('snip_index', {sort: sortOption}) }}"
|
<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 %}">
|
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>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@ -37,11 +40,22 @@
|
|||||||
<br>
|
<br>
|
||||||
<h5>Visibility</h5>
|
<h5>Visibility</h5>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for visibilityOption in ['all', 'visible', 'hidden', 'archived'] %}
|
{% for visibilityOption in snipFilterOptions() %}
|
||||||
<a href="{{ path('snip_index', {visibility: visibilityOption}) }}"
|
<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 %}">
|
class="list-group-item list-group-item-action {% if request.visibility is same as(visibilityOption) %}list-group-item-primary{% endif %}">
|
||||||
Show {{ visibilityOption|capitalize }}
|
Show {{ visibilityOption|capitalize }}
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</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 %}
|
{% endblock %}
|
@ -37,10 +37,7 @@
|
|||||||
<div class="card" style="width: 100%;">
|
<div class="card" style="width: 100%;">
|
||||||
<h4 class="card-header">
|
<h4 class="card-header">
|
||||||
{{ include('snip/badge.html.twig', {snip: snip}) }}
|
{{ include('snip/badge.html.twig', {snip: snip}) }}
|
||||||
{{ snip }} <small class="text-muted">#{{ snip.id }}</small><br>
|
{{ snip }} <small class="text-muted">#{{ snip.id }}</small>
|
||||||
{% for tag in snip.tags %}
|
|
||||||
<span class="badge bg-secondary">{{ tag }}</span>
|
|
||||||
{% endfor %}
|
|
||||||
</h4>
|
</h4>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{{ content|raw }}
|
{{ content|raw }}
|
||||||
@ -53,6 +50,9 @@
|
|||||||
Created at {{ snip.activeVersion.id.dateTime|date('Y-m-d H:i:s') }}
|
Created at {{ snip.activeVersion.id.dateTime|date('Y-m-d H:i:s') }}
|
||||||
|
|
||||||
{{ include('user/badge.html.twig', {user: snip.createdBy}) }}
|
{{ include('user/badge.html.twig', {user: snip.createdBy}) }}
|
||||||
|
{% for tag in snip.tags %}
|
||||||
|
<span class="badge bg-secondary">{{ tag }}</span>
|
||||||
|
{% endfor %}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</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 %}
|
{% set title = app.user.name %}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user