2

我有多个我希望通过人类可读的 URL 访问的对象,因此我正在为所有数据库记录生成别名(例如 blog.com/this-is-an-alias/)。

自动生成这些的最佳实践是什么?

我目前正在挂钩模型的 'values()' 方法并在其中生成一个新别名(基于所需的 'name' 字段),但我不禁觉得这可以更优雅地使用,比如 Kohana 构建- 过滤器。

这是精简模型:

class Model_Category extends ORM {
    // relevant rules:
    public function rules(){
            return array(
            'alias' => array(
                array('max_length', array(':value', 63)),
                array(array($this, 'unique'), array(':field', ':value')),
            ),
            'name' => array(
                array('max_length', array(':value', 63)),
            ),
            // (...)
        );
    }

    // overrides default method:
    public function values(array $values, array $expected = NULL){
        if(!$this->_loaded){
            if($values['name'] && !$values['alias'])
                $values['alias'] = Helper_Form::to_alias($values['name']);
        }

        return parent::values($values, $expected);
    }
}

仅供参考, to_alias 函数看起来像这样:

return strtolower(substr(trim(preg_replace('/[^0-9a-zA-Z]+/','-',$str),'-'),0,63));

所以,我的问题:

  • 是否可以和/或建议从过滤器回调中访问模型的属性(被过滤的属性除外)? (到目前为止,我的测试似乎表明没有,或者充其量是不可靠的)
  • 更重要的是,如何构建唯一性测试?即,在自动生成别名后,如何确定 slug 尚未在使用中而不抛出模型的 rules() 异常?
4

1 回答 1

5

我会使用您提到的过滤器进行自动生成。以下是我这样做的想法。对于过滤器功能,您可以传递一些特定的参数,例如:model, :value:field在这种情况下,我将使用:model它来访问当前模型的属性。

class Model_Category extends ORM {

    public function filters()
    {
        return array(
            'slug' => array(
                array(array($this, 'create_slug'), array(':model')),
            ),
        );
    }

    public function create_slug($model)
    {
        $model = ($model instanceof ORM) ? $model : $this;

        $number = 1;

        $slug = UTF8::transliterate_to_ascii($model->name);
        $slug = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $slug);
        $slug = UTF8::strtolower(trim($slug, '-'));
        $slug = preg_replace("/[\/_|+ -]+/", '-', $slug);

        while ( ! $this->unique_slug($slug))
        {
            if ( ! preg_match('/\d+$/', $slug))
            {
                $slug .= '-'.$number;
            }
            $slug = preg_replace('/\d+$/', $number++, $slug);
        }

        return $slug;
    }

    public function unique_slug($slug)
    {
        return (bool) DB::select(array('COUNT("*")', 'total_count'))
            ->from($this->_table_name)
            ->where('slug', '=', $slug)
            ->where($this->_primary_key, '!=', $this->pk())
            ->execute($this->_db)
            ->get('total_count');
    }

}

上面的例子可能功能不全,但我希望你能明白。

于 2012-08-10T19:03:18.300 回答