Уродливые пути URL-адресов Symfony3 после отправки (перезапись URL-адресов или маршрутизация)

Я использую:

  • 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-адреса, подобные этим:

Я подозреваю, что это может быть проблема с перезаписью 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>

person Rikijs    schedule 27.05.2016    source источник


Ответы (2)


Это нормально иметь такой URL-адрес с использованием метода GET, попробуйте использовать POST.

Но лучше всего было бы использовать Ajax.

person Kvn91    schedule 27.05.2016
comment
Мне нужно передать параметры GET, потому что у меня есть две страницы: [1] search и [2] searchShow (показывает подробное представление только об одном элементе), и на этой странице есть ссылка на страницу [1], для которой нужен параметр термина в чтобы отобразить поиск с одинаковыми параметрами. - person Rikijs; 28.05.2016
comment
может быть, вы можете передать эти параметры с помощью сеанса? Так или иначе - если вы используете метод get, ваш URL будет неверным - person Michał G; 28.05.2016
comment
Ничто здесь не мешает вам использовать метод POST для получения параметров поиска, а затем отображать ваше searchShow с помощью кнопки «Назад», которая перенаправляет на ваше предыдущее представление, передавая ваш термин в качестве параметра. - person Kvn91; 28.05.2016
comment
Я обновил свой вопрос, чтобы проиллюстрировать проблему. - person Rikijs; 28.05.2016

Вы можете сделать что-то подобное в своем шаблоне ветки:

{{ form_start(form, 
    {'action': path('/en/search-show',
        {'id':search_items.getID,
        'term':term}),
    'method': 'GET'}) }}

Затем мне нравится использовать аннотации в моем контроллере (вместо файла YAML) и делать что-то вроде этого для обработки параметров:

/**
 * @Route("/search-show/{id}/{term}",
 *  defaults={"id" = 0,"term" = 0},
 *  name="submitPetHasProgram")
 */
public function searchShowAction($id, $term, Request $request){
...

Тогда URL будет выглядеть так: http://localhost:8000/lv/search/someId/someTerm< /а>

Я показываю «someId» и «someTerm», но это будут фактические идентификатор и термин, переданные из шаблона ветки.

person Alvin Bunk    schedule 28.05.2016
comment
Я последовал вашему совету (см. Обновление 2 вопроса), к сожалению, результат все тот же - это означает, что term дважды является частью URL-адреса. - person Rikijs; 29.05.2016