10分でFuelPHPの基礎を理解する
- 作者: 早川聖司
- 出版社/メーカー: ソーテック社
- 発売日: 2012/06/02
- メディア: 単行本
- 購入: 10人 クリック: 192回
- この商品を含むブログ (9件) を見る
様々な技術を求められる開発現場
じゃあ、いつRails始めるの?... 今でしょ! - Yuta.Kikuchiの日記
様々な開発現場でそこに必要な技術を求められていて四苦八苦中の@yutakikucです。ついこの前Railsのエントリーを書いたばかりなのに今度はFuelPHPについて調べなければいけなかったり...僕の体はいつ休まるんだろうか。FuelPHPもRailsと似ているところが多いのでRailsを学習した記憶が新しいうちにFuelPHPについて学んだことをどんどん書いていこうと思います。Railsに比べると少し設定が面倒なんで、ハマった方の少しでも参考になればと思います。
Index
FuelPHP Setting
Nginx WebServer
CentOSでNginxのログをFluentdを使ってMongodbにリアルタイムで格納する - Yuta.Kikuchiの日記
FuelPHPを動かす環境をNginxを利用します。CentOSでのNginxの設定は上のエントリーを確認しながらやってみてください。ここではProcessが立ち上がっていることの確認とphp-fpmのCGI設定について記述します。プロセスの確認はpsコマンドで、php-fpmはWebでPHPを利用するためのCGIパッケージでyumにて最初にinstallしておくと良いでしょう。
先にエントリポイントについて少し説明をしていおくとnginxの設定でrootを/usr/share/nginx/html/fuel_sample/publicとし、fuelのエントリポイントとなるパスを指定します。fuel_sampleは後で定義するプロジェクト名です。/usr/share/nginx/html/fuel_sample/public直下に.htaccessファイルが生成されそちらでもaccessの設定が編集できますが、今回はnginx側で全て対応させます。
fastcgi_param FUEL_ENV development;の箇所でFuelの環境に合わせた設定変更ができます。FUEL_ENVをアプリケーション側が自動で読み込んで、fuel/app/config//config.phpのような設定ファイルを切り替えます。設定を変更したらnginx/php-fpmの両方を再起動します。またnginx/php-fpm/mysqldを全て自動起動設定を入れておきます。 $ /usr/share/nginx# ps auxw | grep nginx root 1879 0.0 0.0 44688 848 ? Ss 01:05 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 1881 0.0 0.1 45096 1548 ? S 01:05 0:00 nginx: worker process$ sudo yum install php-fpm -y $ sudo vim /etc/nginx/conf.d/default.confserver { listen 80; server_name localhost; root /usr/share/nginx/html/fuel_sample/public; index index.php; location / { try_files $uri /index.php?$uri&$args; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param FUEL_ENV development; include fastcgi_params; } }$ sudo vim /etc/php-fpm.d/www.conf; user,groupをapacheからnginxに変更 ; RPM: apache Choosed to be able to access some dir as httpd user = nginx ; RPM: Keep a group allowed to write in log dir. group = nginx$ sudo /etc/init.d/nginx restart nginx を停止中: [ OK ] nginx を起動中: [ OK ] $ sudo /etc/init.d/php-fpm restart php-fpm を停止中: [ OK ] php-fpm を起動中: [ OK ] $ sudo /sbin/chkconfig nginx on $ sudo /sbin/chkconfig php-fpm on $ sudo /sbin/chkconfig mysqld onoil Install / oil create
gitをinstallしておきます。Centosのgit-install時にPackageの依存関係のエラーがでるので--disablerepo=epelのオプションを指定してinstallします。その次にoilコマンドをダウンロードします。oilはRailsで言うrakeコマンドのようなものです。Projectを作成したりModel/View/Controllerを生成したり、Scaffoldができたり、DBMigrationができます。oilのダウンロードが完了したらoil create でfuel_sampleというProjectを作成します。NginxのDocumentRootはDefaultでは/usr/share/nginx/html
$ sudo yum install git --disablerepo=epel -y $ curl get.fuelphp.com/oil | sh $ cd /usr/share/nginx/html $ sudo oil create fuel_sampleError - date_default_timezone_get()
/etc/php.iniでdefaultのtimezoneが指定されていない場合は修正します。
[Date] ; Defines the default timezone used by the date functions ; http://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone ;date.timezone = date.timezone = "Asia/Tokyo"DB設定
fuel_sample/fuel/app/config/
/db.phpとして生成されているdbの設定ファイルを修正します。接続username、passwordを自分の環境に合わせて適宜設定をする必要があります。FuelはORMというDB接続クラスを用意しているのでORMを使えるようにcoreのconfig.phpをormをコメントインします。またoil refineコマンドでmigrationをしようとするとerrorが出てしまうので、先に環境に合わせたdbをcreateしておきます。ここでは開発環境のdevelopmentの説明を前提に記述します。
fuel_sample/fuel/app/config/development/db.php<?php /** * The development database settings. These get merged with the global settings. */ return array( 'default' => array( 'connection' => array( 'dsn' => 'mysql:host=localhost;dbname=fuel_dev', 'username' => 'root', 'password' => '', ), ), );fuel_sample/fuel/core/config/config.php
<?php /**************************************************************************/ /* Always Load */ /**************************************************************************/ 'always_load' => array( /** * These packages are loaded on Fuel's startup. * You can specify them in the following manner: * * array('auth'); // This will assume the packages are in PKGPATH * * // Use this format to specify the path to the package explicitly * array( * array('auth' => PKGPATH.'auth/') * ); */ 'packages' => array( 'orm', ),mysql> create database fuel_dev; Query OK, 1 row affected (0.00 sec)Scaffoldで雛形を作る
今回はnoteを作成/編集/詳細表示/一覧表示することを考えます。Scaffoldでは特定のURL/Directoryのルールに従ってコードを自動生成してくれます。noteで扱うデータはtitle/descriptionの2種類を定義します。oil generate sfaffold module
: のような文法です。生成される名前のルールとしてDBはnotesのような名詞の複数形になります。 $ sudo oil generate scaffold note title:varchar[255] description:text Creating migration: /usr/share/nginx/html/fuel_sample/fuel/app/migrations/001_create_notes.php Creating model: /usr/share/nginx/html/fuel_sample/fuel/app/classes/model/note.php Creating controller: /usr/share/nginx/html/fuel_sample/fuel/app/classes/controller/note.php Creating view: /usr/share/nginx/html/fuel_sample/fuel/app/views/note/index.php Creating view: /usr/share/nginx/html/fuel_sample/fuel/app/views/note/view.php Creating view: /usr/share/nginx/html/fuel_sample/fuel/app/views/note/create.php Creating view: /usr/share/nginx/html/fuel_sample/fuel/app/views/note/edit.php Creating view: /usr/share/nginx/html/fuel_sample/fuel/app/views/note/_form.php Creating view: /usr/share/nginx/html/fuel_sample/fuel/app/views/template.phpmigraionファイルはDBの初期設定を行うためのものです。oil refine migrateでDBの設定を行います。念のためmigraionファイルがどのようなものかを確認します。またoil refine migrateを行った後はDBのtableが作成されたかどうかを見ます。
fuel_sample/fuel/app/migrations/001_create_notes.php<?php namespace Fuel\Migrations; class Create_notes { public function up() { \DBUtil::create_table('notes', array( 'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true, 'unsigned' => true), 'title' => array('constraint' => 255, 'type' => 'varchar'), 'description' => array('type' => 'text'), 'created_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), 'updated_at' => array('constraint' => 11, 'type' => 'int', 'null' => true), ), array('id')); } public function down() { \DBUtil::drop_table('notes'); } }$ sudo oil refine migrate Performed migrations for app:default: 001_create_notes $ mysql -u root -p mysql> use fuel_dev; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +--------------------+ | Tables_in_fuel_dev | +--------------------+ | migration | | notes | +--------------------+ 2 rows in set (0.00 sec) mysql> show create table notes; +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | notes | CREATE TABLE `notes` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `description` text NOT NULL, `created_at` int(11) DEFAULT NULL, `updated_at` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)Mysqlの設定にもよりますがmigrationを実行すると残念ながらDefaultではENGINE = MyISAMとして設定されてしまうようです。migraionファイルを修正することによってENGINEやCHASETを自由に書き換えることができます。下はmigrationファイルから呼び出しているDBUtilクラスのcreate_tableメソッドです。5/6番目の引数でENGINEとCHARSETが指定出来ます。
fuel_sample/fuel/core/classes/dbutil.php<?php /** * Creates a table. * * @throws \Database_Exception * @param string $table the table name * @param array $fields the fields array * @param array $primary_keys an array of primary keys * @param boolean $if_not_exists whether to add an IF NOT EXISTS statement. * @param string $engine storage engine overwrite * @param string $charset default charset overwrite * @param array $foreign_keys an array of foreign keys * @return int number of affected rows. */ public static function create_table($table, $fields, $primary_keys = array(), $if_not_exists = true, $engine = false, $c harset = null, $foreign_keys = array(), $db = null)Routingの設定
URIの規則で重要な役割を果たしているのがroutes.phpです。ここでアクセスしたURIと呼び出したいControllerとメソッドを指定することができます。_root_はBaseURIになります。下の例でいうとhttp://localhost/helloにアクセスすると内部的にはhttp://localhost/welcome/helloを呼び出していることになります。
<?php return array( '_root_' => 'welcome/index', // The default route '_404_' => 'welcome/404', // The main 404 route 'hello(/:name)?' => array('welcome/hello', 'name' => 'hello'), );Crypt Key Error
ここまで設定できたらScaffoldで作成されたnoteにアクセスしてみます。http://localhost/note/createにアクセスすると、Crypt Key Errorという画面が出てしまいます。暗証Keyをどうやら手動で設定する必要があるようです。画面に出力されたphpコードをconfig直下に配置します。
fuel_sample/fuel/app/config/crypt.php<?php /** * Part of the Fuel framework. * * @package Fuel * @version 1.6 * @author Fuel Development Team * @license MIT License * @copyright 2010 - 2013 Fuel Development Team * @link http://fuelphp.com */ return array ( 'crypto_key' => 'Leg2Qg73448k594xBob-s-wc', 'crypto_iv' => 'j2w-MchSEx7IZUES3QBfkKAQ', 'crypto_hmac' => 'KUQ9hEL6wLsMw1MMKIqDAJ_U', );FuelPHPに接続
http://localhost/note/createに再度アクセスをすると以下の様な画面が出力されると思います。URIの規則は呼び出したいController名/メソッド名という感じになります。ここではnote/createとするとnoteを入力する画面が表示されます。これでNginx上でのFuel設定は完了です。
FuelPHP
以下ではscaffoldされたnoteのMVCを例にFuelPHPの内部構造を少し説明しようと思います。
Coreのライブラリのautoload
fuel/core/classes以下に様々なライブラリがoilでcreateされます。createされたclassesはautoloadされます。autoloadしているファイルはfuel/core/bootstrap.phpのsetup_autoloader()メソッドになります。このautoload機能により様々なファイルで利用されているSession、Input、Viewクラスなどが利用できる事になります。
/usr/share/nginx/html/fuel_sample/fuel/core/classes# tree ├── agent.php ├── arr.php ├── asset │   └── instance.php ├── asset.php ├── autoloader.php ├── cache │   ├── handler │   │   ├── driver.php │   │   ├── json.php │   │   ├── serialized.php │   │   └── string.php │   ├── notfound.php │   └── storage │   ├── apc.php │   ├── driver.php │   ├── file.php │   ├── memcached.php │   └── redis.php ├── cache.php ├── cli.php ├── config │   ├── file.php │   ├── ini.php │   ├── interface.php │   ├── json.php │   ├── php.php │   └── yml.php ├── config.php ├── controller │   ├── hybrid.php │   ├── rest.php │   └── template.php ├── controller.php ├── cookie.php ├── crypt.phpfuel/core/bootstrap.php
<?php function setup_autoloader() { Autoloader::add_namespace('Fuel\\Core', COREPATH.'classes/'); Autoloader::add_namespace('PHPSecLib', COREPATH.'vendor'.DS.'phpseclib'.DS, true); Autoloader::add_classes(array( 'Fuel\\Core\\Agent' => COREPATH.'classes/agent.php', 'Fuel\\Core\\Arr' => COREPATH.'classes/arr.php', 'Fuel\\Core\\Asset' => COREPATH.'classes/asset.php', 'Fuel\\Core\\Asset_Instance' => COREPATH.'classes/asset/instance.php', 'Fuel\\Core\\Cache' => COREPATH.'classes/cache.php', 'Fuel\\Core\\CacheNotFoundException' => COREPATH.'classes/cache/notfound.php', 'Fuel\\Core\\CacheExpiredException' => COREPATH.'classes/cache.php',Controller
FuelのビジネスロジックはControllerがメインです。Controllerのメソッド名はaction_<メソッド名>として定義されます。
Controllerの役割は当然Modelとのデータのやり取りとViewへの流しこみを担います。データを保存する流れとしてはModelクラスで定義したValidateを呼び出し、Validate結果が問題なければModelのsaveメソッドを使ってデータを保存します。
Controller/Viewのルールとして覚えておきたいことは$this->template->content = View::forge('note/index', $data);の箇所でViewに渡すデータの設定を行います。$data[key]は連想配列として渡すことによりView側でkey名の変数で呼び出す事が可能です。例えばaction_indexで$data['notes'] = Model_Note::find('all');$this->template->content = View::forge('note/index', $data);されたデータはnote/indexのView側で$notesとして呼び出すことができます。
fuel/app/classes/controller/note.php<?php class Controller_Note extends Controller_Template{ public function action_index() { $data['notes'] = Model_Note::find('all'); $this->template->title = "Notes"; $this->template->content = View::forge('note/index', $data); } public function action_view($id = null) { is_null($id) and Response::redirect('note'); if ( ! $data['note'] = Model_Note::find($id)) { Session::set_flash('error', 'Could not find note #'.$id); Response::redirect('note'); } $this->template->title = "Note"; $this->template->content = View::forge('note/view', $data); } public function action_create() { if (Input::method() == 'POST') { $val = Model_Note::validate('create'); if ($val->run()) { $note = Model_Note::forge(array( 'title' => Input::post('title'), 'description' => Input::post('description'), )); if ($note and $note->save()) { Session::set_flash('success', 'Added note #'.$note->id.'.'); Response::redirect('note'); } else { Session::set_flash('error', 'Could not save note.'); } } else { Session::set_flash('error', $val->error()); } } $this->template->title = "Notes"; $this->template->content = View::forge('note/create'); }Model
ModelはDataのやり取りをするための仕組みです。ここではDataSourceをDBとしているのでDBModelになります。
Modelの仕組みはとてもシンプルで固有のValidateメソッドを定義するぐらいでDBとのやり取りが出来てしまいます。Modelのルールとしてはprotected static $_propertiesにてDBのカラムを定義、public static function validateとしてどの種別のValidateを掛けるかを定義します。Validationの細かいルールはValidation - Classes - FuelPHP Documentation こちらを参照して下さい。Validationファイルはcore以下のfuel/core/classes/validation.phpになります。noteのModelでは必須とMaxLengthだけをチェックしています。複数の条件してはrequired|max_length[255]のようにパイプでつなぎます。$val->add_fieldの引数は第一引数がValidationしたいカラム名、第二引数がValidationのLabel名、第三引数がRuleになります。fuel/app/classes/model/note.php
<?php use Orm\Model; class Model_Note extends Model { protected static $_properties = array( 'id', 'title', 'description', 'created_at', 'updated_at', ); protected static $_observers = array( 'Orm\Observer_CreatedAt' => array( 'events' => array('before_insert'), 'mysql_timestamp' => false, ), 'Orm\Observer_UpdatedAt' => array( 'events' => array('before_save'), 'mysql_timestamp' => false, ), ); public static function validate($factory) { $val = Validation::forge($factory); $val->add_field('title', 'Title', 'required|max_length[255]'); $val->add_field('description', 'Description', 'required'); return $val; } }View
Viewはとてもシンプルです。覚えておくべきことはcoreライブラリのViewクラスで定義されたメソッドを呼び出している箇所がありますが、ViewHelperとしての機能だと思ってもらえれば問題ありません。その他for/foreach/ifなどの制御コードをif ($notes): 〜 endif; やforeach ($notes as $note): 〜endforeach; のように定義するところだけを覚えておけばいいと思います。
<h2>Listing <span class='muted'>Notes</span></h2> <br> <?php if ($notes): ?> <table class="table table-striped"> <thead> <tr> <th>Title</th> <th>Description</th> <th> </th> </tr> </thead> <tbody> <?php foreach ($notes as $note): ?> <tr> <td><?php echo $note->title; ?></td> <td><?php echo $note->description; ?></td> <td> <?php echo Html::anchor('note/view/'.$note->id, '<i class="icon-eye-open" title="View"></i>'); ?> | <?php echo Html::anchor('note/edit/'.$note->id, '<i class="icon-wrench" title="Edit"></i>'); ?> | <?php echo Html::anchor('note/delete/'.$note->id, '<i class="icon-trash" title="Delete"></i>', array('onclick' => "return confirm('Are you sure?')")); ?> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php else: ?> <p>No Notes.</p> <?php endif; ?><p> <?php echo Html::anchor('note/create', 'Add new Note', array('class' => 'btn btn-success')); ?> </p>Security/htmlentities
FuelPHPでは出力時にhtmlentitiesの関数を使ってサニタイジングを行なっています。これはControllerでView::forgeにてデータをセットした時に自動的にサニタイジング処理が走ります。呼び出しの定義はfuel/app/config/config.phpで定義されています。サニタイジングせずにsafedataとして出力したい場合はController側で$this->template->set_safeメソッドにより格納することができます。
fuel/app/config/config.php<?php /** * This output filter can be any normal PHP function as well as 'xss_clean' * * WARNING: Using xss_clean will cause a performance hit. * How much is dependant on how much input data there is. */ 'output_filter' => array('Security::htmlentities'),