xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Программная реализация ЧПУ

Опубликовано в

Задача — из адреса в формате /catalog/notebooks?price_from=xxx&price_to=yyy, в котором /catalog/notebooks это синоним термина, а ?price_from=xxx&price_to=yyy динамические параметры, сделать человекопонятный адрес в формате /catalog/notebooks/price-xxx-yyy.

Теория есть у niklan'a, поэтому сразу к коду.

Для решения надо создать сервис с двумя методами:
processOutbound() — изменяет исходящие адреса в новый формат
processInbound() — изменяет входящие адреса из нового формата в старый

src/ModulenamePathProcessor.php:

class ModulenamePathProcessor implements InboundPathProcessorInterface, OutboundPathProcessorInterface {
 
  /**
   * {@inheritdoc}
   */
  public function processInbound($path, Request $request) {
    // Process path in "/catalog/foo/bar/price-123-456" format
    if (strpos($path, '/catalog/') === 0 && preg_match('/\/price-([^\/]+)$/', $path, $matches)) {
      // Delete custom argument from path
      $path = str_replace($matches[0], '', $path);
 
      // Move argument to $_GET
      $price = explode('-', $matches[1]);
      $request->query->set('price_from', $price[0]);
      $request->query->set('price_to', $price[1]);
    }
 
    return $path;
  }
 
  /**
   * {@inheritdoc}
   */
  public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
    // Process path in "/catalog/foo/bar?price_from=123&price_to=456" format
    if (strpos($path, '/catalog/') === 0 && isset($options['query']['price_from']) && isset($options['query']['price_to'])) {
      // Move query params to path
      $path .= '/price-' . $options['query']['price_from'] . '-' . $options['query']['price_to'];
 
      // Delete query params
      unset($options['query']['price_from']);
      unset($options['query']['price_to']);
    }
 
    return $path;
  }
 
}

modulename.services.yml:

services:
  modulename.path_processor:
    class: Drupal\modulename\ModulenamePathProcessor
    tags:
      - { name: path_processor_inbound, priority: 200 } # Run before \Drupal\Core\PathProcessor\PathProcessorAlias::processInbound()
      - { name: path_processor_outbound, priority: 200 } # Run after \Drupal\Core\PathProcessor\PathProcessorAlias::processOutbound()

Замечания:
— метод processInbound() надо использовать с осторожностью, потому что он вызывается для всех адресов на странице, а это несколько десятков, а то и сотен раз на каждый запрос.
— результат processInbound() кэшируется, поэтому после изменения метода надо очищать кэш.

По аналогии можно сделать ЧПУ любой сложности.

Написанное актуально для Drupal 8
Похожие записи

Комментарии RSS

if (\strpos($path, '/catalog/') === 0 && \preg_match('/(.*)\/price\-(\d+)\-(\d+)$/', $path, $matches)) {
    list(, $path, $price_from, $price_to) = $matches;
    $request->query->set('price_from', $price_from);
    $request->query->set('price_to', $price_to);
}
unset($options['query']['price_from'], $options['query']['price_to']);
isset($options['query']['price_from'], $options['query']['price_to'])

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании