KO3:使用ORM过滤器自动生成唯一的别名/ slug?

Mur*_*ith 2 php orm unique filter kohana

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

自动生成这些的最佳做法是什么?

我现在挂钩模型的'values()'方法并在那里产生一个新的别名(基于所需的'name'字段),但我不禁觉得这可以更优雅地使用,例如,Kohana的内置-in过滤器.

这是精简模型:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

所以,我的问题:

  • 是否有可能和/或建议从过滤器回调中访问模型的属性 - 除了被过滤的属性? (到目前为止,我的测试似乎表明没有,或者说,最好不可靠)
  • 更重要的是,我如何构建唯一性测试?也就是说,在自动生成别名之后,如何在不抛出模型的rules()异常的情况下确定slug还没有被使用?

Kar*_*yst 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');
    }

}
Run Code Online (Sandbox Code Playgroud)

上面的例子可能没有完全的功能,但我希望你能得到这个想法.