PHPでmysql_queryの結果オブジェクトは、mysql_fetch_row()しても良いですが、mysql_fetch_array()した方が便利ですよね。
※mysql_fetch_row()では、結果を通常の配列で取得しますが、mysql_fetch_array()では、カラム名をキーにした連想配列で取得できます
EthnaでAppObjectを使わずにEthna_DBを直接たたく場合、結果オブジェクトはPEAR::DB_Resultオブジェクトです。
これはfetchRow()のメソッドを持ちますが、fetchArray()は存在しません。
http://pear.plus-server.net/package.database.db.db-result.fetchrow.html
カラム名をキーにした連想配列が欲しい場合、queryを投げる前にsetFetchMode(DB_FETCHMODE_ASSOC)を実行しておく必要があります。
http://pear.plus-server.net/package.database.db.db-common.setfetchmode.html
EthnaのデフォルトDBアダプタ、DB_PEARは、内部にPEAR::DBを持っているので、以下のようなコードを書けばOKです。
$db = $this->backend->getDB();
$db->db->setFetchMode(DB_FETCHMODE_ASSOC);
$res = $db->query($sql);
print_r($res->fetchRow());
※http://ethna.jp/ethna-document-dev_guide-db.htmlに
Ethnaの デフォルトの DB接続クラス(Ethna_DB_PEAR) はPEAR::DBを継承しているので
と書いてありますが、継承ではなくて委譲なので、$db->db->setFetchMode()となります。
PHPでMySQL 5をUTF8にして使う場合、文字が全部????になってしまう問題を防ぐため、
default-character-set=utf8
character-set-server=utf8
collation-server=utf8_general_ci
skip-character-set-client-handshake
を指定する、というのが定石になっています(よね?)。
しかし、共用サーバなどでmy.iniを編集できない場合、mysql_set_charset() などを使うと思います。
CakePHPでは、bootstrapでDB設定を読んで手動で設定するのも面倒だな、と思っていたら、さすがはCakePHP。便利な設定が。
app/config/database.php
var $default = array(
'driver' => 'mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'baba',
'password' => 'hoge',
'database' => 'testdb',
'prefix' => '',
'encoding' => 'utf8',
);
このようにencodingを指定するだけで、勝手にSET NAMESやmysql_set_charset()を実行してくれます。便利便利。
WindowsのXAMPP環境でEthnaを使う際、Ethnaコマンドの設定でよく戸惑います。
プロジェクトの環境依存を減らすため、Ethna自体をプロジェクトのlibフォルダに入れるのが好きなのですが、そのような環境だと
- add-project で Could not open input file: ~\Ethna\bin\\bin\ethna_handle.php となどのエラー
- add-action で Fatal error: Could not redeclare class Ethna などのエラー
が出ることがあります。
私の使い方では、以下のような設定に落ち着きました。
共通の設定
phpにパスを通します。xampp/php のフォルダを環境変数のPATHで設定します。
ethna.bat があるフォルダにはパスを通さない方が良いです。
add-project をするとき
Ethnaをダウンロードして、workspaceに設置します。
workspace/Ethna/bin/ethna.bat を、workspaceにコピーします。
workspace/ethna.bat を開き、@PEAR-DIR@ を .\Ethna に一括置換します(2カ所)。
これで、コマンドプロンプトで、workspaceに入り、
C:\Users\baba\workspace > ethna add-project hoge
と実行できます。
add-action などをするとき
add-project 以外では、Ethnaのプロジェクトのディレクトリにいる必要があります。
hogeプロジェクトがある場合、workspace/hoge/lib フォルダに、Ethna(とSmarty)を設置しておきます。
workspace/hoge/lib/Ethna/bin/ethna.bat を、workspace/hoge にコピーします。
workspace/hoge/ethna.bat を開き、@PEAR-DIR@ を、 .\lib\Ethna に一括置換します(2カ所)。
これで、コマンドプロンプトでhogeディレクトリに入り、
C:\Users\baba\workspace\hoge > ethna add-action hoge_index
と実行できます。
以上で実行できますが、正直面倒なので、Eclipseプラグインを作ろうと思います。
CakePHPでjQueryを使ったAjaxを実装した際、IEの古いバージョンでのみエラーになる現象に見舞われました。
調べてみると、Ajaxリクエストを送った際にログインが切れているようです。
どうやら原因は、CakePHPのユーザエージェント検証機能でした。
app/config/core.phpで
Configure::write(’Session.checkAgent’, false);
を設定することで解決しました。
つまり、古いIEでは、通常時のリクエストとAjaxリクエストで、ユーザエージェントが違う、ということですね。
これはたぶん、歴史的な理由からXMLHttpRequestがActiveXオブジェクトで実装されていることに由来するのでしょう。
以下に、各ブラウザで確認したユーザエージェントを書いておきます。
PHPで、$_SERVER['HTTP_USER_AGENT'] を表示しています。また、Ajax通信は、jQueryの$.ajax()を使っています。
■Firefox 3.5.6
通常: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)
Ajax: Mozilla/5.0 (Windows; U; Windows NT 6.1; ja; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)
■Chrome 4 beta
通常: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.64 Safari/532.5
Ajax: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.64 Safari/532.5
■IE8
通常: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
■IE7
通常: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
■IE6
通常: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 6.1; WOW64; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
Ajax: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; .NET4.0E)
CakePHPのpaginatorは、ページングの他にソートもやってくれて大変便利です。
しかし、たまに「ソートはするけどページングしたくない」ということもありますよね?
そんなとき、$this->paginate['limit'] = null のようにやると、Zero Divide でエラーになります。paginatorの中ではそんなことは想定されていません。
ゼロからソート部分を作るのも面倒なので、paginatorのソート部分だけを無理矢理使わせてもらいましょう。
コントローラで以下のように処理します。
//手動でsort
$order = null;
if (isset($this->passedArgs['sort'])) {
$direction = null;
if (isset($this->passedArgs['direction'])) {
$direction = strtolower($this->passedArgs['direction']);
}
if ($direction != 'asc' && $direction != 'desc') {
$direction = 'asc';
}
$order = array($this->passedArgs['sort'] => $direction);
}
//paginate処理はするが、そのデータは使わない
$this->paginate();
//全件を表示
$result = $this->Model->find('all', array('order' => $order)));
この方法なら、ビューでは、
$paginator->sort(’なまえ’, ‘User.name’);
のように、普通にpaginatorを使うときの同じようにかけます。
強引であまり褒められた方法ではありませんが、これで目的は達成できました。
Ajaxを使う際、PHP側からJSON形式の値を出力したいことは良くあると思います(入力はだいたいPOSTで事足りますね)。
PHPでJSON形式の値を出力したい場合、いちばん簡単なのはjson_encode()です。
//本来はheaderなども正しく処理した方が良いが省略
$list = array('apple', 'orange', 'banana');
echo json_encode($list);
ただし、json_encode()はPHP 5.2.0以上の関数なので、それ未満の環境だとundefined functionでエラーになります。
http://php.net/manual/en/function.json-encode.php
リリース後にPHPのバージョン違いに気がついた可哀想な人には、Zend_Jsonがおすすめです。
まずはZend FrameworkのページからZend Frameworkをダウンロードします(minimalでOK)。
そして、回答したフォルダのZend/Json.phpと、Zend/Jsonフォルダをinclude_pathが通ったフォルダにコピーします。
あとは、コード内で
require_once 'Zend/Json.php';
$list = array('apple', 'orange', 'banana');
echo Zend_Json::encode($list);
とやるだけ。
関数の名前が変わるだけで、同じ使い勝手が実現できていますね。これなら一括置換も簡単。
XAMPP最新版1.7.2では、PHPのバージョンが5.3になっています。
この環境でCakePHP(1.2.5)を使うと、以下のようなエラーが出ることがあります
Warning: strtotime() [function.strtotime]: It is not safe to rely on the system’s timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected ‘Asia/Tokyo’ for ‘9.0/no DST’ instead in …
この場合、cakeのapp/config/core.phpで以下の行のコメントアウトを外せばOKです。
date_default_timezone_set(’UTC’)
メッセージそのままで当たり前のことですが・・・
#関係ないですが、なんでCakePHP 1.2.5をインストールすると1.2.4.8284と出るんでしょうね?
久々のEthna小ネタです。
Ethnaでのデフォルトアクション名はAppID_Action_Hogeのようなスタイルのアクション名ですが、これを変更したい場合のTIPSです。
例えば、AppID_HogeActionのようにアクションのクラス名を変更したいと思います。
AppID_Action_Hoge => AppID_HogeAction
その場合は下記のようにAppID_Controller.php内にgetDefaultActionClassメソッドをオーバーライドすることで簡単に実現できます。
ちなみに、アクションをコマンドから作る場合にコントローラに下記のコードを書いておくだけで命名規則が変更されるため、アクションを作る前にコントローラに実装しておくことがお薦めです。
また、ビュー(View)やアクションフォーム(ActionForm)などの命名規則も同様にgetDefaultViewClass, getDefaultFormClassをオーバーライドするだけです。
function getDefaultActionClass($action_name, $gateway = null) {
$gateway_prefix = $this->_getGatewayPrefix($gateway);
$postfix = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($action_name));
$r = sprintf("%s_%s%sAction", $this->getAppId(), $gateway_prefix ? $gateway_prefix . "_" : "", $postfix);
$this->logger->log(LOG_DEBUG, "default action class [%s]", $r);
return $r;
}
JavaScriptってあまり好きじゃないけど便利なものありますね。
先達者の皆様にいつも感謝です。
中でも普段の受注制作で使えそうで、
個人的に興味がある/好きなもの紹介してみます。
Anything Slider
http://css-tricks.com/examples/AnythingSlider/#panel-5
画像とか動画とかスライドできちゃいます。
ちょっとした“魅せ”にはいいですよね。
以外と感動してくれるお客様もいそうです。
CakePHP×FCK Editor
http://d.hatena.ne.jp/slywalker/20081125/1227621414
CMSで自由に画像を加えたりフォーマットをいじるためには、
HTMLを許容したり自由度を下げたりしないといけないですよね。
WordPress-likeなエディタUIを加えてあげることで
編集しやすいCMSをつくるのもいいですよね。
Dojoは、デフォルトでは読み込み元HTMLと同じサーバに置くことを前提に作られています。
具体的には、dojo.require()が、XMLHttpRequestを使ってデータを取得します。
このため、同じドメインにライブラリを設置できない場合(共有サーバで権限が無い時など)、クロスドメインの制限でdojo.require()が失敗してしまいます。
dojo.parserなどの内部でrequireを使っているため、ライブラリの読み込み時点でエラーが多発してしまいます。
この場合は、クロスドメインビルドをしたdojoライブラリ(XDomain Dojo)を使用します。
方法1: AOLを使用
お手軽に使うには、AOLのCDNを活用します。
http://dev.aol.com/dojo に書いてあるように、以下の形式でdojoライブラリを読み込むだけでOKです。
<script type=”text/javascript” src=”http://o.aolcdn.com/dojo/1.3/dojo/dojo.xd.js”></script>
この場合、dojo.requireは、デフォルトで用意されているdojo, dijit, dojoxのみ使用可能で、自前のコンポーネントは使用できません。
方法2: クロスドメインDojoのビルド
方法1はお手軽ですが、AOLのサーバが重いとか、自前で設置したいこともあると思います。
その場合、Dojoをソースからビルドします。
-
ソースを入手
まず、Dojoのダウンロードサイトから、ソースを取得します。dojo-release-1.3.0-src.zip のように、srcが付いているものがソースです。
ダウンロードサイト: http://download.dojotoolkit.org/
- ビルド
そして、以下のページの手順に従い、ビルドします。
ビルドの手順: http://www.dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds
具体的には、以下のコマンドでビルドできます。(Linuxの場合)
xdDojoPathに、Dojoライブラリを設置するディレクトリ名を記述します。テスト環境と本番環境ではURLが違うと思うので、その場合は2回ビルドする必要があります。
パックするライブラリを変更したい場合は、profileを変更します。
$ cd util/buildscripts
$ build.sh profile=standard loader=xdomain xdDojoPath=http://www.bpsinc.jp/dojoxd action=release
以上のコマンドを入力すると、ビルドが始まり、しばらくするとreleaseフォルダにXDomainビルドされたDojoが生成されます。
- 設置
xdDojoPathに設定したフォルダに、dojoを設置します。
上記の例では、DocumentRootのdojoxdフォルダに、dojo/dijit/dojox が入っている状態になります。
- 読み込み
あとは、
<script type=”text/javascript” src=”http://www.bpsinc.jp/dojoxd/dojo/dojo.xd.js”></script>
のように読み込めばOKです。