okomeworld

なんやかんやで白米が好き

twitterでカオナシbotを作りました

タイトルのとおりですが、twitterボットを作ってみました。
http://twitter.com/kaonashi_bot

twitterでいろんなボットを見て「これなら自分でも何かできるかも」と思い
「ネタになるようなものがいいなぁ」と考え、千と千尋の神隠しカオナシというキャラクターで
ボットを作りました。

機能としては
 ・定期的につぶやく
 ・フォローされたら、フォローし返す

この二つのみです。

今後リプライを返すような機能もつけたいなーと思っていますが
漠然と考えているだけで作業は何もしていません。

ひたすら「あ」とつぶやき続ける時報みたいになってますが
かわいがってやってください。

beforeFindを使うときに気をつけること

ModelクラスにbeforeFindメソッドというのがあって、SQL発行時に常にいれておきたいwhere句を
設定しておいたりするのによく使用します。

<?php
class Post extends AppModel {
    function beforeFind($queryData) {
        $queryData = parent::beforeFind($queryData);
        $queryData['conditions']['Post.status'] = true;
        return $queryData;
    }
}
?>

だいたいこんな感じで使ってますが、これを実行するとエラーが発生。
$queryDataの中身が何故かtrueになっているため、処理ができないとのこと。
あれ?と思ってソースをたどってみるとコアのModelクラスに定義されているbeforeFindが

<?php
function beforeFind($queryData) {
    return true;
}
?>

となっていました。なのでapp/app_model.php

<?php
class AppModel extends Model {
    function beforeFind($queryData) {
        return $queryData;
    }
}
?>

と書き加えて解決しました。

ブックには”$queryDataを返すか、findに渡したいものかそれ相応のものを返します。”とあるけど
$queryDataを返す場合が一番多い気がするんだけどな。なぜtrueなんだろ。

アソシエーション先のモデルで使用しているビヘイビアのafterFindを動かす方法

デフォルトだと何故かビヘイビアでafterFind定義していても動いてくれない。
ちょっと不便だったので動くようにしてみました。

<?php
class AppModel extends Model
{
  function afterFind($results,$primary=false)
  {
    $results = parent::afterFind($results,$primary);
    if(!$primary) {
      $params = array($results,$primary);
      $options = array('modParams' => true);
      $results = $this->Behaviors->trigger($this,'afterFind',$params,$options);
    }
    return $results;
  }
}
?>

モデルクラスはBehaviorsCollectionモデルというのをプロパティに持っているようで
BehaviorCollectionモデルのtriggerメソッドは、指定したメソッドが使用しているビヘイビアにあれば
一気に呼び出してくれるもののようです。

triggerメソッドに関してはhttp://api.cakephp.org/で見てみれば大体の雰囲気はわかると思います。
とりあえず僕はこれで今のところ困ってません。

しかしなぜafterFindは動いてくれないんだろ。。
わざわざ第2引数にprimaryフラグがあるので何か理由があるのかもしれませんけど・・・。

ctrl+sを押してしまったら落ち着いてctrl+qを!!

puttyに限らずターミナル系はだいたいそうらしいですが

viでテキスト編集してて最後に:wqやるつもりが、いつもの癖でctrl+sを押してしまったりして。。
そうするとターミナル系ではctrl+sはコンソールへの出力をロックするという処理を行なってしまうようで
ターミナルがフリーズしたように感じちゃって「え、なにこれ、なんかやばいんじゃないのか」と焦りますが(実際焦った)
単純にctrl+qでロックを解除できるらしく、試してみたらちゃんと動いてくれました(当たり前なんでしょうが・・・)

なので癖でctrl+sやってしまったときはctrl+qを慌てずに。。。。

Htmlヘルパーを使って$script_for_layout変数にCSSのlinkタグをセットする

http://book.cakephp.org/ja/view/1437/css/を見ると

css(mixed $path, string $rel = null, array $htmlAttributes = array(), boolean $inline = true)

CSS スタイルシートへのリンクを作成します。$inline を false にセットした場合、link タグは $scripts_for_layout 変数の中に出現するようになるので、この変数を文書中の head タグの中に入れておくといった使い方ができます。

とあるけど、実際CakePHP 1.3.5の環境で実行してもheadタグに入ってくれない。
おかしいなぁ、と思ってhttp://api.cakephp.org/view_source/html-helper/#line-336を見てみると

<?php
  function css($path, $rel = null, $options = array())
  {
    $options += array('inline' => true);
    ・・・
  }
?>

えええええ
・・・ということで下のコードで実行するとしっかりheadタグに入ってくれました。

<?php
$html->css($path, null, array('inline' => false));
?>

これいつからなんだろう。1.3から?
何にせよ、困ったときのAPIだなぁと思った。。

ルートの処理ではまった

<?php Router::connect('/foo/',array('controller' => 'foo','action' => 'bar')) ?>

上のようなルート設定をしてる環境では、http://hostname/foo/にアクセスすると
思い通りの処理をしてくれるけど、http://hostname/fooにアクセスした場合
FooControllerがないよ。なんて言われたりする。当たり前っちゃ当たり前だなぁ。。。

ただ、この環境下で

<?php pr(Router::url(array('controller' => 'foo','action' => 'bar'))) ?>

とした場合、"/foo"となってしまう。これは$html->link()でも同じで、当然アクセスしても
FooControllerないよ!とか言われる。思い通り動いてくれない。。。

ルート処理でURL指定する場合は"/"で終わらせないほうがいいっぽい。

<?php Router::connect('/foo',array('controller' => 'foo','action' => 'bar')) ?>