find時のオプション指定で、任意のフィールドだけを除外したい時ってのが結構ありますよね?ないですか?私はよくあるのですが、それを簡単にすまそうといつも似たような処理をちょこちょこ書いてるのでここにメモっておきます。

どんな仕様にしたいかというと、

$exFields = array('created', 'modified'); // ほとんどの場合、これが無駄だったりする。かといってテーブルには残したい。
$results = $this->Record->find('first', compact('exFields'));

という具合に、 ‘exFields’ というキーで除外(exclude)したいカラムを配列で指定したらそれ以外のカラムが全て取得されるという振る舞いです。

AppModel::find をオーバーライドします。

/**
 * PHP>=5.3
 */
class AppModel extends Model
{

    public function find($type = 'first', $options = array())
    {
        if (isset($options['exFields'])) {
            if (isset($options['fields'])) {
                $fields = $options['fields'];
            } else {
                $schema = $this->schema();
                $fields = array_keys($schema);
            }
            $options['fields'] = array_filter(
                $fields,
                function ($var) use ($options) {
                    return ! in_array($var, $options['exFields']);
                }
            );
            unset($options['exFields']);
        }
        return parent::find($type, $options);
    }

}

一応、’fields’ でカラムを指定した場合にもそこから除外するようにしています。まぁ、無いだろうけど。

場合によってはフィールドを取得する部分だけを抜き出したほうが便利かもしれませんね。

/**
 * PHP >= 5.3 Because it uses closure.
 * It returns a list of fields excluded any keys.
 * 
 * @param array any fields which you would like to exclude
 * @return array
 */
    public function exFields($excludes = array('created', 'modified'))
    {
        if (!is_array($excludes)) {
            $excludes = (array)$excludes;
        }
        $fields = array_keys($this->schema());
        $fields = array_filter(
            $fields,
            function ($var) use ($excludes) {
                return ! in_array($var, $excludes);
            }
        );
        return $fields;
    }

以上