Я использую:
- Symfony v3.0.6;
- Доктрина v2.5.4
Я построил поиск по сайту с LIKE в запросе доктрины.
// My search query
$query = $em->createQueryBuilder()
->select('i')
->from('AppBundle:Item', 'i')
->where('i.name_lv LIKE :term')
->andWhere('i.description_lv LIKE :term')
->setParameter('term', '%' . $term . '%')
->orderBy('i.price', 'DESC')
->getQuery();
Он отлично работает, если я пишу запросы вручную в адресную строку браузера.
Например:
возвращает страницу с продуктами, которые были найдены.
ПРОБЛЕМА:
Хотя, когда я использую кнопку поиска в форме (как и каждый пользователь)
// Relevant part of twig template showing my search form
<div class="search-box row clearfix text-center">
<form id="search-form" method="GET">
<fieldset>
<p>{{ "goods.msg.searchSomething"|trans }}</p>
<input type="text" class="input-term" name="term" />
<p>{{ msg }}</p>
<input type="submit" class="input-submit button small success" value="{{ "goods.button.search"|trans }}" />
</fieldset>
</form>
</div>
У меня проблема с путями - потому что
затем я получаю уродливые URL-адреса, подобные этим:
- http://localhost:8000/lv/search?term=productName
- http://localhost:8000/lv/search/productName?term=orherProductName
Я подозреваю, что это может быть проблема с перезаписью URL или с маршрутизацией.
Мне всегда нужны красивые URL-адреса — не только при ручном вводе URL-адреса, но и при использовании формы для поиска продуктов.
Вот соответствующий код из контроллера поиска:
// start of function: searchAction
// getting GET parameter
$term = $request->get('term');
// end of function: searchAction
// rendering template with additional parameters
return $this->render('search/search.html.twig', array(
'search_items' => $search_items,
'msg' => '',
'term' => $term
));
Вот моя маршрутизация:
goods_search_show:
path: /{_locale}/search-show/{id}/{term}
defaults: { _controller: 'AppBundle:Search:searchShow', id: 1, term: '' }
requirements:
_locale: lv|en|ru
id: \d+
goods_search_no_term:
path: /{_locale}/search
defaults: { _controller: 'AppBundle:Search:search' }
requirements:
_locale: lv|en|ru
goods_search:
path: /{_locale}/search/{term}
defaults: { _controller: 'AppBundle:Search:search', term: '' }
requirements:
_locale: lv|en|ru
Пожалуйста, порекомендуйте. Спасибо за ваше время и знания.
ОБНОВЛЕНИЕ 1:
Мне нужно передать параметры GET, потому что у меня есть две страницы: [1] search
и [2] searchShow
(которые показывают подробный вид только одного элемента), и на этой странице есть ссылка на страницу [1], для которой нужен «термин». параметр для отображения поиска с теми же параметрами
Пример:
- На странице поиска [1], когда я нажимаю кнопку отправки, после ввода поискового запроса я получаю URL-адрес вида
http://localhost:8000/en/search?term=productName
На той же странице со списком результатов поиска есть несколько ссылок на страницу с подробностями [2]. Ссылки сделаны с помощью функции
path()
<li><a class="button secondary small" href="{{ path('goods_search_show', {'id': search_item.id, 'term': term}) }}">{{ "goods.button.view"|trans }}</a></li>
и выдает URL типа
http://localhost:8000/en/search-show/162/productName
на этой странице [2] мне нужно создать ссылку на страницу поиска [1] с параметром поиска
term
, который передается по ссылке со страницы поиска [1]. Для этого я снова использую функциюpath()
<li><a class="button secondary small" href="{{ path('goods_search', app.request.get('_route_params')|merge({'term': term})) }}">{{ "goods.button.backToList"|trans }}</a></li>
и получить URL вида
http://localhost:8000/en/search/productName
Теперь - по этой ссылке я возвращаюсь на страницу поиска [1] с отображением предыдущих результатов поиска.
Затем, когда я пробую другой поисковый запрос и нажимаю кнопку отправки, я получаю сгенерированный URL-адрес [A] вместо [B] или [C]
[A] http://localhost:8000/en/search/productName?term=anotherProductName [B] http://localhost:8000/en/search/anotherProductName [C] http://localhost:8000/en/search?term=anotherProductName
Как видно из роутинга - маршрут идет на
goods_search
. Поиск выполняется дляproductName
, ноanotherProductName
полностью игнорируется (на самом делеterm
является частью URL дважды).
Я чувствую, что должно быть лучшее решение, чем использование POST или передача term
в сеансе. Возможно, некоторые дополнительные параметры для файла .htaccess
для сервера Apache могли бы исправить плохой URL-адрес, чтобы он стал хорошим.
ОБНОВЛЕНИЕ 2:
Я последовал совету Элвина Банка и реализовал форму и обновил шаблон, чтобы использовать виджеты формы вместо основного HTML.
К сожалению, когда я нажимаю поиск вместо красивого URL, я получаю этот
`http://localhost:8000/ru/search?term=productName&submit=&_token=IvGAvN-nCR40-PKm--rA92AzGXTbI94y2rDCPZxa5D0`
и когда я меняю термин на otherProductName, я получаю
`http://localhost:8000/ru/search/productName?term=otherProductName&submit=&_token=IvGAvN-nCR40-PKm--rA92AzGXTbI94y2rDCPZxa5D0`
Таким образом, проблема остается прежней — это означает, что term
является частью URL-адреса дважды.
Так что, может быть, этот вопрос действительно связан с маршрутизацией или проблемой перезаписи URL? (Маршрутизация, которую я использую, упоминается в вопросе, а файл .htaccess
по умолчанию поставляется с Symfony3).
Моя форма
{{ form_start(form, {'attr': {'id': 'search-form'}, 'action': path('goods_search', {'_locale': lang, 'term': term}), 'method': 'GET'}) }}
<fieldset>
{{ form_row(form.term, {'name': term, 'attr': {'class': 'input-term'}}) }}
{{ form_row(form.submit, {'attr': {'class': 'input-submit small success'}}) }}
</fieldset>
{{ form_end(form) }}
Это тип элемента
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class ItemType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('term', TextType::class, array('mapped' => false, 'label' => false))
->add('submit', SubmitType::class, array('label' => 'Test label for SUBMIT button'))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Item',
));
}
public function getBlockPrefix()
{
return null;
}
}
Вот как я создаю форму в SearchController
$item = new Item();
$form = $this->createForm(ItemType::class, $item);
return $this->render('search/search_show.html.twig', array('term' => $term, 'form' => $form->createView()));
ОБНОВЛЕНИЕ 3:
Нашел пару обходных путей для моей проблемы, после применения оба сайта работают как положено.
ВРЕМЕННОЕ РЕШЕНИЕ 1
Простое опускание атрибута действия формы заставляет URL-адрес работать и перезаписывать term
в URL-адресе вместо того, чтобы отображать его дважды.
моя форма сейчас
{{ form_start(form, {'attr': {'id': 'search-form'}, 'method': 'GET'}) }}
<fieldset>
{{ form_row(form.term, {'name': term, 'attr': {'class': 'input-term'}}) }}
{{ form_row(form.submit, {'attr': {'class': 'input-submit small success'}}) }}
</fieldset>
{{ form_end(form) }}
ВРЕМЕННОЕ РЕШЕНИЕ 2
На второй странице есть ссылка на страницу поиска с term
в URL-адресе, например search?term=productName
.
Итак, во втором шаблоне страницы поиска я создаю собственный уродливый URL с помощью этого кода:
{% set link_back = path('goods_search') ~ '?term=' ~ term %}
<li><a href="{{ link_back }}">link back to main search page</a></li>
вместо объединения term
с параметрами маршрута
{% set link_back = path('goods_search', app.request.get('_route_params')|merge({'term': term})) %}
<li><a href="{{ link_back }}">link back to main search page</a></li>