Implemented search by tags with these operators: AND (&), OR (|)
Fixes #30
This commit is contained in:
parent
7c2c17c571
commit
9921a789e5
2 changed files with 116 additions and 19 deletions
|
@ -25,6 +25,7 @@ use Jsvrcek\ICS\Utility\Formatter;
|
|||
use Jsvrcek\ICS\CalendarStream;
|
||||
use Jsvrcek\ICS\CalendarExport;
|
||||
use Symfony\Component\Validator\Constraints\DateTime;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
|
||||
/**
|
||||
* Tag controller.
|
||||
|
@ -47,26 +48,98 @@ class TagController extends Controller
|
|||
|
||||
/** @var EntityRepository $repo */
|
||||
$repo = $em->getRepository('CalciferBundle:Tag');
|
||||
$tags = [];
|
||||
$operator = 'or';
|
||||
if (strpos($slug,'|') !== false) {
|
||||
$slugs = explode('|',$slug);
|
||||
foreach($slugs as $item) {
|
||||
/** @var Tag $tag */
|
||||
$tag = $repo->findOneBy(['slug' => $item]);
|
||||
|
||||
/** @var Tag $location */
|
||||
$tag = $repo->findOneBy(['slug' => $slug]);
|
||||
if ($tag instanceof Tag) {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
}
|
||||
} else if (strpos($slug,'&') !== false) {
|
||||
$slugs = explode('&',$slug);
|
||||
$operator = 'and';
|
||||
foreach($slugs as $item) {
|
||||
/** @var Tag $tag */
|
||||
$tag = $repo->findOneBy(['slug' => $item]);
|
||||
|
||||
if (!$tag) {
|
||||
if ($tag instanceof Tag) {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/** @var Tag $tag */
|
||||
$tag = $repo->findOneBy(['slug' => $slug]);
|
||||
|
||||
if ($tag instanceof Tag) {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($tags) == 0) {
|
||||
throw $this->createNotFoundException('Unable to find tag entity.');
|
||||
}
|
||||
|
||||
$now = new \DateTime();
|
||||
$now->setTime(0, 0, 0);
|
||||
|
||||
/** @var QueryBuilder $qb */
|
||||
$qb = $em->createQueryBuilder();
|
||||
$qb->select(array('e'))
|
||||
->from('CalciferBundle:Event', 'e')
|
||||
->join('e.tags', 't', 'WITH', $qb->expr()->in('t.id', $tag->id))
|
||||
->where('e.startdate >= :startdate')
|
||||
->orderBy('e.startdate')
|
||||
->setParameter('startdate', $now);
|
||||
$entities = $qb->getQuery()->execute();
|
||||
$entities = null;
|
||||
if ($operator == 'and') {
|
||||
$sql = <<<EOF
|
||||
SELECT * FROM events AS e
|
||||
WHERE id IN (
|
||||
WITH events_on_tags AS (
|
||||
SELECT events_id, array_agg(tags_id) as tags
|
||||
FROM events2tags
|
||||
GROUP BY events_id
|
||||
)
|
||||
SELECT events_id FROM events_on_tags
|
||||
WHERE tags @> array[@tags@]
|
||||
)
|
||||
AND e.startdate >= :startdate
|
||||
ORDER BY e.startdate
|
||||
EOF;
|
||||
$tag_ids = array_reduce($tags,function($carry,$item){
|
||||
if (strlen($carry) == 0) {
|
||||
return $item->id;
|
||||
} else {
|
||||
return $carry . ',' . $item->id;
|
||||
}
|
||||
});
|
||||
|
||||
$sql = str_replace('@tags@',$tag_ids,$sql);
|
||||
|
||||
$rsm = new ResultSetMappingBuilder($em);
|
||||
$rsm->addRootEntityFromClassMetadata('CalciferBundle:Event','e');
|
||||
|
||||
$query = $em->createNativeQuery($sql,$rsm);
|
||||
|
||||
$query->setParameter('startdate',$now);
|
||||
|
||||
$entities = $query->getResult();
|
||||
|
||||
} else {
|
||||
/** @var QueryBuilder $qb */
|
||||
$qb = $em->createQueryBuilder();
|
||||
$qb->select(array('e'))
|
||||
->from('CalciferBundle:Event', 'e')
|
||||
->where('e.startdate >= :startdate')
|
||||
->orderBy('e.startdate')
|
||||
->setParameter('startdate', $now);
|
||||
|
||||
$qb->join('e.tags', 't', 'WITH', $qb->expr()->in('t.id', array_reduce($tags,function($carry,$item){
|
||||
if (strlen($carry) == 0) {
|
||||
return $item->id;
|
||||
} else {
|
||||
return $carry . ',' . $item->id;
|
||||
}
|
||||
})));
|
||||
$entities = $qb->getQuery()->execute();
|
||||
}
|
||||
|
||||
if ($format == 'ics') {
|
||||
$calendar = new Calendar();
|
||||
|
@ -110,7 +183,8 @@ class TagController extends Controller
|
|||
} else {
|
||||
return array(
|
||||
'entities' => $entities,
|
||||
'tag' => $tag,
|
||||
'tags' => $tags,
|
||||
'operator' => $operator,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,22 @@
|
|||
<div class="ui column">
|
||||
<h1>
|
||||
Termine
|
||||
{% if tag|default(false) %} für Tag „{{ tag.name }}“{% endif %}
|
||||
{% if tags|default(false) %}
|
||||
{% if tags|length == 1 %}
|
||||
für Tag {{ tags[0].name }}
|
||||
{% elseif(tags|length == 2) %}
|
||||
für die Tags {{ tags[0].name }} {% if operator == 'or' %}oder{% else %}und{% endif %} {{ tags[1].name }}
|
||||
{% else %}
|
||||
für die Tags
|
||||
{% for tag in tags %}
|
||||
{% if not loop.last %}
|
||||
{{ tag.name }}{% if loop.index < (tags|length - 1) %},{% endif %}
|
||||
{% else %}
|
||||
{% if operator == 'or' %}oder{% else %}und{% endif %} {{ tag.name }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if location|default(false) %} für Ort „{{ location.name }}“ <a class="location-edit" href="{{ path("location_edit",{slug:location.slug}) }}"><i class="ui icon edit inverted green circular link" data-content="Ort bearbeiten" title="Ort bearbeiten"></i> </a> {% endif %}
|
||||
</h1>
|
||||
{% if tag|default(false) %}
|
||||
|
@ -68,10 +83,18 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui three column page grid stackable">
|
||||
{% for entity in entities %}
|
||||
{{ include('CalciferBundle:Event:event_box.html.twig',{'truncate_summary':true}) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if entities|length > 0 %}
|
||||
<div class="ui three column page grid stackable">
|
||||
{% for entity in entities %}
|
||||
{{ include('CalciferBundle:Event:event_box.html.twig',{'truncate_summary':true}) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="ui one column page grid stackable">
|
||||
<div class="ui column">
|
||||
<p>Es konnten keine Termine gefunden werden.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
Reference in a new issue