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\CalendarStream;
|
||||||
use Jsvrcek\ICS\CalendarExport;
|
use Jsvrcek\ICS\CalendarExport;
|
||||||
use Symfony\Component\Validator\Constraints\DateTime;
|
use Symfony\Component\Validator\Constraints\DateTime;
|
||||||
|
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tag controller.
|
* Tag controller.
|
||||||
|
@ -47,26 +48,98 @@ class TagController extends Controller
|
||||||
|
|
||||||
/** @var EntityRepository $repo */
|
/** @var EntityRepository $repo */
|
||||||
$repo = $em->getRepository('CalciferBundle:Tag');
|
$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 */
|
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 instanceof Tag) {
|
||||||
|
$tags[] = $tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/** @var Tag $tag */
|
||||||
$tag = $repo->findOneBy(['slug' => $slug]);
|
$tag = $repo->findOneBy(['slug' => $slug]);
|
||||||
|
|
||||||
if (!$tag) {
|
if ($tag instanceof Tag) {
|
||||||
|
$tags[] = $tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($tags) == 0) {
|
||||||
throw $this->createNotFoundException('Unable to find tag entity.');
|
throw $this->createNotFoundException('Unable to find tag entity.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$now = new \DateTime();
|
$now = new \DateTime();
|
||||||
$now->setTime(0, 0, 0);
|
$now->setTime(0, 0, 0);
|
||||||
|
|
||||||
|
$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 */
|
/** @var QueryBuilder $qb */
|
||||||
$qb = $em->createQueryBuilder();
|
$qb = $em->createQueryBuilder();
|
||||||
$qb->select(array('e'))
|
$qb->select(array('e'))
|
||||||
->from('CalciferBundle:Event', 'e')
|
->from('CalciferBundle:Event', 'e')
|
||||||
->join('e.tags', 't', 'WITH', $qb->expr()->in('t.id', $tag->id))
|
|
||||||
->where('e.startdate >= :startdate')
|
->where('e.startdate >= :startdate')
|
||||||
->orderBy('e.startdate')
|
->orderBy('e.startdate')
|
||||||
->setParameter('startdate', $now);
|
->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();
|
$entities = $qb->getQuery()->execute();
|
||||||
|
}
|
||||||
|
|
||||||
if ($format == 'ics') {
|
if ($format == 'ics') {
|
||||||
$calendar = new Calendar();
|
$calendar = new Calendar();
|
||||||
|
@ -110,7 +183,8 @@ class TagController extends Controller
|
||||||
} else {
|
} else {
|
||||||
return array(
|
return array(
|
||||||
'entities' => $entities,
|
'entities' => $entities,
|
||||||
'tag' => $tag,
|
'tags' => $tags,
|
||||||
|
'operator' => $operator,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,22 @@
|
||||||
<div class="ui column">
|
<div class="ui column">
|
||||||
<h1>
|
<h1>
|
||||||
Termine
|
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 %}
|
{% 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>
|
</h1>
|
||||||
{% if tag|default(false) %}
|
{% if tag|default(false) %}
|
||||||
|
@ -68,10 +83,18 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if entities|length > 0 %}
|
||||||
<div class="ui three column page grid stackable">
|
<div class="ui three column page grid stackable">
|
||||||
{% for entity in entities %}
|
{% for entity in entities %}
|
||||||
{{ include('CalciferBundle:Event:event_box.html.twig',{'truncate_summary':true}) }}
|
{{ include('CalciferBundle:Event:event_box.html.twig',{'truncate_summary':true}) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</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 %}
|
{% endblock %}
|
||||||
|
|
Reference in a new issue