当初、ソース内にValidation::factory()と記述をしていましたが、近々廃止予定とのことです。
Validation::forge()を使うべきとご指摘を頂きました。有難うございます。
当記事の該当箇所について、修正してあります。
FuelPHP Advent Calendar 2011 11日目です。
@madmamor です。
前日の @kenji_s さんの
FuelPHP での Migration の使い方
でもご紹介頂いたとおり、今回は、Facebookアプリの実装編です。
尚、先にこちらをお読み下さるよう、お願いします。
FuelPHPでFacebookアプリを作ってみよう。準備編。
今回実装する機能は
* Facebookでのログイン/ログアウト機能
* Facebook情報のDB保存(バリデーション付き)
* Facebookのウォール投稿機能(バリデーション付き)
です。
各項にポイントを書いています。
では、一気にいきましょう。
【DBとテーブルを作成】
MySQLを使います。DB名はfuelfb。テーブル名はusers。とします。
尚、今回、Facebook情報はusersテーブルに保存するのみです。
検索して使用する。という処理は組み込みませんが、DB周りの機能紹介を兼ねて、記載します。
create database fuelfb; create table fuelfb.users ( id int not null auto_increment, created_at int not null, updated_at int not null, facebook_id varchar(255) not null unique, facebook_name varchar(255) not null, facebook_link varchar(255) not null, primary key (id) );【ポイント】
idはFuelPHPが定める主キーカラム名です。
created_atはFuelPHPが定めるレコード作成時刻カラム名です。
updated_atはFuelPHPが定めるレコード更新時刻カラム名です。
created_atとupdated_atはデフォルトだとUNIXタイムスタンプとなります。
datetime型にすることも可能ですが、今回はint(UNIXタイムスタンプ)で。
その他のカラムは、Facebook認証時に取得するデータ用のカラムです。
ユーザ入力ではありませんが、外部データなので、制約は緩めにしてあります。
【ORMモデルを作成】
前述のusersテーブルに対するモデルです。
fuel/app/classes/model/user.phpを作成。
<?php namespace Model; class User extends \Orm\Model { protected static $_observers = array( 'Orm\Observer_CreatedAt' => array('events'=>array('before_insert')), 'Orm\Observer_UpdatedAt' => array('events'=>array('before_save')), 'Orm\Observer_Validation'=> array('events'=>array('before_save')), ); protected static $_properties = array( 'id', 'created_at', 'updated_at', 'facebook_id' => array( 'validation' => array( 'trim', 'required', 'max_length' => array(255), 'valid_string' => array('integer'), ), ), 'facebook_name' => array( 'validation' => array( 'trim', 'required', 'max_length' => array(255), ), ), 'facebook_link' => array( 'validation' => array( 'trim', 'required', 'max_length' => array(255), ), ), ); }【ポイント】
今回は、Orm\Modelを継承したモデルとします。
$_observersで、様々な振る舞いを指定可能です。
今回は、created_at値、updated_at値の自動登録と、
insert or update前のバリデーション自動実行。を設定しています。
$_propertiesでカラム毎にバリデーションを定義可能です。
バリデーションは、"単一のStringを受け、Stringを返却するPHP関数"を指定可能です。
今回は、trimを設定しています。
$_propertiesには全てのカラムを記述して下さい。エラーとなります。
【ORMパッケージの有効化】
fuel/app/config/config.phpを修正
'packages' => array( //'orm', ),↓
'packages' => array( 'orm', ),【ポイント】
前述のORMモデルが使用可能となります。
【DB接続情報を設定】
fuel/app/config/development/db.phpを修正
<?php /** * The development database settings. */ return array( 'default' => array( 'connection' => array( 'dsn' => 'mysql:host=localhost;dbname=fuel_dev', 'username' => 'root', 'password' => 'root', ), ), );↓
<?php /** * The development database settings. */ return array( 'default' => array( 'type' => 'mysql', 'connection' => array( 'hostname' => 'localhost', 'port' => '3306', 'database' => 'fuelfb', 'username' => 'root', 'password' => '', ), ), );【ポイント】
必要に応じて、接続情報は書き換えて下さい。
【ビューの修正】
fuel/app/views/index/index.phpを修正
<p>Index</p> <?php if ($is_login): ?> <a href="http://127.0.0.1/fuelfb/public/index/logout">Log out.</a> <?php else: ?> <a href="http://127.0.0.1/fuelfb/public/index/login">Login with Facebook.</a> <?php endif; ?>↓
<?php if ($is_login): ?> <?php echo(Form::open('index/index/'))?> <?php echo(Form::textarea('message'))?> <?php echo(Form::submit('submit','Post to Facebook'))?> <?php echo(Form::close())?> <a href="http://127.0.0.1/fuelfb/public/index/logout">Log out.</a> <?php else: ?> <a href="http://127.0.0.1/fuelfb/public/index/login">Login with Facebook.</a> <?php endif; ?>【ポイント】
ログインしていれば入力フォームとログアウトリンクを表示します。
ログインしていなければログインリンクを表示します。
判断基準の$is_loginは後述のコントローラでセットします。
【コントローラに機能を実装】
fuel/app/classes/controller/index.phpを修正
<?php require_once APPPATH.'vendor/facebook-php-sdk/src/facebook.php'; class Controller_Index extends Controller_Template { private $fb; public function before() { parent::before(); $this->fb = new Facebook(Config::get('facebook.init')); } public function action_index() { $this->template->title = 'Index » Index'; $data = array( 'is_login' => $this->fb->getUser()?true:false, ); $this->template->content = View::forge('index/index',$data); } public function action_login() { exit('TODO : login'); } public function action_callback() { exit('TODO : callback'); } public function action_logout() { exit('TODO : logout'); } }↓
<?php require_once APPPATH.'vendor/facebook-php-sdk/src/facebook.php'; use Model\User; class Controller_Index extends Controller_Template { private $fb; public function before() { parent::before(); $this->fb = new Facebook(Config::get('facebook.init')); } public function action_index() { $this->template->title = 'Index » Index'; $is_login = $this->fb->getUser()?true:false; $data = array( 'is_login' => $is_login, ); if($is_login and Input::method() == 'POST') { $v = Validation::forge(); $v->add('message', 'message')->add_rule('required'); if(!$v->run()) { Session::set_flash('notice', $v->errors('message')->get_message()); } else { $message = $v->validated('message'); try { $res = $this->fb->api(array( 'method' => 'stream.publish', 'message' => $message, )); Session::set_flash('notice', 'complete!!'); } catch (FacebookApiException $e) { Session::set_flash('notice', $e->getMessage()); } Response::redirect('index/index/'); } } $this->template->content = View::forge('index/index',$data); } public function action_login() { $url = $this->fb->getLoginUrl(Config::get('facebook.login')); Response::redirect($url); } public function action_callback() { try { $me = $this->fb->api('/me'); $user = User::find_by_facebook_id($me['id']); if(!$user) $user = new User; $user->facebook_id = $me['id']; $user->facebook_name = $me['name']; $user->facebook_link = $me['link']; $user->save(); Response::redirect('/index/index/'); } catch (Orm\ValidationFailed $e) { throw new Exception($e->getMessage()); } catch (FacebookApiException $e) { throw new Exception($e->getMessage()); } } public function action_logout() { $url = $this->fb->getLogoutUrl(Config::get('facebook.logout')); $this->fb->destroySession(); Response::redirect($url); } }【ポイント】
以下の順を想定して、各メソッドのポイントを記載します。
(1) http://127.0.0.1/fuelfb/public/index/index/ にアクセス。
(2) "Login with Facebook."をクリック。
(3) Facebook認証をして http://127.0.0.1/fuelfb/public/index/index/ に戻ってくる。
(4) Facebookのウォールへ投稿。
(5) ログアウト。
■before()
Facebookオブジェクト($fb)の初期化。全アクションに対しての、事前処理みたいな感じです。
■action_login()
Facebook認証画面にリダイレクトします。
fuel/app/config/custom.phpのfacebook.loginには、
認証後のリダイレクト先とパーミッション設定が設定してあるはずです。
■action_callback()
Facebook認証後のリダイレクト先になります。
$me = $this->fb->api('/me');自身のFacebook情報を取得しています。
$user = User::find_by_facebook_id($me['id']);usersテーブルに対してFacebookのIDで検索を行なっています。
find_by_[カラム名]はFuelPHPのORMが標準に提供する検索機能です。
$user->save();前述のfind_by_facebook_idでデータがヒットしなければinsert。
ヒットすればupdateを行います。
Response::redirect('/index/index/');action_index()へリダイレクトします。
catch (Orm\ValidationFailed $e)ORMモデルにバリデーションルールを書きましたが、それに反する場合、ここに入ります。
今回はユーザ入力データでは無いので、実質発生しないはずです。
なので、画面表示はしていません。
catch (FacebookApiException $e)$this->fb->api('/me'); でエラーが発生した場合、ここに入ります。
その他、FacebookのAPIでエラーが発生した場合も、FacebookApiExceptionが発生します。
■action_logout()
Facebookのセッションを破棄してリダイレクトします。
リダイレクト先はfuel/app/config/custom.phpのfacebook.logout.nextに書いてあるはずです。
■action_index()
if($is_login and Input::method() == 'POST')フォームに入力してsubmitボタンを押すと、この中に入ります。
$v = Validation::forge(); $v->add('message', 'message')->add_rule('required'); if(!$v->run()) { Session::set_flash('notice', $v->errors('message')->get_message()); }必須チェックを行なっています。
入力が空だった場合、エラーメッセージを表示します。
具体的には、fuel/app/views/template.phpの
Session::get_flash('notice')
の箇所で表示されます。
$message = $v->validated('message'); try { $res = $this->fb->api(array( 'method' => 'stream.publish', 'message' => $message, )); Session::set_flash('notice', 'complete!!'); } catch (FacebookApiException $e) { Session::set_flash('notice', $e->getMessage()); } Response::redirect('index/index/');バリデーション完了後のデータを取得して、Facebookのウォールに投稿(stream.publish)します。
FacebookApiExceptionについてはaction_callback()に記載した通りとなります。
最後にリダイレクトしているのは、リロード対策です。
■その他
再現性が乏しいのですが、Facebookの証明書エラーが発生するケースがありました。
その場合、ブラウザの関連するキャッシュをクリアして下さい。
また、XAMPPのApacheを再起動してみて下さい。
これで、私の場合、エラーが発生しなくなりました。
以下、画面キャプチャを掲載しておきます。
まずは、この画面が表示されるはずです。
Login with Facebook.をクリックして、Facebook側に飛びます。
Facebook側の認証画面です。
認証が済むと、今回作成したプログラム側に戻ります。
正しく実装されていると、この画面に戻るはずです。
textareaとpostボタンが表示されます。
postが正常に行われると、"complete!!"と表示されます。
この後、ログアウトをして、最初の画面に戻れば、一通りOKと思います。
以上、実装編でした。
fuel/app/classes/welcome.php等のゴミファイルが残っていたり
fuel/app/config/config.phpのbase_urlが空だったり
その他、色々とやり残したことはありますが、ミニマムな手順は、こんな感じと思います。
有難うございました。
明日の12日目は @mataga さんです。
FuelPHP動作実験 - 実験くんソースをModulesに閉じ込めてモジュール分割してみる。
P.S.
次回は、軽めのネタでいきます。。。
No comments:
Post a Comment