FuelPHPを使ったリレーションがやっとわかったのでメモしておきます。
要件は下記の通り。
テーブル「カード」と、
テーブル「ユーザーが所持するカード一覧」の2種類を用意し、
特定のユーザーが持っているカードだけ抽出する
まずは「カード」のテーブルを作成します。
カードID、カード名だけの単純なテーブルです。
CREATE TABLE `testdb`.`table_card` ( `cardid` VARCHAR( 32 ) NOT NULL UNIQUE, `name` VARCHAR( 256 ), INDEX ( `cardid` ) ) ENGINE = MYISAM ;
次にユーザーが所有するカードの一覧のテーブルです。
こちらもシリアル、ユーザーID、カードID、枚数だけの単純なもの。
CREATE TABLE `testdb`.`table_userscard` ( `id` SERIAL NOT NULL DEFAULT NULL UNIQUE, `userid` VARCHAR( 256 ), `cardid` VARCHAR( 32 ), `count` INT, INDEX ( `id` ) ) ENGINE = MYISAM ;
単純な \Fuel\Core\Model_Crud ではなく、\Orm\Model を使います。
ORM(オブジェクトリレーショナルマッパー)はざっくり言うと“リレーションを組むのに便利なモデル”です。
ORMを使うには事前に準備が必要になります。
≫Introduction - Relations - Orm Package - FuelPHP Documentation
≫FuelPHPのORM(オブジェクトリレーショナルマッパー) | WinRoad徒然草
≫FuelPHPをやってみる (8) - Orm\Modelを試す - - kinjou_jのメモログ
いよいよORMを継承したクラスを作ります。
まずはユーザーの所有カード。
バリデーションの設定など色々行えますが、ここではシンプルに。
fuel/app/classes/model/userscard.php
class Model_Userscard extends \Orm\Model{ protected static $_table_name = 'table_userscard'; protected static $_primary_key = array('id'); protected static $_propeties = array( 'id', 'userid', 'cardid', 'count' ); }
そしてリレーションを設定するカードのモデル。
fuel/app/classes/model/card.php
class Model_Card extends \Orm\Model{ protected static $_table_name = 'table_card'; protected static $_primary_key = array('cardid'); protected static $_propeties = array( 'cardid', 'name' ); /********************************** * リレーション:一対多 */ protected static $_has_many = array( 'owncard' => array( 'model_to' => 'Model_Userscard', 'key_from' => 'cardid', 'key_to' => 'cardid', 'cascade_save' => false, 'cascade_delete' => false ) ); }
key_from、key_toで結合する項目を指定しています。
また、cascade_save、cascade_deleteは「false」にして、カード情報を変更や削除しても、所有情報には影響が出ないようにしています。
そしていよいよ本番! リレーションを使い、かつ、リレーション内での絞り込みです。
$results = Model_Card::find( 'all', array( 'related' => array( 'owncard' => array( // リレーション条件を指定 'where'=> array( // リレーション内での検索 array( 'userid', '=', 'ABC12345' ) ) ) ), // table_card 側での検索はこっちに記述 // 'where' => array( // array( 'exp' => 3 ) // ), 'order_by' => array( 'cardid'=> 'asc' ) ));
モデル内で作成したリレーション条件名を「related」で指定し、
その中で同じように「where」を指定するだけなのですが、
これがなぜか情報が見付かりませんでした。^^;
同じ状況で悩んでいる方のお役に立てればと。
\Orm\Model を継承した場合と、\Fuel\Core\Model_Crud を継承した場合ではメソッド名も違いますし、取得できるデータ形式もだいぶ違いますので注意が必要です。
一度 var_dump() で確認してみてください。
FuelPHPで端末によって表示を切り替える方法はいくつかあるようですが、
一番簡単なのは Themeクラスを使うことです。
今回の要件は下記の通り。
fuel + app + classes | + controller | + list.php ←コントローラー | + view + template_pc.php ←PC用テンプレート + template_mobile.php ←携帯用テンプレート + pc ←PC用テーマディレクトリ | + list | + index.php | + mobile ←携帯用テーマディレクトリ + list + index.php
まずは初期化部分。
class Controller_List extends Controller{ function before(){ parent::before(); // テーマ設定 $this->theme = Theme::instance( 'custom', array( 'active' => "pc", // 存在するテーマディレクトリを指定 'fallback' => 'pc', // activeが存在しない場合に使うテーマ 'paths' => array(APPPATH.'views'), // 検索パス 'view_ext' => '.php' // テーマファイル拡張子 ) ); // モバイル端末ならテンプレート変更 // iPadは除外 if (Agent::browser() != "iPad" && Agent::is_mobiledevice()){ $this->theme->active('mobile'); $this->theme->set_template('template_mobile'); }else{ $this->theme->active('pc'); $this->theme->set_template('template_pc'); } }
いったんインスタンスを作る時に active を指定しないとエラーになるので、
PC向けのテーマ(active)を指定して、後から変更しています。
FuelPHPの Agentクラスでは iPadもモバイル端末扱いなのですが、
iPadは PCと同じほうがいいですよねw
続いて表示部分。
public function action_index() { $this->theme->template->title = "ページタイトル"; $this->theme->template->content = $this->theme->view('list/index', Array( 'hoehoe' => 'ほえほえ' )); return $this->theme; }
タイトルと、テーマ内で使う変数を指定しています。
最後にテーマを返すことで表示させます。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title><?php echo $title; ?></title> </head> <body> <?php echo $content; ?> <p>PC用</p> </body> </html>
リスト表示するテーマ <?php echo $hoehoe; ?>
このへんを参考にしました。
≫FuelPHPのテーマクラスのサンプル - BTT's blog
≫FuelPHPのテーマクラス | WinRoad徒然草
この記事のサンプルでは Controllerクラスを継承した方法を使っていますが、Controllerクラスを拡張した Controller_Templateを使う方法もあります。
テンプレートコントローラーでは変数「$template」でテンプレートを指定することが出来ます。
class Controller_Entry extends Controller_Template{ public $template = 'template_pc';
画面の反映はテーマを使ったのと同じ様なものです。
サンプルでは Controllerクラスを継承していたので return で表示内容を返す必要がありましたが、Controller_Templateクラスを継承している場合その必要はありません。
$this->template 内のものが自動的に表示されます。
$this->template->content = $this->Theme->view( 'list/index', array('hoehoe'=>'ほえほえ') );
テーマの設定を使って切り替える方法もあるようです。
インストールはこのへんを参考にしました。
≫【PHP】Xdebugを利用したデバッグ環境構築(5.3)
Microsoft Visual C++ 2008 再頒布可能パッケージが必要
≫【PHP】Xdebugを利用したデバッグ環境構築(php5.2)
どのDLLが必要なのか。
≫XAMPPでXDebugを有効にする。 - ぐだぐだ日記
php.iniの設定
≫PHP向けのNetBeans IDEのエディタでのPHPソース・コードのデバッグ
しかしどうやってもインストールできない!!!
おっかしいなーとコマンドプロンプトで「php.exe -v」すると「with Xdebug」の文字が。
インストールできてんじゃん!
でも phpinfo() だと出てこない。なんでだろ? と思ったら
php.ini 自体が違っていて……。
コマンドプロンプトで実行するときは下記を。
C:\Program Files (x86)\Ampps\php\php.ini
Apacheから実行する時は下記を読んでいたんですね。
C:\Program Files (x86)\Ampps\apache\php.ini
そりゃ動かないわーーー!!
以前 FuelPHPのメール文字化け対策の記事を書きましたが不完全でした。
今度こそ対策ができた(と思う)のでまとめたいと思います。
FuelPHPからメールを送ったら Gmailでは正常に読めたのに、携帯では文字化けしてしまったのでその対処法をメモしときます。
といってもまた場当たり的な対処な感じですが。
先ほど書いた [FuelPHP]デフォルト以外のデータベースを利用する ですが、正しい方法を教えていただきました。そもそも FuelPHPには設定を切り替えるための簡単な方法がありました。
fuel/app/config/ → 共通設定
fuel/app/config/development/ → 開発用設定
fuel/app/config/production/ → 公開(製品)用設定
という感じになっており、development/db.php に開発環境の、production/db.php に公開環境のDB設定を記述すればいいのでした。設定名も「default」のままで。
そして環境を切り替えるには、fuel/app/bootstrap.php を下記のように編集するだけです。
/** * Fuel::DEVELOPMENT 開発環境 * Fuel::TEST テスト環境 * Fuel::STAGE ステージング環境 * Fuel::PRODUCTION 製品環境 */ Fuel::$env = (isset($_SERVER['FUEL_ENV']) ? $_SERVER['FUEL_ENV'] : Fuel::PRODUCTION);
末尾の名前を書き換えるだけなんですね。便利。
.htaccessで切り替える方法もあるようです。
参考:インストール方法 - インストール - FuelPHP ドキュメント
SetEnv FUEL_ENV production
環境変数「FUEL_ENV」を「development」にすれば開発環境なわけですね。
初期状態で作業をしているとURLは
http://hoge.com/mailform/index.php/entry/confirm
のようになり、「index.php」がURLに含まれてしまいます。
個人的にはちょっと美しくないなあと思うので消すことにしました。
まずはFulePHPインストールディレクトリの .htaccess を下記のようにします。
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 [L] </IfModule>
次に fuel/app/config/config.php を下記のように編集します。
//'index_file' => 'index.php', 'index_file' => false,
これでURLは下記のようになるはずです。
http://hoge.com/mailform/entry/confirm
修正記事を書きましたので、そちらをご覧下さい。(2012.09.14)
FuelPHPからメールを送ったら Gmailでは正常に読めたのに、携帯では文字化けしてしまったのでその対処法をメモしときます。
といってもまた場当たり的な対処な感じですが。
【追記】正しい方法を教えていただいたので修正記事を書きました。
データベースの接続設定を default から任意の名前の設定に切り替える方法。
解決方法というより、こうしたら出来ましたーというメモです。
本当はもっとスマートなやり方があると思います。
いわゆるCSRF対策のメモです。
Webでのデータ登録には
入力 → 確認 → 完了 という3つのフェーズで行うのが一般的です。
中でも最後の「完了」でデータ登録を行うことが多いため、
このページでリロードを行われると重複登録になったり、
前2フェーズを飛ばして不正なフォームをPOSTしてくるなどの
対策をする必要があります。
今まではセッションを使うなどして自前でコードを書く必要がありましたが、
FuelPHPでは Securityクラスを使うことで簡単に行えます。
確認画面のフォーム部分に下記を追加します。
echo Form::hidden( Config::get('security.csrf_token_key'), Security::fetch_token() );
下記のような隠し項目が書き出されます。
<input name="fuel_csrf_token" value="8af49a49ef926ca20fb713542c258fb4" type="hidden" id="form_fuel_csrf_token" />
そして登録を行うコントローラーで下記のように振り分けます。
if( !Security::check_token() ){ // エラー表示 }else{ // 正常なデータ登録 }
下記のサイトでは様々なセキュリティ対策について書かれてます。
CSRF対策についてはこちらの記事が良いかもしれません。
PHPには標準で $_SESSIONが用意されていますが、FuelPHPにもセッション管理用に
Sessionクラスが用意されています。
セッションの書き込みには Session::set() を使います。
名前と内容のペアを渡すだけなので簡単です。
Session::set( 'name', 'hogehoge' ); Session::set( 'characters', array( 'haruka', 'chihaya', 'miki', 'yayoi' ) );
2行目のように、オブジェクトを渡すこともできます。
連想配列や、多次元配列でも可能です。
取り出すには Session::get() を使います。
$name = Session::get( 'name' ); $characters = Session::get( 'characters' ); $all_sessions = Session::get(); $nodata = Session::get( 'no_exists', 'hogehoge' );
3行目:引数がない場合は全てのセッションデータを取得する。
4行目:セッションが存在しない場合の初期値を指定。
削除は Session::delete( 'name' ); という感じで行います。
set_flash()、get_flash()
というメソッドもあります。
set() で作ったセッションはしばらく残りますが、
set_flash() で作ったものは一度使うと消えるようです。
Session::set_flash( 'name', 'azunyan' ); $name = Session::get_flash( 'name' ); Session::delete_flash( 'name' );
set()、get()、delete()と使い方は同じですね。
今回はこちらの記事を参考にさせていただきました。
というかほぼそのままです。
初期状態ではセッション情報をクッキーに保存しているので、ファイルに書き出すようにします。
fuel/core/config/session.php を fuel/app/config/session.php にコピーします。
エディタで下記のように編集します。
'driver' => 'file',
ファイルの保存場所が「/tmp」になっていますが、自分は Windows環境でテストしたいので
FuelPHP管理下のフォルダに作ることにします。
'file' => array( 'cookie_name' => 'fuelfid', 'path' => APPPATH.'/tmp', 'gc_probability' => 5 ),
設定ファイル session.php の下記部分を「db」に修正します。
'driver' => 'db',
dbにセッション専用のテーブルを作成します。
下記SQLで作成できるようです。
CREATE TABLE IF NOT EXISTS `sessions` (
`session_id` varchar(40) NOT NULL,
`previous_id` varchar(40) NOT NULL,
`user_agent` text NOT NULL,
`ip_hash` char(32) NOT NULL DEFAULT '',
`created` int(10) unsigned NOT NULL DEFAULT '0',
`updated` int(10) unsigned NOT NULL DEFAULT '0',
`payload` longtext NOT NULL,
PRIMARY KEY (`session_id`),
UNIQUE KEY `PREVIOUS` (`previous_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
ドキュメントによるとメモリキャッシュに書き出すこともできるみたいですね