cakePHP2.1でcakeEmailを使う。

そろそろcakePHP2.1であんなことやこんなことやっていろいろ恥ずかしいことも蓄積してきたので皆様とシェア致します。

こちらのサイトを参考にしました。
1.2,1.3ではqdmailを使っていたのですが、開発自体がすでに止まっているようなので
標準で用意されているものも最近は利用されている人が多いようなのでこちらでやってみました。

app/Config/email.phpにはこんなかんじで設定。gmail経由で送ってみたよ。
インストールしたばっかりんときはemail.php.defaultみたいなファイル名なので名前をちゃんと変えよう。
すでにdefaultの項目があるのでこんなかんじに変えてみました。お好みで変えてみてください。

	public $default = array(
		'transport' => 'Smtp',
		'from' => array('yash@xxx.com' => 'メールでの表示名'),
		'host' => 'ssl://smtp.gmail.com',
		'port' => 465,
		'timeout' => 30,
		'username' => 'hogehoge@hogehoge.com',
		'password' => 'hogehoge',
		'log' => true//ここをtrueにするとtmp/debug.logにメールのログが書かれる。
	);

を冒頭にセット。
使う側のコントローラーには

App::uses('CakeEmail', 'Network/Email');

そんでもって実際に送る場所こんなかんじで。
テンプレートやらのセットはマニュアルにあるので読むべし。cakePHP2.1から?ではないと思うけどテンプレートの構成が若干1.2と変わっているんでつね・・

$email = new CakeEmail('default');//ここ、ちゃんとdefaultを設定しないと送れませんでした・・。
$email->from(array('yashiro@XXX.com' => 'My Site'));
$email->to('yashiro@XXX.com');
$email->subject('テストです');
$email->send('日本語でおくれるかなー?');

こんなかんじで無事におくれました!(∩´∀`)∩ワーイ
Pluginも結構cakePHP2.1で動くもの多いですね。SearchPluginもACLPluginも。SoftDeleteビヘイビアとかArraySourceとかもぼつぼつ。

広告

CakePHP Advent Calendar 2011 12/09

こんにちは。本日12月9日担当の@yashioです。
来週はいよいよcake勉強会and忘年会ですね(∩´∀`)∩ワーイ皆さんにあえるの楽しみにしています。

さて今回は、1.3系で・・しかも出尽くされていると思いますがViewキャッシュ導入について紹介したいと思います。
いろいろな方がこちらは紹介されていますが、私でもできるヨ!ってことで生暖かく見てください。
頑張って図つけたわ。。これが一番時間かかったとか・・・・。

・登録者向けのサービスだが、ログイン前にランディングページなどの静的なページを多用している
・できるだけ、ウェブサーバーへの負荷を軽減したい

などの時にぜひ。

レシピ:cake1.3、 https://github.com/mcurry/html_cacheからダウンロードしてきた一式

手順その1:
https://github.com/mcurry/html_cache からファイルをダウンロードしてapp/plugins/html_cache/の下につっこむ。

手順その2:
App::import(‘core’, ‘File’); をapp_controller.phpのbeforeFilterに記述する(これ重要です。忘れてすごい悩んだ・・)
特定のコントローラーだけに処理をさせたい場合は、該当するcontrollerのbeforeFilterに記述が望ましいでしょう。

手順その3:webroot/cache配下に静的に出力したいファイルのパスでディレクトリをつくる。app/webroot/cache/controller名/action名/のような。

手順その4:
3で作成したディレクトリにアクセス権限をつける。実際にここに静的なHTMLファイルが作成されます。

手順その5:
静的表示をしたいコントローラー、のアクションに、

$this->helpers[] = ‘HtmlCache.HtmlCache’;

を追記する。
※妙な怒りのデバッグが入っていますがおきになさらずに。ちゃんと表示されます。

これは、3の手順で作成したディレクトリのパスにcontroller,actionが一致している必要があります。

手順その6:
webroot直下にある/htaccessを表1.のように変更する(簡単に言うと、webroot/cache配下に該当のファイルがある場合にはそちらを優先的参照する。ない場合は通常通りフレームワークのルールに則り、/controller/actionへ飛ぶ。)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} ^GET$ #追加部分
RewriteCond %{DOCUMENT_ROOT}/cache/$1/index.html -f #追加部分
RewriteRule ^(.*)$ /cache/$1/index.html [L]  #追加部分
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
</IfModule>

手順その7:
美味しくいただく。 さあ該当ページにアクセスしてみましょう。ファイルが作成されない場合はパーミッションの確認をしてください。
3で作られたディレクトリにファイルがつくられていますか?日付を見てみてくださいね。
この場合、controllerも通らないので不必要なロードがされないので結構表示速度を体感できるのではないかと思います。
(コンテンツにもよるでしょうが)


試しに削除してもう一度作成してみましょう。【やったー!】
注意すべきことはctpファイルの中身に変更が合った場合などは、

こちらにあるキャッシュを一度削除しないと新しいファイルが作成されません。

そのため頻繁に変更するファイルに関してはあまり向かないかもしれませんが、キャッシュで表示する方が
明らかに表示速度は上昇しますので、お手軽にできますし皆さん、試してみてはいかがでしょうか。

さて、明日はおなじみ@mon_satさんです。よろしくおねがいしまーす!

bootstrap.cssの対応(for Play framework)

メモ。
ちょっと家庭内制作で「phpじゃないやつで!」ということになってjavaでrailsライクなplayframeworkいぢってんですが、
来月の某締切りにむけて画面周りで、Bootstrap を使ってます。
で、playはそもそもrailsライクってことで、cakephpと非常に似ているので、ファイルの構成とかは分かりやすい。
まあおいおいいろいろかけたらと思うんですけど、ひとまず、今Bootstrapが流行っているので、playframeworkで使ってみたい!ってことで使ってたんですが、一点、pagenateについてがどうにも、見た目を変更する必要がありました。

なので、paginateの導入も含めてメモしときます。

※試行錯誤なんで、自己責任でよろしくおねがいします><

1.2.2使っているので、コンソールでとりあえず

play install paginate

する。そうすると、コンソールで「いれちゃうぜ?」てきいてくるので、はいyて答える。

そうすると・・・playインストール場所/modulre/paginate-0.11

という構成になり、そこにモジュールが展開される。

そのあと、

conf/dependencies.ymlに

~ require:

~ play -> paginate 0.11
これを追記して、さらに
conf/application.confに
# Import the pagenate module
module.paginate=${play.path}/modules/paginate-0.11
こんな感じで、play再起動。起動時に、
Module paginate is available (/home/yashiro/play-1.2.2/modules/paginate-0.11)
とかいうログが見えると、無事paginateモジュールが読み込まれています。
さて、そのモジュールの中に、htmlが入っていて、(playの雛形みたいな)paginateに対してどういう記述をするか
が書かれているControls.htmlをいうソースを探し出します( paginate-0.11/app/views/にありました)。
それをコピーして、app/views/paginate/Controls.htmlという構成にします。
(やってることはcakephpで、helperを自分のappの配下にもってきて変更していることにそっくり。)

それでそのファイルをこんな感じで修正してみました。そしたらデモで見えるようなpaginateが表示されたよ!

(実際はpaginateを表示させるところまで、これ以外にもいろいろ道のりがあったんですが・・それは割愛)

app/views/paginate/Controls.html

%{
int __firstPage = 1;
int __currentPage = _items.pageNumber;
int __pagesDisplayed = _items.pagesDisplayed;
int __pagesBeforeMiddle = __pagesDisplayed / 2;
int __maxPage = _items.pageCount;
if (__currentPage > (__pagesDisplayed / 2)) {
	__firstPage = __currentPage - __pagesBeforeMiddle;
}
int __lastPage = __currentPage + (__pagesDisplayed - __pagesBeforeMiddle - 1);
if (__currentPage < (__pagesDisplayed - __pagesBeforeMiddle)) {
	__lastPage = __pagesDisplayed;
}
if (__lastPage > __maxPage) {
	__lastPage = __maxPage;
}
boolean __hasPrev = _items.hasPreviousPage;
boolean __hasNext = _items.hasNextPage;
String __firstURL = __hasPrev ? _items.getCallbackURL(1) : "#";
String __prevURL = __hasPrev ? _items.getCallbackURL(__currentPage-1) : "#";
String __nextURL = __hasNext ? _items.getCallbackURL(__currentPage+1) : "#";
String __lastURL = __hasNext ? _items.getCallbackURL(__maxPage) : "#";
%}
<div class="pagination">
	<ul>
%{ if (_items.boundaryControlsEnabled) { %}
		<li class="${__currentPage == 1 ? 'disabled' : 'first'}"><a href="${__firstURL}">&{'play-paginate.first'}</a></li>
%{ } %}
		<li class="${__hasPrev ? 'previous' : 'disabled'}"><a href="${__prevURL}">&{'play-paginate.prev'}</a></li>
%{
for (__idx = __firstPage; __idx <= __lastPage; __idx++) {
boolean __active = __currentPage == __idx;
%}
		<li class="${__active ? 'active' : 'inactive'}"><a href="${_items.getCallbackURL(__idx)}">${__idx}</a></li>
%{
}
%}
		<li class="${__hasNext ? '' : 'disabled'}"><a href="${__nextURL}">&{'play-paginate.next'}</a></li>
%{ if (_items.boundaryControlsEnabled) { %}
		<li class="${__currentPage == __maxPage ? 'disabled' : ''} next"><a href="${__lastURL}">&{'play-paginate.last'}</a></li>
%{ } %}
	</ul>
</div>
<br style="clear:both;"/>

まあここまではよかったんだけど、lastページになると、PreviousとNextのあいだのページ数が一個減るという謎の

現象に・・まあこれは次回でもどうにか修正することにしましょう。

 

※10年ぶりにJavaとか見たら、「アノテーション」とかいう謎の識別子がついていて時代を感じた。

mysqlバックアップ

テーブルを丸ごとバックアップする方法で今までバックアップをとってきたんだが、
ある特定の業務アプリで、データが膨大なものが存在してた。
エディタでいちいちひらいてテーブルの名前から探して…みたいなことをしてたみたいで、
ちょっと手間がかかるなと。で、緊急時にリストアする際に、特定のテーブルだけしたいという
リクエストをうけたので探してみた。
それっぽいのはあったんだけどまあ、100%ってものがなかったのでとりあえず自作。
一週間で上書きっていう簡単なやつにしてみたよ。

Shellスクリプトもいろいろ面白いでつね。
#!/bin/sh
#DAYは数字で曜日。
DAY=`date '+%w'`
WORK_DIR=バックアップするディレクトリ
FILE_NAME=dump_$DAY
BACKUP_DIR=/tmp/
USER=DBのユーザ名
PASS=DBのパスワード
DB_NAME=データベース名

#バックアップディレクトリに移動
cd $BACKUP_DIR
#バックアップディレクトリがなかったら
if [ ! -d $WORK_DIR ]; then

	#ディレクトリを作成する
	mkdir $WORK_DIR
fi

#そのディレクトリに入る
cd $WORK_DIR
#事前にあったファイルは全部消す
rm ./*

#データベース内にあるテーブルリストを作成し、個別にテーブルのダンプデータを作成する
#-eはその後コマンドを実行するというオプション。
#-Bは余計な表示をせずに一覧を出力させる。
#-Nは一番上の見出しを削除する
for TABLENAME in ` mysql -u $USER -p$PASS -B -N -e 'show tables' $DB_NAME`
do
	#echo $TABLENAME
	mysqldump --opt -c -u $USER -p$PASS -x $DB_NAME $TABLENAME > $TABLENAME.sql
done

#移動する
cd $BACKUP_DIR

#該当する日付のディレクトリをまるごと圧縮する
tar -czf $DB_NAME$DAY.tar.gz $WORK_DIR

Containable Behaviorを追いかけてみました。

cakephp 1.3.3で開発しております。
今回は先日わたくしがハマった事象についてお話します。多少書きなぐり気味ですが><許してください。

前提条件

1.A_controllerでpaginateしている
2.paginate対象のモデル(User)には色々なモデルが関連付けられているが、その1部であるHogehogeというモデルをLEFTJOINではなく、INNERJOINで連結したいので一度unbindする
3.このメソッドが呼ばれる前にapp_controllerのbeforeFilter()にUserモデルで検索をかけている箇所がある。そこはContainableBehaviorが使われている

という前提でした。

1.A_controllerのpaginateの箇所はこんなかんじ。

$this->User->unbindModel(array('belongsTo'=>array('Hogehoge')), false);//第2引数をfalseにすることでモデルの関連性を維持させる

			'joins'=>array(
				array(
					'type'	=>'INNER',
					'fields'=>array('Hogehoge.name'),
					'table'=>'`Hogehoges`',
					'alias'=>'`Hogehoge`',
					'conditions'=>array(
						'Hogehoge.id = Hogehoge.user_id',
					),
				),
			),
//このあとpaginate実行

でハッピー! にならなかった・・・というお話。

 

“Containable Behaviorを追いかけてみました。” の続きを読む

javascriptでtextareaに値をセットしたい

ビールのんで帰ってきたので放置せずにこれだけは書いて寝よう。
やりたいこと。

DB上で登録したテンプレートなる文書のデータを、subjectだけ一覧で見せたい。
そんで、その一覧のsubjectをクリックしたら、テンプレートの内容をtextareaにセットしたい。

…たったこれだけ。
やってみたことはリンククリック時にわざわざDB通信するのもなんなので…ちょっとダサいけど、ページ出力時にテンプレートの内容はDIVで区切ってどっかに出力させて、かつ表示させない(display=none)にして、リンククリックしたらそのDIVの中身をテキストエリアにセットする、という流れ。

ところが、Chromeだとちゃんと見えるのにIE(7)だと、テンプレート内の改行が全部、すっ飛ばされてしまう!
で、ググると出てくる、出てくる。そもそもinnerHTMLには適用されないだの、textareaがUNKOだとか、IE・・・?とか色々でてくるんですけど、これ!っていう情報が出てこない。なんつーか文字コードと混同してる(私が)感じで情報が切り分けられず、phpで文字コードを変換してみたりとか色々したけどもうだめびーるのみたいしさいきん体組成系かってふとったしビールのみたいし。

で、DIVタグなのがいけないのかと思ってたので、仕方ないのでinputタグで出力し、それを見せない、みたいなことをやってみたんだけど、どうにもこうにもダメ。text()でやるとうまくいった、とかいろいろあったんだけどもうだめぽ…と思ったんですが最終的に一番楽そうな手段が見つかったので、備忘録的にメモ。これが最適手段ではないと思いますが、もし他の方法をご存知の方がいらしたら「っへ!こんなのもあるでよ!」って教えてくれるとありがたい。

結論からいうとですね、DIVタグではなくて、テンプレートの内容をあらかじめtextareaに書き出しました。そして上記のようにdispayをnoneにして非表示にし、この値をjQueryで言うところのval()で取得し、セットもval()で行いました。そうするとIEだろうがChromeだろうが、改行がきちんと判断されるようになりましたとさ。


$(document).ready(function() {
// bind 'Form' and provide a simple callback function
$(".template").click(function(event){
$('.comment').val($("textarea.setText" + $(this).attr('id')).val());
return false;
});
});

こんなかんじで、セットする元のテンプレート内容は

	if(isset($document)){
		//改行処理があるため、セットする要素と同じtextareaで対処する
	    foreach($template as $key=>$value) {
			echo "<textarea style='display:none' class='setText{$value['Template']['id']}'>";
	    	echo $value['Template']['content'];
			echo '</textarea>';
	    	
	    }
	}

こんなかんじで対処しました。他にもっと良い方法あるよ!って人は是非。いやーこれ解決するのにすんごい時間かけてしまったよ…とほほ。

※21日はCakeAdvent2010 なんで最近はまったcontainableとunbindのくだりを書く予定です。よろしくお願いします。

TortoiseGit &VirtualBox

今まで、サービスインしたサイトは社内ではxamppで開発し、社内で別途構築したCenOS上にデプロイし、本番機にアップ…という流れでした。ところが、巷では結構このxamppさん、あまり好かれてない。導入も楽だし、簡単な設定ですぐ動く。でもあまり好かれていない…で。会社で第2弾のサービスを立ち上げるにあたって社内の開発環境を少し変えてみることにした。

びふぉあ

  • xamppでWindow上で開発
  • DBだけは社内のテストサーバーにあるmysqlを参照(共有)
  • バージョン管理はSVN(TortoiseSVN)
  • タスク管理は完全独立でbacklog
  • あふたー

  • virtualBoxでローカルでの開発
  • DBもVirtualBox上にローカルでお好きにどうぞ
  • テスト環境は変わらず。
  • バージョン管理はgit(TortoiseGit)
  • タスク管理はredmineを導入し、gitと連動する形にする
  • ここで今回私が社内で悪戦苦闘したVirtualBoxのインポートと、Gitの接続時にしくじったことをメモ書き。

    “TortoiseGit &VirtualBox” の続きを読む