【问题标题】:Symfony: question about routing and sluggingSymfony:关于路由和 slugging 的问题
【发布时间】:2011-03-15 12:00:43
【问题描述】:

为了不在 URL 中显示我的社交网络成员的 ID,我创建了这个路由:

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

并在显示动作中添加了这一行:

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

它工作正常:当我点击他们的名字时,会显示相应的个人资料,并且 URL 是这种类型:

frontend_dev.php/miembros/Maria+de+Miguel+Alvarado

现在我想在 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:

frontend_dev.php/miembros/maria-de-miguel-alvarado

但它总是显示我在夹具文件中拥有的第一个成员的个人资料。

我怎样才能让它工作?

Ubuntu 8.04 - Symfony 1.3.

【问题讨论】:

    标签: routing symfony1


    【解决方案1】:

    您可以使用路由的这些选项:options: { model: Usuario, type: object, method: getObjectBySlug },但您需要一个 getObjectBySlug() 方法,该方法在给定 slug 的情况下检索您的对象。现在你有getNombreApellidosSlug(),这正好相反。问题是,通常无法知道 slug "maria-martinez" 是否对应于用户 "Maria Martinez"、"María Martínez"、"MaRiA MaRtInEz" 或 "María MartíÑez",所以这是个问题。您可以通过“slug”列来解决它。

    我的建议是使用Sluggable behaviour of Doctrine,它负责处理 slug 列。

    我正在 this pet project 上使用它来做到这一点。使用它非常简单:

    首先,你在the schema中激活它:

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

    它会创建并维护一个名为“slug”的列。

    然后,在the routing 中使用它。在我的情况下是:

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

    您需要lib/model/doctrine/yourmodelTable.class.php 中的getObjectBySlug 方法:

      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();
    

    【讨论】:

      【解决方案2】:

      slug 字段必须是真实的列,而不是您创建的虚拟列。
      当 url 被访问时,教义正在寻找单个对象 匹配在 url 中找到的字段 - 在您的情况下,这意味着没有字段,那就是 为什么您会在表格中看到第一条记录。查询记录器 应该显示类似select * from tablename limit 1;

      关于您的网址的说明:您确定不会有多个 同名的人?如果发生这样的碰撞,没有人会 能够看到第二、第三等人的页面。我会在 url 中包含 ID,以 /miembros/:id/:slug 的形式,这样它就可以保持人类可读并且肯定不会发生冲突。

      更新
      在第一条评论中,@Raise 建议使用 ID 的加盐哈希而不是 ID 本身。这比我最初包含 ID 的想法要好。
      sfDoctrineGuardPlugin 为每个用户生成一个新的 salt,存储它,并用于设置/验证密码。您需要在 users 表中为哈希创建一个新字段(不需要存储 salt,ID 不会更改),并且您的 url 看起来像 /miembros/:hash/:slug

      【讨论】:

      • +1 建议“唯一化” URL 以避免冲突,尽管我认为 id 和 salt 的一些散列会更好 - 避免将 id 暴露给网站。 Doctrine 真的会构建这样的查询,并返回数据库中的第一行吗?如果属实,那就令人担忧了。
      • @Raise 哈希是个好主意。关于查询构建,我是推进用户,但根据症状,这是我能想象的唯一方法。我同意计数可能是为了查看记录如何匹配查询,但这不是必须的。
      • 感谢 Maerlyn,您写了“我会在 url 中包含 ID”,但这不是一个好的做法,您可以在此处看到(搜索永久链接)symfony-project.org/gentle-introduction/1_4/en/…
      • @Raise(希望你读到它)推进和教义路线都调用$variables = $this->getRealVariables(),所以他们可以简单地忽略不映射到数据库列的 url 变量。参见 sfPropelRoute 第 46 行和 sfDoctrineRoute 第 68 行(当然是 1.4 版)
      • @Maerlyn 我不完全理解这部分:您需要在您的用户表中为哈希创建一个新字段(不需要存储盐,ID 不会改变),。你能帮我多一点吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-10
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多