Element から別のElement を呼び出す

2010年3月7日

公式マニュアルを含むWeb上の情報で見つけることができなかったので、メモしておきます。

そもそも、CakePHPを体系的に理解できている人、具体的には Element が View でどのように展開されているのかを理解している人にとっては自明なことで、いちいち疑問にならないことかもしれません。
私自身は非常に行き当たりばったりの付け焼刃な知識しかない上、ソースを読む時間もなかったので単純な処方箋のみになります。
時間のある方は是非一度詳しくお調べになってください。

何がしたいのかというと、Viewから呼び出したElementの中から、さらに別のElementを呼び出すことです。

結論だけ言いますと、Viewに記述するのと全く同じやり方で問題なさそうです。

たとえば、View ファイル view.ctp から Elementファイル elm1.ctp を呼び出す。そして、その elm1.ctp の中に、別のElementファイル elm2.ctp を呼び出す記述をする場合、次の通りで問題ないというのが今のところの結果です。

view.ctp内

echo $this -> element( "elm1" );

elm1.ctp内

echo $this -> element( "elm2" );

ViewからElementへ新たにパラメータを追加した場合、そのパラメータは引き継がない。
たとえば、view.ctp から、 elm1.ctp へ追加したパラメータを elm2.ctp でも追加したい場合は、 elm1.ctp 内で同様に明示的に追加する必要がある。

view.ctp内

$params = array( "name1" => "value1" );
echo $this -> element( "elm1", $params );

elm1.ctp内

echo $this -> element( "elm2", $params );

mb_convert_kana のオプション

2010年2月2日

php の mb_convert_kana のオプションを決める際に、毎度まいどリファレンスを見直してるんでさすがに嫌になってきた。

分類 記号 意味
半角へ変換 r A→A 全角英字を半角英字へ
n 1→1 全角数字を半角数字へ
a A1→A1 全角英数字を半角英数字へ
s _→_ 全角スペースを半角スペースへ
k ガ→ガ 全角カタカナを半角カタカナへ
h が→ガ 全角ひらがなを半角カタカナへ
全角へ変換 R A→A 半角英字を全角英字へ
N 1→1 半角数字を全角数字へ
A A1→A1 半角英数字を全角英数字へ
S _→_ 半角スペースを全角スペースへ
K ガ→カ゛ 半角カタカナを全角カタカナへ(濁点記号は分離)
H ガ→か゛ 半角カタカナを全角ひらがなへ(濁点記号は分離)
KV ガ→ガ 半角カタカナを全角カタカナへ(濁点記号を一文字に)
HV ガ→が 半角カタカナを全角ひらがなへ(濁点記号を一文字に)
ひらがなカタカナ変換 c ガ→が 全角カタカナを全角ひらがなへ
C が→ガ 全角ひらがなを全角カタカナへ

Scaffolding の、 index の行数を変える

2009年11月2日

Scaffold クラスは、コントローラの $paginate メンバー変数を参照している。

デフォルトでは

var $paginate = array('limit' => 20, 'page' => 1);

なので、1ページ目の20行が表示される。

これを、Controller の継承クラスで上書きして任意に調整。

スロツール、アカウント停止中・・・ orz…

2009年10月31日

まさに青天の霹靂ですが、私の運営しているスロツール.comが、本日の明け方、レンタルサーバー事業者様より、突如アカウントを停止されてしまいました。

もし、スロツールのユーザーさんで、ここをご覧になっているのなら、つまりそういうわけです。本当にすいません。

理由は、スクリプトの負荷が高すぎるためらしいです。

あぁ、他人事だと思っていたアカ停止がまさか自分に降りかかってくるとは。。。
確かに月200円少しの値段にしては、いろいろとやっていたかもしれません。
そして、サーバー運営者にも当然事情はおありでしょう。
私一人のせいで、他の多くの顧客からクレームが来ていたのだとしたら、高々年間数千円程度のユーザーを重く見ることもないでしょう。

しかし、せめて事前に警告ぐらいしてくれてもいいんじゃないの?

とにかく、こちらとしてはどんな形であれ再稼動させたいわけですが、いくつか提案させていただいたのにナシのツブテ。いったいどうしろと?

マジ、連絡して欲しいですよ。


と、22:36にエントリーしているあいだ、アカウント再開のメールが22:34に到着していました。早速、負荷軽減バージョンと差し替え。

ただし、

アカウントを元の状態に戻しましたので、ご確認ください。

再度高負荷の状態になった場合、アカウントの停止を行います。ご了承ください。

よろしくお願いいたします。

とのことなので、いよいよ別のサーバーへ移転せざるを得ないときがやってきたようです。この文面を見れば、一切の警告ナシで、即アウトになる恐れがあるので、戦々恐々としています。

安いから仕方ない、のだろうか?

Model のメンバー変数($belongsTo など)を、コンストラクタで設定する

2009年10月21日

気付いたのでメモ。
「Model::$belongsTo などを、コンストラクタで設定する場合、式の右辺が配列にならないようにするべき。」

たとえば、一般にメンバーフィールドとして記述する際には、必要な値のみ、

class Hoge extends AppModel
{
  var $belongsTo["Moge"] = array(
    "className" => "Moge",
    "foreignKey" => "moge_id",
  );

}

とすればいいですが、これと同じことをやったつもりでも、コンストラクタに以下のように書くと思った通りに動作しません。

class Hoge extends AppModel
{
  function __construct()
  {
     parent::__construct();
     $this -> belongsTo["Moge"] = array(
       "className" => "Moge",
       "foreignKey" => "moge_id",
     );
  }
}

ソースを読む時間がないので処方箋だけを言えば、

class Hoge extends AppModel
{
  function __construct()
  {
    parent::__construct();
    $this -> belongsTo["Moge"]["className"] = "Moge";
    $this -> belongsTo["Moge"]["foreignKey"] => "moge_id";
  }
}

と、する。

親クラスのインスタンス化の際に、”className”, “foreignKey” だけでなく、”conditions”, “fields”, “order”, “counterCache” にも空の値(stirng(0) “”)がセットされています。

$this -> belongsTo = array(
  "Moge" => array(
    "className" => "Moge",
    "foreignKey" => "Hoge.moge_id",
    "conditions" => "",
    "fields" => "",
    "order" => "",
    "counterCache" => "",
  )
);

これら6つの要素のすべてか、一部かは分かりませんが、$belongsTo["Moge"]配列のキーとして、たとえ空の値であってもセットされていないと、アソシエーションを組んでくれないみたいです。

なので、コンストラクタでこれを定義する際は、それらの空の要素も含めて指定するか、必要な値のみを(配列ではなく、次数を落として)文字でセットする必要があります。

blogger API の XML_RPC の原典は?

2009年10月16日

今、ブログ投稿APIを整理しています。

調査中なので、やがて判明するかもしれませんが、覚え書きしておきます。

blogger.deletePost のパラメータが、MovableType と、それ以外とで異なっていることに気づいたのが疑問の発端。 (っていうか、MovableTypeの下記のドキュメントが、単に間違っているっぽいんですが。。。)

MovableType の blogger.deletePost パラメータ (参考)

  • String appkey
  • String postid
  • String username
  • String password
  • String content
  • boolean publish

そのほかの blogger.deletePost のパラメータ(参考, 参考)

  • String appkey
  • String postid
  • String username
  • String password
  • boolean publish

実験してみればすぐに分かることかも知れませんが、今のところ特に問題にならないので完全にスルーしてます。要するに、インターフェイスが2種類存在しちゃってるので、blogger の APIにバージョンが複数あるのでなければ、どちらかが間違っているかということでしょう。接頭辞に’mt.’が付いてるわけじゃないので、MovableTypeの独自APIでも無いわけで。 なんとなく、deletePost ってメソッドに ‘content’ っていうパラメータは不要な気がします。

そこで、肝心の Blogger なのですが、現在は AtomPublishingProtocol に移行しちゃって、 XML-RPCは過去の遺物(Blogger API)としてしか扱ってないみたい。 ‘This documentation is provided for historical interest only.’ などと前書きがあるし、その内容には’実験的なんで、いつ変わるか分かりません’と但し書きが添えてある状態で放置しているのです。

そして、この過去の遺物のどこをひっくり返しても blogger.deletePost にお目にかかれないという次第。どなたかご存知の方がいらっしゃいましたらご教授下さいませ。

携帯用CAPTCHA(画像認証)

2009年10月12日

携帯向けの画像認証スクリプトを公開しました。

以下のページでデモの確認とダウンロードが行えます。

http://u.xao.jp/zubotcha_m/

特徴は以下の通り

  • クッキーを使わない
  • 数字のみの入力
  • 設置が(たぶん)とても簡単

厳密にCAPTCHAといえば、コンピュータと人間を区別するためのものですが、これは人間に対して、投稿アクションの心理的なハードルを高める目的が主です。いわゆる一つのシシオドシ。

もちろん、画像のフィルタリングを複雑にして、ロボット対策も可能になりますが、そうするのであれば、もっと高機能なスクリプト、たとえば KCAPTCHA などを利用する方が良いでしょう。

それから、ワンタイムハッシュの発行なんかも実装してないので、二重ポストの防止にもなりません。これは、いずれ必要なときに追加しようと思います。

php imagettftext()

2009年10月12日

パラメータ $angle の説明は、原文は ‘counter-clockwise’  なんで、「反時計回り」が正しい。
たまにこの関数を使うたびに気づくんですけど、そのうち訂正されると思っててもそのままです。

http://www.php.net/manual/ja/function.imagettftext.php

ps: メーリングリストに参加して具申いたしたところ、直ちに修正していただけました。有難うございます!(2009/10/21 確認)

WordPress の、 do_action って関数を見てみた

2009年10月5日

現在ほとんどデフォルトのままの WordPress 。
とりあえず、差し迫って必要なことは無いのだけど、なにかいじってみたいので Google Analytics を挿入してみようと思います。

結論を言いますと、結局先人の開発したすばらしいプラグイン Ultimate Google Analytics plugin for WordPress を使用しました。

なので、以下は単にソースを読んだときのメモです。

吐き出されたHTMLソースから、どうやら wp_footer() という関数に、好きなコードを吐き出させるみたい。んで、この wp_footer が何をしているのかたどっていく。

すると、

wp-content\themes\default\footer.php(14)
wp-includes\general-template.php(1362)
wp-includes\plugin.php(299)

までたどり着いたのですが、この、 plugin.php にある

function do_action

ていうのはよく読まないと先へ進めないです。
で、私なりに読んで解釈したのをメモします。
ちなみに、この関数はいたるところで呼び出されていると思いますが、今回はあくまでもフッタの記述。つまり、引数として “wp_footer” っていう文字列を渡している場合に限られます。そして、トップページでの呼び出しでのみ調べたことなので、ページが異なれば挙動が変わる可能性も大いにありです。

function do_action($tag, $arg = '') {
  // 4つのグローバル変数を関数内で展開
  global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;

  // 配列 $wp_actions に "wp_footer" をプッシュ。
  if ( is_array($wp_actions) )
    $wp_actions[] = $tag;
  else
    $wp_actions = array($tag);

  // 配列 $wp_current_filter にも "wp_footer" をプッシュ。(これは、空の配列でした)
  $wp_current_filter[] = $tag;

  // $wp_filter['all'] はセットされていないのでパス
  // Do 'all' actions first
  if ( isset($wp_filter['all']) ) {
    $all_args = func_get_args();
    _wp_call_all_hook($all_args);
  }

  /*-------------------------------------
   $wp_filter[$tag] がセットされていなければ、
   $wp_current_filter から先ほどの "wp_footer" をポップして終了しますが、
   $wp_filter['wp_footer'] に値があるので続く。
   この、 $wp_filter の該当する箇所を抜き出すとこんな風。

  array(
    [wp_footer] => array
    (
      [10] => array
      (
        [wp_print_footer_scripts] => array
        (
          [function] => wp_print_footer_scripts
          [accepted_args] => 1
      )

      )

    )
  )

  ここに、処理内容をスタックさせているのでしょう。
  ---------------------------------------*/
  if ( !isset($wp_filter[$tag]) ) {
    array_pop($wp_current_filter);
    return;
  }

  // $args には何もセットされない。
  $args = array();
  if ( is_array($arg) && 1 == count($arg) && is_object($arg[0]) ) // array(&$this)
    $args[] =& $arg[0];
  else
    $args[] = $arg;
  for ( $a = 2; $a < func_num_args(); $a++ )
    $args[] = func_get_arg($a);

  /*----------------------------------------
  $merged_filters[$tag] がセットされていないので

  ksort($wp_filter[$tag]);
  $merged_filters[ $tag ] = true;

  っていう処理を行う。けど、$wp_filter['wp_footer'] は、
  1つしか要素が無いので順番は変わらない。 reset してもポインタに影響なし。
  -----------------------------------------*/
  // Sort
  if ( !isset( $merged_filters[ $tag ] ) ) {
    ksort($wp_filter[$tag]);
    $merged_filters[ $tag ] = true;
  }

  reset( $wp_filter[ $tag ] );

  /*-------------------------------------------
  いよいよここで、$wp_filter['wp_footer']
  にセットされたタスクを処理

  current だとか、array にキャストだとか、
  私が使ったことの無い、良く分からんけど なんかかっこいい
  テクニックが最後に出てきてしまいましたが、
  要は $wp_filter['wp_footer'] から、配列を抜き出して、
  その配列を foreach でループさせているのですね。(違う?)
  PHPでポインタとか考えたこと無かったんで、この辺ちょっと勉強不足です。

  で、実際に何を実行しているかというと、

  関数 wp_print_footer_scripts() の呼び出しなのですね。
  受け取る引数の数が 1 ですが、 $args には何も入っていないので、
  wp_print_footer_scripts() には、空の配列が渡されて終了。
  -------------------------------------------*/
  do {
    foreach ( (array) current($wp_filter[$tag]) as $the_ )
      if ( !is_null($the_['function']) )
        call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));

  } while ( next($wp_filter[$tag]) !== false );

  // 最初にプッシュした "wp_footer" をポップして(空に戻る)終了。
  array_pop($wp_current_filter);
}

で、肝心のフッタの挿入ですが、 wp_print_footer_scripts は、 print_footer_scripts を呼び出していています。(ふぅーっ)

ここまできて、これはやはり先人のご意見を伺おうとググってみたわけです。

「WordPress Google」 ここまで入力した時点で、アナリティクス(って、しかもカタカナで)補完(笑)

はい、すばらしいプラグインがありました。

http://www.oratransplant.nl/uga/

ありがとう御座いました。

すごいこれ!
ログイン中のユーザーに対してはスクリプト吐き出さないんですね!

function do_action($tag, $arg = ”) {
// 4つのグローバル変数を関数内で展開
global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;

// 配列 $wp_actions に “wp_footer” をプッシュ。
if ( is_array($wp_actions) )
$wp_actions[] = $tag;
else
$wp_actions = array($tag);

// 配列 $wp_current_filter にも “wp_footer” をプッシュ。(これは、空の配列でした)
$wp_current_filter[] = $tag;

// $wp_filter['all'] はセットされていないのでパス
// Do ‘all’ actions first
if ( isset($wp_filter['all']) ) {
$all_args = func_get_args();
_wp_call_all_hook($all_args);
}

/*————————————-
$wp_filter[$tag] がセットされていなければ、 $wp_current_filter から先ほどの “wp_footer” をポップして終了しますが、 $wp_filter['wp_footer'] に値があるので続く。
この、 $wp_filter が興味深い。該当する箇所を抜き出すとこんな風。

array(
[wp_footer] => array
(
[10] => array
(
[wp_print_footer_scripts] => array
(
[function] => wp_print_footer_scripts
[accepted_args] => 1
)

)

)
)

ここに、処理内容をスタックさせているのでしょう。
—————————————*/
if ( !isset($wp_filter[$tag]) ) {
array_pop($wp_current_filter);
return;
}

// $args には何もセットされない。
$args = array();
if ( is_array($arg) && 1 == count($arg) && is_object($arg[0]) ) // array(&$this)
$args[] =& $arg[0];
else
$args[] = $arg;
for ( $a = 2; $a < func_num_args(); $a++ )
$args[] = func_get_arg($a);

/*—————————————-
$merged_filters[$tag] がセットされていないので

ksort($wp_filter[$tag]);
$merged_filters[ $tag ] = true;

っていう処理を行う。けど、$wp_filter['wp_footer'] は、1つしか要素が無いので順番は変わらない。 reset してもポインタに影響なし。
—————————————–*/
// Sort
if ( !isset( $merged_filters[ $tag ] ) ) {
ksort($wp_filter[$tag]);
$merged_filters[ $tag ] = true;
}

reset( $wp_filter[ $tag ] );

/*——————————————-
いよいよここで、$wp_filter['wp_footer']
にセットされたタスクを処理

current だとか、array にキャストだとか、
私が使ったことの無い良く分からんけど、
なんかかっこいいテクニックが最後に出てきてしまいましたが、
要は $wp_filter['wp_footer'] から、配列を抜き出して、
その配列を foreach でループさせているのですね。(違う?)
ポインタとか考えたこと無かったんで、この辺ちょっと勉強不足です。

で、実際に何を実行しているかというと、

関数 wp_print_footer_scripts() の呼び出しなのですね。
受け取る引数の数が 1 ですが、 $args には何も入っていないので、
wp_print_footer_scripts() には、空の配列が渡されて終了。
——————————————-*/
do {
foreach ( (array) current($wp_filter[$tag]) as $the_ )
if ( !is_null($the_['function']) )
call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));

} while ( next($wp_filter[$tag]) !== false );

// 最初にプッシュした “wp_footer” をポップして(空に戻る)終了。
array_pop($wp_current_filter);
}

毎度まいど、バカバカしいことで・・・

2009年10月4日

CakePHPの、ついうっかり忘れてしまう基本事項。
何ヶ月かぶりにさわると、よく間違える。
箇条書きにして、機会があれば見直すための備忘録。

  • コントローラがビューするメソッドは Controller::render()、よく Controller::display() と Smarty風にやってしまう。
  • モデルからレコードをセレクトするメソッドは Model::find()、よく Model::select() とやってしまう。