Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Symfony: вопрос о маршрутизации и пробках

Автор вопроса: ziiwebОтветов: 2

Чтобы не отображать идентификаторы участников моей социальной сети в URL-адресе, я создал этот маршрут:

perfil_miembro:
  url: /miembros/:nombre_apellidos
  class: sfDoctrineRoute
  options: { model: Usuario, type: object}
  param: { module: miembros, action: show}

И добавил эту строку в действие show:

$this->usuario = $this->getRoute()->getObject();

Это работает нормально: когда я нажимаю на их имена, отображается соответствующий профиль, а URL-адрес имеет следующий тип:

frontend_dev.php/miembros/Мария+де+Мигель+Альварадо

Теперь я хотел бы указать имена в URL-адресе, поэтому я изменил маршрут следующим образом:

perfil_miembro:
  url: /miembros/:nombre_apellidos_slug
  class: sfDoctrineRoute
  options: { model: Usuario, type: object}
  param: { module: miembros, action: show}

И я создал эти методы:

public function getNombreApellidosSlug()
{

     return Tirengarfio::slugify($this->getNombreApellidos());
}

class Tirengarfio
{
  static public function slugify($text)
  {

    // replace all non letters or digits by -
    $text = preg_replace('/\W+/', '-', $text);

    // trim and lowercase
    $text = strtolower(trim($text, '-'));

    return $text;
  }
}

Теперь, когда я нажимаю на имя участника, отображается этот URL:

Но он всегда показывает профиль первого члена, который у меня есть в файле приспособлений.

Как заставить его работать?

Ubuntu 8.04 - Symfony 1.3.

routingsymfony1

Ответы

Ответ 1 · рейтинг 1 · Maerlyn

Поле slug должно быть реальным столбцом, а не виртуальным, который вы создали.
При доступе к URL-адресу доктрина ищет один объект, соответствующий полям, найденным в URL-адресе. В вашем случае это означает отсутствие полей. , поэтому вы видите самую первую запись в своей таблице. Регистратор запросов должен показать что-то вроде select * from tablename limit 1;.

Примечание относительно вашего URL: вы уверены, что не будет нескольких людей с одинаковым именем? Если произойдет такая коллизия, никто не сможет увидеть страницу 2-го, 3-го и т.д. человека. Я бы включил идентификатор в URL-адрес в виде /miembros/:id/:slug, чтобы он оставался удобочитаемым для человека и, конечно же, не сталкивался.

ОБНОВЛЕНИЕ
В первом комментарии @Raise предлагает использовать соленый хэш идентификатора вместо самого идентификатора. Это лучше, чем моя первоначальная идея включения идентификатора.
Плагин sfDoctrineGuardPlugin создает новую соль для каждого пользователя, сохраняет ее и использует для установки/проверки пароля. Вам понадобятся новые поля в таблице пользователей для хэша (соль не нужно хранить, идентификатор не изменится), и ваш URL-адрес будет выглядеть как /miembros/:hash/:slug.

Ответ 2 · рейтинг 1 · nacmartin

Вы можете использовать эти параметры маршрутизации: options: { model: Usuario, type: object, method: getObjectBySlug }, но вам нужен метод getObjectBySlug(), который извлекает ваш объект с учетом слага. Теперь у вас есть getNombreApellidosSlug(), который делает прямо противоположное. Проблема в том, что обычно невозможно узнать, соответствует ли слаг "maria-martinez" пользователю "Maria Martinez", "Maria Martínez", "MaRiA MaRtInEz" или "Maria Martíñez", так что это проблема. Вы можете решить эту проблему, имея столбец "slug".

Мой совет - использовать Sluggable поведение Doctrine, который отвечает за краткий столбец.

Я использую его в этом любимом проекте именно для этого. Использовать его довольно просто:

Сначала вы активируете его в схеме:

actAs:
  Timestampable: ~
  Sluggable:
    fields: [name]
    indexName: name_slug
    canUpdate: true
    unique: true

И он создаст и будет поддерживать столбец с именем "slug".

Затем используйте его в маршрутизации. В моем случае это:

list_permalink:
  url: /:slug
  class: sfDoctrineRoute
  options: { model: SkinnyList, type: object, method: getObjectBySlug }
  param: { module: list, action: show }
  requirements: { sf_method: get }

Вам понадобится метод getObjectBySlug в lib/ модель/доктрина/yourmodelTable.class.php:

  public function getObjectBySlug($options = array())
  {
    if (!isset($options['slug']))
    {
      throw new InvalidArgumentException('The slug is required in the options');
    }
    $q = $this->createQuery('td')->where('td.slug = ?', $options['slug']) ;

    return $q->fetchOne();
  }

В действии вы можете получить объект, выполнив:

$this->list = $this->getRoute()->getObject();

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы