Форма поиска на Symfony
Теперь когда у нас есть стили и мы можем сделать наш блог красивым, сделаем форму поиска. Поиск есть почти в каждом приложении, так почему бы и нам не иметь свой?
Для начала нам нужна верстка формы поиска. Раз у нас уже есть bootstrap, возьмем готовую. Вы можете взять целое меню bootstrap и вставить в неё нашу форму или же только значения action и name у тега input.
<form class="form-inline my-2 my-lg-0" action="{{ path('blog_search') }}" method="get">
<input class="form-control mr-sm-2" type="search" aria-label="Search" name="q">
<button class="btn btn-default my-2 my-sm-0" type="submit">Ищем</button>
</form>
Во-первых, необязательно для поиска использовать форму Symfony, мы можем в теге action написать имя нашего экшена, который мы назвали blog_search. Туда будут уходить данные, отправленные методом get, то есть они будут такого вида:
127.0.0.1/posts/search?q=наш_запрос
q - потому что так мы назвали наш input. search - наш будущий роут, который будет обрабатывать наш экшен blog_search, куда мы отправляем наш запрос. Поиск мы будем делать только по названию статьи. Вы же помните, что все запросы мы пишем в PostsRepository? Так что давайте откроем этот файл и напишем следующий метод:
public function searchByQuery(string $query)
{
return $this->createQueryBuilder('p')
->where('p.title LIKE :query')
->setParameter('query', '%'. $query. '%')
->getQuery()
->getResult();
}
Все запросы в ваших репозиториях будут начинаться с метода createQueryBuilder, куда вы передаёте ссылку (alias) на вашу таблицу. Можно писать как post, так и p, при условии что у вас только одна таблица начинается на букву p. Дальше мы указываем, что хотим все данные, где название (p.title) похоже (LIKE) на наш запрос (:query). Вам это может напомнить работу с PDO - все эти плейсхолдеры и биндинги. Поскольку мы хотим, чтобы слово, которое мы ищем в названии, могло находиться и в начале, и в середине, и в конце, обрамляем знаками процент полностью наш запрос с двух сторон. Потом получаем наш результат. Теперь этот метод мы вызовем в нашем экшене в контроллере PostsController.
Переходим в PostsController и пишем метод search().
/**
* @Route("/posts/search", name="blog_search")
*/
public function search(Request $request)
{
$query = $request->query->get('q');
$posts = $this->postRepository->searchByQuery($query);
return $this->render('blog/query_post.html.twig', [
'posts' => $posts
]));
}
Как мы уже договорились, запросы будут идти на роут /posts/search, а называться он будет blog_search. Определяем это в аннотациях к методу. В качестве аргумента передаем наш Request, где хранится наш запрос. Для этого мы должны вызвать метод query() и у него метод get(), куда передаем q - имя нашего инпута, откуда мы хотим брать данные. Присваиваем переменной posts результат выполнения нашего метода searchByQuery и рендерим шаблон, где в цикле перебираем наш массив (массив, потому что результатов поиска может быть много).
{% extends 'base.html.twig' %}
{% block title %}Результаты поиска{% endblock %}
{% block body %}
{% for post in posts %}
<div class="media text-muted pt-3">
<p class="media-body pb-3 mb-0 small lh-125 border-bottom border-gray">
<a href="{{ path('blog_show', {id: post.id}) }}">{{ post.title }}</a><
{{ post.body | slice(0, 255) ~ '...' }}
</p>
</div>
{% endfor %}
<small class="d-block text-right mt-3">
<a href="{{ path('blog_home') }}">На главную</a>
</small>
{% endblock %}
В шаблоне мы также использовали функцию twig slice, которая обрезает исходный текст до 255 символов и проставляет многоточие. Теперь вы можете попробовать ввести что-то в поиск и получить результат!
На этом первая часть курса закончилась. Мы научились всему, чтобы перейти к более серьёзным вещам: аутентификации на сайте, комментариям к постам, сложным связям между тегами и постами и многому другому, что вас ждёт во второй части курса!
Комментарии