ECサイト運営開発記

PHPフレームワーク Laravelの使い方を中心とした通販サイトの開発日記

Laravel4でArtisanによるCLI開発

Laravel4の便利機能のひとつにArtisanというコマンドラインツールが存在します。
プロジェクトルートにて、php artisan ***** とコマンドを打つことで、様々な命令を実行させることができる機能です。
今回は、とりあえず、CSVデータを読み込んで、DBにデータを保存するサンプルを作っていくことにします。

[下準備と前提条件]

  • CSVファイルは以下の形式とする
  • ファイル名はitem.csv
    • ファイルは app/storage/csv/ に保存する
  • Eloquentクラスを継承したItemクラスはすでに作成済みとする。

[コマンドクラスの作成]

  • プロジェクトルートにて以下のコマンドを実行
    • php artisan command:make ItemImport
      • app/command/ディレクトリにItemImportクラスファイルが生成される。
      • オートロードのクラスマップに反映させるために、composer dump-autoloadもしておきましょう。

[処理を記述]

  • ItemImportクラスファイルを開いて、以下を修正
    • protected $name : artisanコマンドで呼び出す際のコマンド名
    • protected $description : listやhelpを実行した時に表示されるコマンドの説明文
    • getArguments():コマンドが受け取る引数(今回は使いません)
      • 初期状態では、array('example', InputArgument::REQUIRED, 'An example argument.')となっているので、コメントアウト
    • getOptions():コマンドが受け取るオプション(今回は使いません)

-肝心の処理はfireメソッドに記述する。

<?php

class ItemImport extends Command {

  protected $name = 'new-item';
  protected $description = 'New Item Impoert!';

  /* 中略 */
  public function fire(){
    // CSV
    $handle = fopen(storage_path()."/db/item.csv", "r");
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE){
      // Eloquentでデータを挿入
      $item=new Item;
      $item->item_code=$data[0];
      $item->item_name=$data[1];
      $item->item_price=$data[2];
      $item->save();
    }
    echo "Completed!";
  }

  
  protected function getArguments(){
    return array(
      //array('example', InputArgument::REQUIRED, 'An example argument.'),
    );
  }

さぁ、これで使える!と思いきや、実はまだやることがあります。作ったコマンドをアプリケーションに登録しなければなりません。
方法は簡単で、app/start/artisan.phpを開いて、以下のように追加してあげればいいだけです。

<?php

Artisan::add(new ItemImport);

これで、準備OK。プロジェクトルートにて、以下のコマンドを実行

  • php artisan item-import
    • Completed!と表示されていれば、成功です。おめでとうございます。

ORM Eloquentに追加された新機能

Laravel4の正式リリースまであと1ヶ月ちょっとらしい。現在はBeta5の開発段階。
フレームワークとしての仕様もほぼ固まってきて、おそらく、大幅な変更点は無いだろうということでEloquentの新しい機能を紹介します。

  • コレクション
    • Laravel4のEloquentでは、DBからの取得結果をコレクションにして返却してくれるようになりました。
      • Eloquentのコレクションはイテレーターやら配列アクセスやらJSON変換やらいろんなインターフェースを実装してる。
<?php

// 全ての商品一覧を取得
$itemList=Item::all();

// 最初の商品名と最後の商品名を表示
echo $item->first()->item_name;
echo $item->last()->item_name;

// もちろん普通にforeachで回せる
foreach($itemList as $value){
  echo $value->item_name;
}

// 普通の配列のようにアクセスできたり
echo $itemList[2]->item_name;

// 要素数を取ってきたりも
echo $itemList->count();

// コレクションの中に任意のIDが存在するかチェックできたりもする
if($itemList->contains($key)){
  echo "あるよ";
}

// JSONに変換したり
$json=$itemList->toJson();

// ただの配列に変換したり
$array=$itemList->toArray();
  • 時にはコレクションのデータを操作したい事もあるでしょう。そこで、eachとfilterのメソッド
    • 要素に対して、コールバック関数を適応できる。
    • eachは単純なループ。全ての要素に対して平等に行われます。filterは該当しない要素を削除してくれます。
    • filterは内部でarray_filterをしている事になるので、必ずbool値を返さなければならない。
      • falseを返した場合は、コレクションから削除されます。また、bool値を返さなくても、同じ扱いです。
<?php

// 全ての商品一覧を取得
$itemList=Item::all();

// 全ての商品名にビックリマークを付与
$itemList->each(function($item){
  $item->item_name=$item->item_name."";
});

// コレクションの中で1000円未満の商品を削除
$itemList->filter(function($item){
  if($item->price < 1000){
    return false;
  }
  return true;
});

// 表示
foreach($itemList as $value){
  echo $value->item_name.":";
  echo $value->price."<br />";
}

と、このように、DBから取ってきた後の一手間として、eachとfilterが使えるようになりました。
個人的には、やや使い所は難しい気もしますが、Laravel3ではなかった機能なので、何らかの形で使ってみたい。

  • クエリースコープ
    • Ruby on RailsのモデルにあるScopeがLaravel4にも実装されました。
    • scopeMethodName($query)という形式でメソッドを作成すれば、よく使う、条件式を予め登録できる機能。
      • 以下のサンプルでは、商品テーブルに削除フラグ=del_flgと公開フラグ=public_flgのある商品テーブルがあると仮定する。
        • 削除フラグは0デフォルトで1が削除扱い。公開フラグは0が未公開で1が公開の扱い。
        • つまり、販売中の商品は削除フラグが0で、公開フラグが1という状態。
        • でも、この条件を毎回書くのは面倒。そこでクエリースコープ。
    • モデルファイルの定義
<?php

class Item extends Eloquent {
	
  protected $table = 'item';
  protected $primaryKey = "item_id";
  public $timestamps = false;

  public function scopePublicItem($query){
    $query->where('del_flg', '=', 0);
    $query->where('public_flg', '=', 1);
  }

}
    • どうやって呼び出すか?
<?php

// こう書いていたのが・・・
$itemList=Item::where("del_flg","=",0)->where("public_flg","=",1)->get();

// こんなにシンプルに!呼び出しはscopoを取り除いて、camelCase形式で呼び出す。
$itemList=Item::publicItem()->get();

// 更に条件を追加してもOK
$itemList=Item::publicItem()->where("price",">",500)->get();

// こっちでも同じ
$itemList=Item::where("price",">",500)->publicItem()->get();
  • この、スコープにはwhere句だけでなく、Laravelのクエリービルダーで使えるメソッドが使える。
    • よって、whereBetweenもOKだし、orderByでソートも可能。よく使うクエリー条件はスコープメソッドで定義しておくと、グンと効率が上がります。

という事で、今日はこのくらいで...
公式のマニュアルが現在、大幅に追記されていますので、そちらも参照して下さい。

Laravel4で廃止されたdd()関数みたいなものを組み込む

Laravel3系で結構、重宝していた関数であるデータダンプ用の関数=dd関数。
しかし、残念ながら、Laravel4では廃止になったようです。

「Laravel4ではComposerという便利機能があるので、欲しい人は、自分で探してインストール下さい。」

おそらく、そういう方針なんでしょう。もちろん、要望が高まれば、いずれ、取り込まれる可能性もあるかもしれませんが。
ただ、今のところ、そんな気配はないっぽいです。

で、data-dump関数で良い物があるのか、Composerでインスールできるパッケージを探してみました。
https://packagist.org/

キーワード検索で dump と入力してみると...いろいろ出てきます。
で、今回、注目してみたのが、dump_r()です。

https://packagist.org/packages/leeoniya/dump-r

↓実行結果はこんな感じで、とっても、見やすい!
http://o-0.me/dump_r/

インストール方法はとても、簡単で、プロジェクトルートのcomposer.jsonのrequireのセクションに
"leeoniya/dump-r": "dev-master" を追記するだけ。json形式なので前後の , に気をつけて。

そして、Composer updateを実行。これで、dd関数の代用ができました。

<?php

dump_r($obj);

他にも、Composerでインストールできるいろんなパッケージがあるので、探してみると結構面白いです。

Laravel4でコントローラーの作成とモデルの作成に関する簡単なまとめ

Laravel4のBeta4がリリースされ動きが活発なLaravel。

Laravel4のコントローラーの作成とモデルの作成に関する簡単なまとめを残しておこうと思います。

[下準備]

[新しいコントローラーの作成]

  • app/controllers/のディレクトリに新しいコントローラーの作成する
    • デフォルトではBaseControllerとHomeControllerのふたつ。
  • サンプルとして、このディレクトリにShopControllerという名前のコントローラーを作成する
    • ファイル名は一応、ShopController.php。ただし、必ずしも、この名前じゃなければいけないわけではない。詳しくは後述。
    • BaseControllerを継承するコントローラークラス
    • アクションとして、indexアクションを作成する。
      • アクションメソッドはHTTPメソッド+アクション名の形。
        • アクション名がindexでGETで呼び出される場合は、getIndex。POSTで呼び出される場合は、postIndexという具合。
      • 以下のコードでは、ただ、Shop Index! という文字列がブラウザ上に表示されるサンプル。
        • return "String" で文字列が出力されます。
        • 同様にViewオブジェクトをreturnした場合も、文字列が返却されるので、ブラウザにHTMLが出力されます。
<?php
class ShopController extends BaseController {

	public function getIndex(){
	  return "Shop Index!";
	}

}

ただし、この状態で、http://localhost/project/public/shop/にアクセスしてもエラーになるだけ。

  • ここからが重要。
    • Laravel4では新しいクラスファイルを作成した場合、プロジェクトルートにて、composer dump-autoloadを実行しなければならない
      • このコマンドを実行することによって、ShopControllerの存在がプロジェクトに認識されることになる。
        • Generating autoload filesと表示されればOK。
    • 正しく、ShopControllerの存在が認識されているか確認するには?
      • vendor/composer/autoload_classmap.phpを開いてみればわかる。
      • 長〜い配列の中に、自身で作成したShopControllerがオートロード一覧に入っていれば、OK。
      • 見てみれば、なんとなくわかるように、ファイルとクラス名のマッピングが行われており、ファイル名は実はshop.phpでもOKだったりする。
        • 例えば、ファイル名がyamada.phpでもコードの中でShopContorllerと書いてあれば、ShopControllerがマッピングされる。もちろん、望ましくはない。
<?php

// autoload_classmap.php generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'BaseController' => $baseDir . '/app/controllers/BaseController.php',
    'DatabaseSeeder' => $baseDir . '/app/database/seeds/DatabaseSeeder.php',
    'HomeController' => $baseDir . '/app/controllers/HomeController.php',
    /** 中略 **/
    'ShopController' => $baseDir . '/app/controllers/ShopController.php',
    'TestCase' => $baseDir . '/app/tests/TestCase.php',
    'User' => $baseDir . '/app/models/User.php',
);

コントローラークラスのオートロードが確認できたら、今度はルーティングの設定。
作ったコントローラーを呼び出すための定義をしなければならない。

  • app/routes.phpを開く
    • デフォルトでは、publicルートの定義のみが行われているだけ。
    • project/public/shop/というURIで呼び出すためのコントローラーを登録するためには?
      • Route::controller('shop', 'ShopController');
        • 基本これだけでOK。

で、ブラウザでhttp://localhost/project/public/shop/にアクセス!
Shop Index!と表示されていれば、ひとまず、コントローラーの作成に成功!

[新しいモデルの作成]

  • モデルファイルを作って、DBからデータを取得するサンプルにチャレンジしてみる。
    • DBはとりあえず、MySQLで、商品テーブルからデータを取得するという想定で。
      • 商品情報が保存されているitemテーブルには、商品ID=item_id=主キー、商品名=item_name、価格=item_priceの3つのフィールドがあるする。
      • サンプルデータは適当に入れておいて下さい。
  • まずは、app/config/database.phpにある、mysqlの項目を環境に合わせて変更。
<?php

	'mysql' => array(
		'driver'    => 'mysql',
		'host'      => 'localhost',
		'database'  => 'sample_db',
		'username'  => 'user',
		'password'  => 'password',
		'charset'   => 'utf8',
		'collation' => 'utf8_unicode_ci',
		'prefix'    => '',
	),
  • 次にモデルクラスの作成。app/models/にItem.phpというファイルを作成。
    • ItemクラスはLaravelのORMである、Eloquentクラスを継承する。コードは以下の様な具合で。
<?php

class Item extends Eloquent {
	
	protected $table = 'item';
	protected $primaryKey = "item_id";
	public $timestamps = false;

}
  • $timestampsは created_atとupdated_atのフィールドを更新するためのもの。今回のテーブルには両方共存在しないので、falseを設定。
  • 次はコントローラークラスを作成した時と同様に、プロジェクトルートにて、composer dump-autoloadを実行。Generating autoload filesと表示されていればOK。

[コントローラーにアクションメソッドを追加]

    • 先ほど、作成したShopControllerにgetListメソッドを追加。
      • メソッドはGETで呼び出され、全ての商品名を出力するコードを記述。
    • ORMのEloquentの詳しい使い方に関しては、ドキュメントを参照してみて下さい。
      • なんらかのフレームワークを使ったことがある人には、それほど、習得の敷居は高くないと思います。
<?php
class ShopController extends BaseController {

	public function getList(){
	  foreach(Item::all() as $item){
	    echo $item->item_name."<br />";
 	  }
	}

}

とりあえず、今日はここまで。追記もあるかもしれません。

Laravel4で「HelloWorld」を表示させるまで

最近、ようやく、注目が集まってきたPHPのWebアプリケーションフレームワークLaravelのLaravel4 Beta4が
リリースされたので、HelloWorldを出力するまでの流れを簡単に書いていこうと思います。

【Laravel4のインストール】

  • Laravel4はLaravel3とは違ったインスール方法が採用されている。
{
	"require": {
		"laravel/framework": "4.0.*"
	},
	"autoload": {
		"classmap": [
			"app/commands",
			"app/controllers",
			"app/models",
			"app/database/migrations",
			"app/database/seeds",
			"app/tests/TestCase.php"
		]
	},
	"minimum-stability": "dev"
}
  • requireの項目に、"laravel/framework": "4.0.*" という記述が。
    • どういうことか?
      • https://packagist.org/packages/からrequireで指定されたパッケージのバージョンがダウロード&インストールされる。
      • https://packagist.org/packages/laravel/framework/へブラウザでアクセスすると、Laravelのパッケージ一覧が閲覧できる。
      • requireの項目に "laravel/framework": "4.0.*@dev"を指定すると最新版が、"laravel/framework": "v4.0.0-BETA3"を指定すると、BETA3がインストールされる。
        • requireでバージョンが指定されていない場合minimum-stabilityの値が"dev"となっているので、最新版が自動的にインストールされる形になる。
  • どうやってインストールする?
    • コマンドライン操作
      • composer.jsonがあるディレクトリで以下のコマンドを実行。
        • php composer.phar install
          • WindowsでPATHが通っている場合は composer install だけでOK。
          • vendorディレクトリが作成される
          • 依存関係をチェックした上で、プロジェクトにLaravelが使用しているライブラリ(Symfonyのライブラリ)なども含めてインストールしてくれる。


    • vendorディレクトリの大事なファイルたち
      • vendor/composerディレクトリのファイルたち
        • autoload_classmap.phpとautoload_namespaces.php
        • ここにはアプリケーションで使用するクラスマップと名前空間の定義が記述されている
          • 例えば、autoload_classmap.phpを開いてみる
<?php

// autoload_classmap.php generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'BaseController' => $baseDir . '/app/controllers/BaseController.php',
    'DatabaseSeeder' => $baseDir . '/app/database/seeds/DatabaseSeeder.php',
    'HomeController' => $baseDir . '/app/controllers/HomeController.php',
    /* 中略 */ 
    'User' => $baseDir . '/app/models/User.php',
);
    • composer.jsonで指定した、autoload classmapで指定したディレクトリ内のファイルとクラス名がマッピングされている事がわかる。
      • 簡単に言うと、ここに記述されているクラスファイルたちはちゃんと自動的にロードされますよ!っていうもの。
    • 同様にautoload_namespaces.phpを開くと、Laravel4の名前空間 Illuminate が定義されている事がわかる。
<?php

// autoload_namespaces.php generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Symfony\\Component\\Translation\\' => $vendorDir . '/symfony/translation/',
    'Symfony\\Component\\Routing\\' => $vendorDir . '/symfony/routing/',
    'Symfony\\Component\\Process\\' => $vendorDir . '/symfony/process/',
    /* 中略 */
    'Illuminate' => $vendorDir . '/laravel/framework/src/',
);
  • で、ようやく、Laravel4の初期設定。
    • php artisan key:generate を実行しておく。すると、app/config/app.php のkeyに値がセットされる。
    • .htaccessを編集。
      • RewriteBase /project_root/public/ 任意のディレクトリを指定
        • 127.0.0.1/project_root/public/へアクセスする
          • Hello World!」が出力されていればとりあえずは成功。
          • app/routes.php にルーティングが定義されていおり、デフォルトではトップページのルーティングが定義されているだけ。詳しくは、別のエントリーで。
          • ちなみに、このViewファイルはapp/views/hello.php

とりあえずは、今回は、こんな具合で終わり。
次は、新しいコントローラーの作成とルーティングの定義やモデルファイルの作成を書いていこうと思います。

LaravelのORM Eloquentで括弧を使ったクエリーのグループ化する方法

  • 商品テーブルから削除フラグが0で公開ステータスが1の商品で、更に入力されたキーワードに該当する商品を取得したい
<?php

// キーワード
$keyword=Input::get("keyword");

// 検索
$itemList=Item::where("del_flg", "=", 0)
->where("item_public_status", "=", 1)
->where(function($query) use($keyword)
{
  $query->where("item_name", "LIKE", "%$keyword%");
  $query->or_where("item_meta_keywords", "LIKE", "%$keyword%");
  $query->or_where("item_meta_description", "LIKE", "%$keyword%");
})
->get();
  • ポイントは無名関数を使うときに、useを使うこと。
    • 無名関数内では、$keywordにアクセスできないためuse構文を使用する。
    • useには複数指定できるので、引き継ぎたい変数をどんどんぶっこめばいいだけ。
  • こうして実行されるSQL
SELECT 
 * 
FROM 
 `item` 
WHERE 
`del_flg` = '0' AND `item_public_status` = '1' AND 
 (`item_name` LIKE '%チョコ%' OR `item_long_description` LIKE '%チョコ%' OR `item_meta_keywords` LIKE '%チョコ%' OR `item_meta_description` LIKE '%チョコ%')

LaravelのキャッシュでRedisを使う

PHPフレームワークのLaravelでキャッシュエンジンをRedisにしてみた。以外と、すんなり言ったので、記事を残しておく。

  • Redisの概要
    • オープンソースのkey/valueなデータストア
    • インメモリデータベースで非常に高速に動作する
      • ファイルキャッシュするよりいいらしい。
    • レプリケーションも可能で、非常に簡単らしい。
      • 設定ファイルにちょこっと記述するだけ


  • Laravelでの設定。
    • application/config/database.php にRedisに関する項目を探す
<?php
// application/config/database.php
/* 中略 */
'redis' => array(
  'default' => array(
    'host'     => '127.0.0.1',
    'port'     => 6379,
    'database' => 0
  ),
),
    • キャッシュの設定
      • ドライバーにRedisを指定する
    • application/config/cache.php にRedisに関する項目を探す
<?php
// application/config/cache.php
'driver' => 'redis'

基本これだけでOK。あとは通常通り、キャッシュを使えばいいだけ

<?php

// 保存
// 3番目の引数は分数
Cache::put('key', 'value', 10);

// 取得
$value= Cache::get('key');

// 削除
Cache::forget('key');