Грозни 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="/bg{{ 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="/bg{{ 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) }}

Това е ItemType

<?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="/bg{{ 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="/bg{{ 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", но ще бъде действителният идентификатор и термин, предадени от шаблона на twig.

person Alvin Bunk    schedule 28.05.2016
comment
Приех съвета ви (вижте Актуализация 2 на въпроса), за съжаление резултатът все още е същият - което означава, че term е част от URL адреса два пъти. - person Rikijs; 29.05.2016