Чтобы не отображать идентификаторы участников моей социальной сети в 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.
Ответ 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();