Displaying posts tagged with

“CakePHP”

Behavior の適用範囲を広げる $mapMethods

(CakePHP 1.2.5)
ビヘイビアに定義されたメソッドは、モデル自身のメソッドであるかのように呼び出すことができます。

class FooBehavior extends ModelBehavior {
  function foo($model){ /* ... */ }
}
 
class Bar extends AppModel {
  var $actsAs = array('Foo');
}
 
// in Controllers
$this->Bar->foo();

しかしこの方法では Dynamic Finder のように動的に名前が変化するメソッドは実装できません。

ModelBehavior クラスの $mapMethods プロパティを使用すると、この制約を乗り越えることができます。$mapMethods は配列で、次のような構造をしています:

array( '/メソッド名に対する正規表現/' => '実際に呼び出されるメソッド'  )

例えば '/^list/' => '_genericList' という設定を行った場合、listから始まる全てのメソッド呼び出しが、ビヘイビアの _genericList メソッドの呼び出しに変換されます。このとき _genericList メソッドの引数には元のメソッド名と引数が渡されます。ちょうど __call によるメソッドのオーバーロードと同じです。

この機能を活用して、あるカラムの値を配列として取得するための listColumn メソッドを作ってみます(Column はカラム名)。このメソッドは ListingBehavior に実装することにしましょう。

class ListingBehavior extends ModelBehavior {
  var $mapMethods = array('/^list[a-zA-z0-9]+$/' => '_listColumn');
 
  function _listColumn($model, $methodName, $query=array()) {
    $column = substr($methodName, 4);
    $query = am($query, array('fields' => array($model->alias.".".$column)));
    $arr = $model->find('all', $query);
    if(is_array($arr)) {
      return Set::extract("/{$model->alias}/{$column}", $arr);
    }
    return $arr;
  }
}

モデルにこのビヘイビアを組み込むと、任意のカラムに対して listXXX メソッドを呼び出すことができるようになります。

class User extends AppModel {
  var $actsAs = array('Listing');
}
 
// in Controllers
$this->User->listId();
$this->User->listUsername(array('conditions' => 'active = 1'));
$this->User->listGroup_id();

メソッド名は小文字に変換されて渡されるので(これが仕様なのかバグなのか微妙なところです)、残念ながら Inflector::underscore を使うことはできません。

key-valueストア用DataSource(CakePHP1.2)

key-valueストア用の DataSource サンプルをgithubで公開しておきます。

cakephp-key-value-source – ver.0.1

以下の説明はバージョン0.1を対象としたものです

以下のクラスが含まれています:

KeyValueSource
抽象ベースクラス。サブクラスでは最低限 get/set/del/count 4つのメソッドを実装する
JsonFileSource
jsonエンコードしてローカルファイルに保存する実装例
MemcacheSource
pecl-memcache を用いる実装例

CakePHPバージョン1.2の DataSource の仕組みはまだまだ未成熟で、あまり突っ込んだ説明は書きにくいので、詳しく知りたい方はコードを読んでください。スキーマ・レスな(スキーマの設定を DataSource側ではなく Model 側で行う)Sourceの例としては最小限の構成になっているはずです。

使用例

database.php

class DATABASE_CONFIG
{
  var $json = array('datasource' => 'json_file',
                    'root' => TMP,
                    'path' => '/json-encoded');
 
  var $memcache = array('datasource' => 'memcache',
                        'host' => 'localhost',
                        'port' => 11211,
                        'default_expire' => 3600,
                        'default_flag' => 0);
}

モデル

class Foo extends AppModel
{
  //どちらを使ったとしても、基本的な機能を使う限り、全く同じ動作になる
  var $useDbConfig = 'json';
  //var $useDbConfig = 'memcache';
 
  /*
    スキーマの設定
    id には length 必須(特に意味がなくても)
  */
  var $_schema = array('id' => array('type' => 'integer', 'length' => 4),
                       'bar_count' => array('type' => 'integer'),
                       'baz_count' => array('type' => 'integer')
                       /* ... */);
}

コントローラ

//保存するデータの構造などはDBを使う場合と同じ
$data = array('Foo' => array('id' => 1,
                             'bar_count' => 1000,
                             /* ... */));
 
//保存
$this->Foo->save($data);
 
//読み出し
$data = $this->Foo->read(null, 1);
 
//戻り値の構造もDBを使う場合と同じ
$barCount = $data['Foo']['bar_count'];

この程度の使い方だと cache と大して変わらないので、バックエンド固有の機能も少しだけ実装してみました。JsonFileSource は decode オプションを指定することでJSONからのデコード方法を指定できます。false を指定すればJSON(文字列)のまま取り出すこともできます。

//JSONのオブジェクトをPHPのオブジェクトとしてデコード(デフォルトでは連想配列)
$obj = $this->Foo->find('first',
                        array('conditions' => array('Foo.id' => 1),
                              'decode' => 'object'));
$bar = $obj['Foo']->bar_count;
 
//JSON文字列のまま取り出す
$data = $this->Foo->find('first',
                         array('conditions' => array('Foo.id' => 1),
                               'decode' => false));
$json = $data['Foo'];

MemcacheSource はモデルの expires プロパティでデータの有効期限を設定できます。

//期限無制限に
$this->Foo->expire = 0;
$this->Foo->save($data);

参考:

簡単DataSourceの作り方
countまわりの実装など参考にしました。こちらではbakeで動かすことが主眼となっていますが、私のサンプルはbakeでは動かないはずです(bake自体使わないので)

CakePHP 1.2 prefix付きURL生成時の注意点

※CakePHP バージョン 1.2限定の話題です。

Router::url によるURLの生成時に、prefix パラメータは考慮されない。ありがちな例として携帯用URLを作るために次のような route を追加した場合、

Router::connect('/m/:controller/:action/*',
                array('prefix' => 'mobile'));

URL生成時には prefix パラメータの有無によらず、この route がマッチする。各種ヘルパー($html->link | $paginator | $form->create)でPC用のURLに意図しないプレフィクスが付いてしまう、という問題の原因はこれである。

// どちらも /m/foo/bar になってしまう!
$url->link('link', array('controller' => 'foo', 'action' => 'bar', 'prefix' => 'mobile'));
$url->link('link', array('controller' => 'foo', 'action' => 'bar'));

この問題を回避するためのイディオムとして、prefix パラメータの他に [prefix名] => true というパラメータを設定する。

Router::connect('/m/:controller/:action/*',
                array('prefix' => 'mobile',
                      'mobile' => true));

URL生成時にはこちらのパラメータを使う。

// こちらは /m/foo/bar
$url->link('link', array('controller' => 'foo', 'action' => 'bar', 'mobile' => true));
 
// こちらは /foo/bar
$url->link('link', array('controller' => 'foo', 'action' => 'bar'));

参考:

3.4.5.5 プリフィックスルーティング(Prefix Routing) :: The Cookbook
現在は正しいコード例が示されている。
“Prefix利用時のPaginatorHelperが吐くURLが正しく表示されない” フォーラム – CakePHP Users in Japan:
cakephp.jpのフォーラムにて。検索パラメータが引き継げないのはおそらく connectNamed が設定されていないから?

なお Routing.admin によるルーティングは純粋なプレフィクスルーティングではなく、Router の中で特別扱いされているのでこの問題は生じない。また CakePHP 1.3 ではプレフィクスルーティングの機能は大きく拡張されるため、最終的にどのようになるのかは分からない(コードを斜め読みした限りでは、個々の route に個別に設定する必要は無くなり、Configure::write(‘Routing.prefixes’, array(…)); で一括指定できるようになるらしい。ただ少なくとも 1.3.0-alpha においては、1.2同様の prefix も使えるようだ)。

追記:

[prefix名] => true を設定してもうまくプレフィクスが付かない場合は、route 側にパラメータが足りない可能性が高い。最もありがちなのは名前付きパラメータを使用する場合。

// こんなURLを作りたいが => /m/foo/bar/type:99 
// こうなってしまう => /foo/bar/mobile:1/type:99
$html->link('link', array('controller' => 'foo', 'action' => 'bar', 'mobile' => true, 'type' => 99));

こういうときは Router::connectNamed を使って routes.php の中で宣言しておく必要がある。

Router::connectNamed(array('type'));

Router::connectNamed についての説明はAPIドキュメントが最も詳しい。ちなみに page や sort といった paginator 関連のパラメータはデフォルトで設定されるので改めて設定する必要はない(だからこそ気が付きにくいとも言えるが)。

続・QdmailをCakePHPで使う

以前gistで公開したQdmailerコンポーネントですが、その後もいろいろ手を加えたい部分が出てきたので、正式にgithubにリポジトリを作成しました。

http://github.com/tkyk/cakephp-qdmailer

使い方はREADMEを読んでください。

本家QdmailComponentとの違いは次の通りです。[*]印はgist版からの変更点になります。

  • View クラスの読み込み方法が EmailComponent と同一になっている(そのためThemeView やプラグインが提供するViewも使用可能)
  • テンプレートファイルのエンコーディングが指定されなかった場合、自動判定するのでは無く App.encoding の値を使う
  • CakePHPのConfigure::read(‘debug’)が0のとき、デフォルトでエラーメッセージを表示しない
  • [*]Configure::writeによるグローバルな設定が可能
  • [*]実行時にis_qmailの設定が可能
  • [*]ログの保存先がデフォルトでLOGSになる(オリジナル版ではCOMPONENTS)
  • [*]Qdsmtp使用時に、qdmail.phpをvendorsディレクトリに置くことができる
  • [*]Qdsmtp使用時に、ログの保存先設定が引き継がれる
  • [*]Qdsmtp使用時に、エラーメッセージ表示可否の設定が引き継がれる

is_qmailの設定は非常に重要なので補足しておきます。Qdmailはデフォルトでは「qmailを使っているか否か」をコンストラクタの中で自動判定しようとします。このときシェル経由(system関数)でsendmailコマンドを(qmailでしか使えないオプションを指定して)実行するため、相応の負荷がかかる上に、qmail以外のMTAを使用している場合はmaillogにエラーメッセージが記録されてしまいます。今のところ(qdmail-1.2.6b)この自動判定を実行時に止める方法はありません。そしてCakePHPのコンポーネントとして使う場合はさらに悲惨で、判定がコンストラクタで行われる以上、たとえメールを送らなくても、コンポーネントを読み込むだけで自動判定が実行されてしまいます。

ということで、is_qmailの設定は絶対に明示的に行ってください。具体的にはbootstrap.phpの中でConfigure::writeを使って行います。

Configure::write('Qdmailer',
                 array('is_qmail' => false,
                          /* ... その他の設定 ... */));

なおこのis_qmailの件も含めて作者spokさんには連絡してあるので、いずれ本体側で何らかの変更が行われるかも知れません。

MarkupHelper:他のヘルパーのメソッドを連結する

MarkupHelper を更新。他のヘルパーのメソッドをチェーンして、戻り値をそのままHTMLの中に配置できるようになりました。

http://github.com/tkyk/cakephp-markup-helper

デフォルトでは HtmlHelper と FormHelper のメソッドを、それぞれ h_, f_ というプレフィクスで呼び出せます。こんな感じのコードが記述可能です。

echo $markup
->div('search')
->fieldset->legend->text('ブログ検索')->end
->f_create('BlogSearch')
->f_input('text', array('label' => false)))
->small->h_link('詳細検索はこちら', array('action' => 'search'))->end
->f_end('検索')
->enddiv;

その他のヘルパーを使用する場合はコントローラの $helpers でオプションとして指定します。

var $helpers = array('Markup' =>
                     array('helpers' => array('My', 'Javascript' => 'js')));

標準でヘルパー名がそのままプレフィクスとなりますが、独自のプレフィクスも指定可能です。上の例では MyHelper のメソッドを My_methodName という名前で、JavascriptHelper のメソッドを js_methodName もしくは javascript_methodName という名前で呼び出すことができます。

注意:他のヘルパーからの戻り値は全て html メソッドで連結されます。XSSが起こらないように気をつけてください。

Super Awesome Advanced CakePHP Tips 訳と註5

コアから学ぶCakeのコツ

この章は本当に日本語に訳しにくいです。$options という”英単語”をどう解釈するか、そしてカタカナ語をどこまで許容するかがとても悩ましく、ごまかしも増えてしまいました。内容は別に難しくはないのですが。

Cake Tricks from The Core 註

Cake Tricks from The Core
ここの訳は完全にごまかし。直訳して「コアから、Cakeのコツ」ではあまりにも意味が分からないので作文せざるを得なかった。すいません。原題に「学ぶ」なんて語は無いしそんなニュアンスも無い。ここの from は日本語だと多分「〜発」というのに近い。「コア発のCakeテクニック」みたいなのが良いかも知れない。
Cake Style $options Parameter
このタイトルはそのまま訳すのは不可能。すなわち $options は英語の「option」であると同時に、プログラミング上のテクニック(この節で説明する、$optionsパラメータを使った方法)を指す一種の固有名詞。さらにこの場合の英語の「option」は、自由選択とか自由入力とかいった意味なのだが、日本語プログラミング用語としては片仮名で「オプション」としか言い様がない。オプション引数、つまり関数呼び出し時に値を与えても与えなくても良い、「オプションの」引数を扱うための $options パラメータを使ったCake流のやり方、ということ。
以下いちいち註では書かないが、この節の中の $options という表記の部分には、いずれも同じ問題がある。そのせいで日本語としては非常に煩雑になってしまった。
We’ve all seen functions that …
この章も他の章と同じく、冒頭の文はちょっとだけ格好をつけた感じの文になっている。訳文も雰囲気重視で作っておいた。
a keyed array
「連想配列」と言ってしまいたくなるのだが、連想配列は普通 associative array の訳語だから、ここで使うのは躊躇われる。それにそもそもPHPには「連想配列」と「普通の配列」という区別は無い。同じ一つのデータ構造を使い方によって呼び分けているだけである。次節で分かる通り、著者はそのPHPの特殊事情について自覚的かつ誠実なので、ここでも敢えて keyed という、配列の「使い方」を示す言い回しをしているのだと思われる。「(文字列の)キーを付けられた配列」。
out of whack
「狂った」とか「めちゃくちゃな」といった意味の決まり文句らしい。
This approach
片仮名で「アプローチ」でも大体意味は通じると思うが、「このアプローチではデフォルトのオプションとマージします」では、英語を日本語に訳しているんだか単に片仮名に書き直しているんだか分からない。approach は元々「近付く」という語なので、ここでは「オプション引数を実現する」という目標に対する近付き方、段取りということ。
The end $options
ここでの $options はコード内の変数名(25行目、代入式の左辺)をも指している。
easier to read, shorter to code
語呂の良い文なので、日本語もちょっと工夫した。この code は「コードを書く」という動詞だから、まあ「書く」で通じるだろう。
Handling Data Arrays with a Single Record or an Array of Records
文法的には “a Single Record” or “an Array of Records” 全体に with がかかる形式で、with は漠然と「〜を持って」「〜を備えて」といった意味だと思われる。
since $data is …
いきなり $data という変数名が出てくるが、この節では関数を作ることを想定しているので、これはその関数がとる引数の名前。最後の段落でも出てくる。
telling them apart
tell 〜 apart で「見分ける」。
to do this
形式的にはこの to do this は「to look at the keys」に対応するのだと思うが、実質的にはその次の文の内容「If they are all numeric」も含むと考えて良いだろう。

QdmailをCakePHPで使う

標準で QdmailComponent が付属しているのですが、Cake 1.2 でそのまま使うには少々難があるので、継承して一部メソッドを書き換えたものを gist で公開しておきます。名前は QdmailerComponent です(CakePHP 1.2専用、qdmail.1.2.6b)。

2009-11-15 更新: さらに改良したものをリポジトリで公開しました。続・QdmailをCakePHPで使うを参照してください。

使い方

qdmail.php は verdors ディレクトリに置いて、上のコードを qdmailer.php として components ディレクトリに置いてください。あとは標準の QdmailComponent と同じです。

$this->Qdmailer->to('address@example.com', '日本語名');
$this->Qdmailer->subject('Qdmailerテスト');
$this->Qdmailer->from('from@example.com' , '配信元日本語名' );
$this->Qdmailer->cakeText('テンプレート使用テスト', 'test_template');
$this->Qdmailer->send();

主な変更点は

  • $is_qmail を明示的に設定(本当は Component のオプションで指定できるようにすべきだが)
  • View クラスの読み込み方法を EmailComponent と同一にした(ThemeView なども使用可能になった)
  • テンプレートファイルのエンコーディングが指定されなかった場合、自動判定するのでは無く App.encoding の値を使うようにした

半角カナを全角に変更

ちょっと反則気味ですがレイアウトファイル内で変換するのが一番楽な気がします。

<?php echo mb_convert_kana($content_for_layout, "KV"); ?>

検索条件をページングで引き継ぐプラグイン

このページの内容は古いバージョン(CakePHP1.2)向けのものです。より新しい情報を参照してください。古いバージョンのコードが必要な場合は1.2ブランチから取得してください。


CakePHP 1.2標準の paginate 機能で、複雑な検索条件をページング用リンクに引き継げるようにするためのプラグイン SearchPagination を公開しました。

http://github.com/tkyk/cakephp-search-pagination/tree/1.2

PHP 5.2.xでしかテストしていませんが、それ以前のバージョンでも動くはずのコードなので、もし動かなかったら教えてください。

使い方

検索専用のモデルを作る方法と、作らない方法(他モデルを流用する方法)とがあります。ある程度以上複雑な検索を行う場合は専用モデルを作る方法をおすすめします。ここでは最初に専用モデルを作る方法から説明して、作らない方法については最後の節で説明します。

検索専用のモデルを作る

複雑な検索を行うための肝は専用のモデルを作ることです。検索条件を組み立てるロジックをモデルの中にカプセル化してしまえば、どれだけ複雑な検索フォーム・検索条件にも対応できます。ここでは次のような検索フォームを例に説明していきます。(いろいろ省略されていますが)ブログの記事を検索すると思ってください。

記事検索

タイトル:

投稿日: 日 以降

カテゴリ:

この検索フォームに対応するモデルは概ね次のようになります。buildQuery が検索条件を組み立てるためのメソッドです(記事に対応するモデルは Entry とします)。

<?php
class EntrySearch extends AppModel
{
  var $useTable = false;
  var $_schema = array('title' => array('type' => 'string'),
                       'created_from' => array('type' => 'date'),
                       'category_ids' => array('type' => 'array'),
                       );
  /**
   * buildQuery メソッドの中で検索条件を組み立てます。
   * もし検索フォーム内でソート順や表示件数を指定できるようにする場合は、
   * limit や order もここで設定します。
   */
  function buildQuery()
  {
    $p = $this->data[$this->alias];
 
    $conditions = array();
    if(!empty($p['created_from'])){
      $conditions['Entry.created >= '] = $p['created_from'];
    }
    //....(省略) ...
    return array('conditions' => $conditions,
                 'joins' => $joins,
                 /* ... */);
  }
}

検索フォーム表示部分のビューは次のようになるでしょう。

echo $form->create('EntrySearch', array('action'=>'search'));
echo $form->input('title', array('label' => 'タイトル:');
echo $form->input('created_from', array('label' => '投稿日:',
                                       'after' => '以降'));
echo $form->input("category_ids", array('label' => 'カテゴリ:',
                                        'multiple' => 'checkbox',
                                        'options' => $categories));
echo $form->end('検索');

これでフォームから検索パラメータを受け取る準備ができました。

SearchPaginationコンポーネント

コントローラの中では SearchPagination コンポーネントの setup メソッドを呼び出します。第1引数は検索用モデルの名前です。ここでは EntrySearch を指定します。またオプションの第2引数として、検索フォームの初期値を与えることもできます。下のコードでは検索開始日を1ヶ月前の日付としてみました(この部分のコードは本来はモデルに置くべきかもしれません)。

<?php
class EntriesController extends AppController
{
  var $components = array('SearchPagination.SearchPagination');
 
  function search()
  {
     $oneMonthAgo = date('Y-m-d', strtotime('1 month ago'));
     $this->SearchPagination->setup('EntrySearch', array('created_from' => $oneMonthAgo));
 
     $this->paginate = $this->EntrySearch->buildQuery();
     /*
      ... 必要ならさらに $this->paginate を加工する ...
     */
 
     $this->set('entries', $this->paginate('Entry'));
     $this->set('categories', $this->Entry->Category->find('list'));
  }
}

setup メソッドは自動的に検索用モデルを読み込んで、モデルの set メソッドで値を設定します。だからあとは buildQuery メソッドを呼んで検索条件を組み立て、paginate を実行するだけです。

ビュー

ビューでは何も特別なことはありません。PaginatorHelper を使って普通にページング用リンクを表示してください。sort メソッドも使用可能です。

echo $paginator->numbers(array('modulus' => 12));
 
foreach($entries as $entry) {
  //検索結果の表示
}

生成されたリンクの中には、次のような形で検索条件が含まれているでしょう。

/entries/search/page:2?title=XXXX&created_from=2009-11-01&category_ids[0]=2&category_ids[1]=4

リンクをクリックすれば、これらのパラメータが検索条件として引き継がれます。同時にコントローラの $data プロパティにも引き継がれるため、FormHelper で作った検索フォームにも入力値が自動的に設定されます。

GETメソッドで検索したい

以上でページング用リンクに対する検索パラメータの引き継ぎが行われるようになりました。しかし検索フォームからの最初の検索がPOSTメソッドで行われることが少し気持ち悪いかも知れません。これは date などの複雑な要素を使う場合の、FormHelper の制約です。

この制約を回避するために、SearchPagination プラグインではオマケ機能として、POST用のフォームをGETに変換するJavaScriptを用意しています。動作にはjQueryが必要ですが、他のライブラリに移植することは容易なはずです。次のように使用します。

// jQuery および search_pagination.js を読み込む
$javascript->link('jquery-1.3.2.min', false);
$javascript->link('/search_pagination/js/search_pagination', false);
 
// form に search-pagination クラスを指定する
echo $form->create('EntrySearch', array('action'=>'search', 'class'=>'search-pagination'));

専用モデルを作るほど複雑ではない場合

検索フォームも検索条件も単純で、検索専用に新たなモデルを作るほどではない場合、既存のモデルを検索用に流用することができます。例えば次のようなごくごく単純な検索フォームの場合、

値を受け取るためのモデルとして、Entry モデルをそのまま使ってしまえば良いでしょう。この場合、setup メソッドの第1引数には Entry を渡し、Entryモデルもしくはコントローラの $data プロパティから検索条件を組み立てます。

<?php
class EntriesController extends AppController
{
  var $components = array('SearchPagination.SearchPagination');
 
  function search()
  {
    $this->SearchPagination->setup('Entry');
    if(!empty($this->data['Entry']['title'])) {
      $this->paginate['conditions']
         = array('Entry.title like' => '%'.$this->data['Entry']['title'].'%');
    }
    $this->set('entries', $this->paginate('Entry'));
  }
}

ビューは専用モデルを使った場合と全く同様ですが、これくらい単純なフォームの場合は FormHelper の create メソッドで type => get を指定しても問題なく動きます。

<?php
echo $form->create('Entry', array('action'=>'search', 'type'=>'get'));
echo $form->input('title');
echo $form->end('検索');
 
echo $paginator->numbers(array('modulus' => 12));
 
foreach($entries as $etnry) {
  //...
}

Super Awesome Advanced CakePHP Tips 訳と註4

jQuery

今回は jQuery についての章です。私も以前 CakePHP のための jQuery ヘルパーを探したことがありますが、結局作者と同じく、直接 jQuery を使う方が楽だという結論に至りました。

翻訳とは関係ないのですが、最後のJavaScriptのコード例は下記のようにすべきではないかと思います。

$("#scoresUpdate").click(function() {
  $.ajax({
    url: this.href,
    success: function(html) {
      $("#divId").html(html);
    }
  });
});

jQuery 註

solid
「手堅い」とか「実績のある」といったイメージだろうか。
The JavascriptHelper used
この文以降、形式的には過去形と現在形が入り交じっている。正直なところ、何を意図しているのかよく分からない。少なくとも仮定法を使った文はないと思うのだが、特に would が過去なのか現在なのか、区別し切れない。
とりあえず JavascriptHelper について語っているこの文と次の文については、著者の意識としてはヘルパーを使う方法は古いやり方だから、過去形になっているのもまあ理解できる。ということで訳文でも過去形にした。
This would fire an alert with …
この段落以後の would は単なる弱い推量?
Notice that this is PHP code that
「PHPのコード」であることに力点があるので、訳文には括弧を追加した。
This is pure JavaScript code and can be …
この and は「したがって」「だから」といった意味。
you’re not just stuck using a DOM ID
stuck は stick の過去分詞形。なんとなく意味は伝わってくるのだが正確な訳はよく分からない。訳文はごまかし。辞書には be stuck with doing … で「〜することを押し付けられる」といった訳が載っている。同じような意味か。
a special link that, when clicked, sends off an XMLHttpRequest, rather then redirecting the browser.
この文は理解できなかった。お手上げ。(1) rather then は rather than の typo なのか (2) もしそうだとしたら、rather の前のカンマは何を意図しているのか (3) 仮にカンマを無視するとしたら後半は sends off redirecting the browser という文を想定することになるが、それで意味が通るか (4) もし then が than の typo でないとしたら、一体どういう文になるのか。
訳文では次のような文を「訳」した: a special link that, when clicked, sends off an XMLHttpRequest rather than redirects the browser.
made
「行う」「する」といった意味の make
you would …
この段落の you は明確に読者を意識しているわけではなく、なんとなく「一般の人」を主語においているだけだろう。

Super Awesome Advanced CakePHP Tips 訳と註3

呆れるほど簡単なURLスラッグの作り方

……
Super Awesome Advanced CakePHP Tipsの翻訳3回目です。まさにアイデアの勝利、といった内容ですね。

Stupid Easy URL Slugs 註

Stupid Easy
直訳は「愚かで簡単な」。たぶん決まり文句だろうと思ってGoogleで検索したところ、「非常に簡単な・初歩的な・容易な」という意味で用いられているようだ。それら用例を見る限りでは、必ずしも(字面から想像されるような)否定的な意味とは限らないらしい。ということで、日本語に置き換えるなら「バカでも分かる」がぴったりだと思うのだが、翻訳でそこまでキツイ語を使う勇気はなかったので、もう少しマイルドに「呆れるほど簡単な」としておいた。
Slugs
Wikipedia-en Slug(typesetting)によれば元々は活字組みでスペースを空けるために用いられる部品?のことらしい。現代のDTPソフトウェアでも補助情報を印刷するための領域(最終的には裁断され捨てられる)の名前として使われているとのこと。ちなみにInDesign CS4の日本語版マニュアルでは「印刷可能領域」という見出しで説明されている。
それが、どういう経緯があったのかは知らないが、最近ではURLの中に埋め込むページ見出しの呼称として使われるようになった。日本語では適当な訳語もないし、WordPress等のブログツールで使われてそれなりに広まっているので、片仮名の「スラッグ」で良いだろう。
I’ve seen this idea floated on a bunch of different blogs.
この章に限ったことではないのだが、章の冒頭の文章はけっこう格好つけた感じの文が多くて、そのまま日本語に訳して意味が通るようにするのは難しい。なので訳文はある程度雰囲気重視で作っておいた。
ここでの float は「提案する」という意味で、this idea は当然「URLスラッグを(CakePHPで)作る」という「考え」だろう。スラッグの作り方について、いろいろなブログでいろいろな提案がされているのを見てきたよ、ということ。
Many offer more complicated methods …
この文もちょっと凝っている。「複雑な方法」か「単純にするためのビヘイビア/ヘルパー」だから、どちらも本質的には複雑だ、という含意がある。
you’re using a standard action for your view
この view がよく分からない。「viewアクション」のことなのか、それとも「項目の表示」という意味なのか、あるいは両方を同一視しているのか。訳文では迷った末に view のまま放っておいた。すいません。一応前者のつもりということで。
It is safe to create URLs
定冠詞なしの URLs だから、ここは一般論。日本語では何か接続詞が欲しくなるところ。
With this method
後に続くのが this method なので、この With は「(道具を)使って」という意味かと思えるのだが、それだと意味が通らない。ここは「〜について、〜に関して」という意味だろう。
Consistency And SEO Improvements
「一貫性とSEO」を改善するのか、それとも「一貫性」および「SEOの改善」を話題にしているのか。どちらとも取れるような訳文にしておいた。 Improvements が複数形だから、「一貫性とSEO」を改善するのだろう。初歩的な見落としをしてしまった。
and
ここと次の文の and は「しかし、にも関わらず」といった意味だろう。
cakephp_sucks_and_so_does_your_site
「CakePHPはクソだしお前のサイトもクソだ」。もし日本語で入力したとしても表示されるはずなので、訳してもよかったかも知れない。
happily
日本語で言う「おめでたい」というやつか。
It’s easy enough
特に訳文には反映していないが、この enough は「十分簡単なので(ご安心ください)」というニュアンスが込められているかもしれない。