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

だから、私の質問:

  • フィルター コールバック内からモデルのプロパティ (フィルター処理されているもの以外) にアクセスすることは可能ですか? (これまでのところ、私のテストでは、いいえ、またはせいぜい、信頼できないことが示唆されているようです)
  • さらに重要なことに、一意性テストを組み込むにはどうすればよいですか? つまり、エイリアスを自動生成した後、モデルの 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 に答える