コアから学ぶCakeのコツ

Cake Style $options Parameter
Cake流・オプション引数の実現法:$optionsパラメータを使ったやり方

We’ve all seen functions that start out taking one parameter and then, as they grow, they end up
looking like this:

誰しも見覚えがあるでしょう。ただ一つのパラメータを取る関数として始まったのに、成長するにつれて、最終的にはこんな見た目になってしまった関数を:

function geoLocationXML($progId=null, $userId=null, $startDate=null,
                        $endDate=null, $allProgs=false, $detail=true) {
  if(!$prodId) {
    $prodId = $this->id;
  }
  if(!$userId) {
    $userId = User::get('id');
  }
  if(!$startDate) {
    $startDate = strtotime('-1 month');
  }
  if(!$endDate) {
    $endDate = time();
  }
}

Many Cake functions solve this problem by taking an $options parameter, which is a keyed array.
This allows the option list to grow without throwing the function declaration out of whack. Within
the function, defaults can be set for the various parameters. Here’s the function above rewritten
with $options support:

多くのCakeの関数は、$options パラメータ一つを取ることでこの問題を解決しています。そのパラメータは[文字列の]キーを持つ配列です。 これによって関数宣言をめちゃくちゃにしてしまうことなく、オプション[パラメータ]の一覧を増やしていくことが可能になります。 それぞれのパラメータに対するデフォルト値は、関数の中で設定することができます。 上の関数を $options [パラメータを使う方法]の助けを借りて書き直せばこうなります:

function geoLocationXML($options = array()) {
  $options = array_merge(array('prodId' => $this->id,
                               'userId' => User::get('id'),
                               'startDate' => strtotime('-1 month'),
                               'endDate' => time(),
                               'allProgs' => false,
                               'detail' => true),
                               $options);
}

This approach merges the passed $options with a default options array. The end $options
contains the values passed, plus the defaults for any key that wasn’t included. The Cake
$options approach is easier to read, shorter to code and much more extensible.

[引数として]渡された $options [配列]と、各オプションに対するデフォルト値の配列とを結合する、という段取りです。最終的な $options は[引数として]渡された値と、[引数の中には]含まれていなかったキーに対するデフォルト値とを含んでいます。Cake のこの $options [によるオプション引数の実現方法]は、[PHPの標準的な方法よりも]読むに易しく書くに短く、ずっと拡張性に富んでいます。

Handling Data Arrays with a Single Record or an Array of Records
単独のレコードか複数レコードの配列か、いずれかをデータとして持つ配列を処理する

There are times when it is useful to have a function that can handle a single data record or an
array of records. Unfortunately, since $data is an array in both cases, it can be difficult to tell
which type it is. The trick is with the type of array. If it is just a single record, it is a keyed array -
something like:

単独のレコードでも複数レコードの配列でも処理できるような関数があると便利なことがあります。[その関数がとる引数を仮に $data とします。]残念ながらいずれの場合も $data は配列なので、その配列がどちらの種類のものなのか見定めるのは困難です。ここ[で紹介する]コツはこの配列の種類に関するものです。もし $data が単独のレコードであれば、$data は[文字列の]キーを持つ配列です。このように:

Array
  (
  [Post] => Array
    (
      [id] => 1
      [title] => Post 1
      [body] => Lorem ipsum dolor sit amet...
      [created] => 2009-01-23 16:53:42
      [updated] => 2009-02-03 12:07:48
    )
  )

In the case where there are multiple records, you will have an indexed array:

複数のレコードが[データの中に]存在する場合は、数値の添字を持つ配列になっているでしょう:

Array
(
  [0] => Array
    (
      [Post] => Array
        (
          [id] => 1
          [title] => Post 1
          [body] => Lorem ipsum dolor sit amet...
          [created] => 2009-01-23 16:53:42
          [updated] => 2009-02-03 12:07:48
        )
    )
 
  [1] => Array
    (
      [Post] => Array
        (
          [id] => 2
          [title] => Post Two
          [body] => Lorem ipsum dolor sit amet...
          [created] => 2009-01-24 15:53:53
          [updated] => 2009-02-03 16:13:20
        )
    )
)

The trick to telling them apart is to look at the keys. If they are all numeric, it is safe to assume
you are dealing with an array of data records. Cake provides a very simply way to do this – the
Set::numeric method.

これらを見分けるコツはキーを調べることです。もしキーが全て数値なら、扱っているのは複数レコードの配列なのだと決めてかかっても大丈夫です。 Cake はキーが全て数値であるかどうか調べるための、とても単純な方法を用意しています – Set::numeric メソッドです。

Set::numeric(array_keys($data));

Then it is simply a matter of converting that single record into an array of records (although there
is still only one entry).

よってあとは単独のレコードをレコードの配列(要素は一つしかありませんが)に変換するだけの問題になります。

if(!Set::numeric(array_keys($data)) {
  $data = array($data);
}

Your function can now handle a single record or an array of records, regardless of how that data
is passed. You just loop through $data and process each of the records.

これでデータがどのように渡されたかに関わらず、単独のレコードでも複数レコードの配列でも処理できる関数になります。 単に $data [配列]全体をループして、それぞれのレコードを処理するだけです。

foreach($data as $i => $record) {
//do stuff here
}

Leave a Reply