レコードを表すモデルとテーブルを表すモデルを作成し、
今回はMySQLデータベースへアクセスして、データの出し入れ、
一覧の取得を行える様にソースコード付きで解説します。
まだまだZendFramework2(ZF2)は日本語の情報が少ないので、
チュートリアル的に参考にして頂けたら幸いです。
それでは実際ににMySQLデータベースと連携するモデルを作成していきますが、
その前に、本家のサンプルと同じ様にalbumというテーブルを作成し、
サンプルの値を入れておきましょう
CREATE TABLE album ( id int(11) NOT NULL auto_increment, artist varchar(100) NOT NULL, title varchar(100) NOT NULL, PRIMARY KEY (id) ); INSERT INTO album (artist, title) VALUES ('The Military Wives', 'In My Dreams'); INSERT INTO album (artist, title) VALUES ('Adele', '21'); INSERT INTO album (artist, title) VALUES ('Bruce Springsteen', 'Wrecking Ball (Deluxe)'); INSERT INTO album (artist, title) VALUES ('Lana Del Rey', 'Born To Die'); INSERT INTO album (artist, title) VALUES ('Gotye', 'Making Mirrors');
上記のテーブルは、アルバムの内容を格納する為のテーブルです。
モデルクラスの作成
それでは、テーブルに格納する対象となるアルバムのモデルクラスを定義しましょう。
作成する場所は、module/モジュール名/src/モジュール名/Model/Album.phpです。
namespace Album\Model; class Album { public $id; public $artist; public $title; public function exchangeArray($data) { $this->id = (isset($data['id'])) ? $data['id'] : null; $this->artist = (isset($data['artist'])) ? $data['artist'] : null; $this->title = (isset($data['title'])) ? $data['title'] : null; } }
ここでは、アルバムが持つべきプロパティを定義しています。
ここで定義する事により、データベース内のテーブルと一致出来ますので、
テーブルのレコードをオブジェクト単位で扱える様になります。
続いて、アルバムテーブルとのやり取りを実際に行うmodelクラスを作成します。
やり取りにはTableGatewayを使用し、追加や削除等をこのクラスにて行います。
TableGatewayはデータベース内のテーブルを表すオブジェクトでして
基本的な操作(select,insert,update,delete)はこのTableGatewayに予めメソッドとして定義されています。
とても便利ですので、扱い方をしっかりと掴む事で、その後のコーディングがとても楽になります。
そんなTableGatewayを用いたAlbumのテーブルを表すクラスを作成する場所は
Album.phpと同じ所にファイル名をAlbumTable.phpとして作成します。
module/モジュール名/src/モジュール名/Model/AlbumTable.php
namespace Album\Model; use Zend\Db\TableGateway\TableGateway; class AlbumTable { protected $tableGateway; public function __construct(TableGateway $tableGateway) { $this->tableGateway = $tableGateway; } public function fetchAll() { $resultSet = $this->tableGateway->select(); return $resultSet; } public function getAlbum($id) { $id = (int) $id; $rowset = $this->tableGateway->select(array('id' => $id)); $row = $rowset->current(); if (!$row) { throw new \Exception("Could not find row $id"); } return $row; } public function saveAlbum(Album $album) { $data = array( 'artist' => $album->artist, 'title' => $album->title, ); $id = (int)$album->id; if ($id == 0) { $this->tableGateway->insert($data); } else { if ($this->getAlbum($id)) { $this->tableGateway->update($data, array('id' => $id)); } else { throw new \Exception('Form id does not exist'); } } } public function deleteAlbum($id) { $this->tableGateway->delete(array('id' => $id)); } }
saveメソッドの引数に、先程作成したAlbumクラスがタイプヒンティングされている事がポイントです。
後は追加や削除等を行っています。
ServiceManageにモデルクラスを登録する
続いて、今回追加したモデルをServiceManageに設定します。
設定する事で、追加や削除等をこのクラスにて行います。無駄なインスタンスを作成する事が無く、
常に同じインスタンスを使用するシングルトンパターンとなります。
追加する時に、use分にて該当ファイルを読み込む事を忘れない様にしてください。
namespace Album; use Album\Model\Album; use Album\Model\AlbumTable; use Zend\Db\ResultSet\ResultSet; // use Zend\Db\TableGateway\TableGateway; class Module { // getAutoloaderConfig() and getConfig() methods here // Add this method: public function getServiceConfig() { return array( 'factories' => array( 'Album\Model\AlbumTable' => function($sm) { $tableGateway = $sm->get('AlbumTableGateway'); $table = new AlbumTable($tableGateway); return $table; }, 'AlbumTableGateway' => function ($sm) { $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter'); $resultSetPrototype = new ResultSet(); $resultSetPrototype->setArrayObjectPrototype(new Album()); return new TableGateway('album', $dbAdapter, null, $resultSetPrototype); }, ), ); } }
データベースへのアクセス情報の設定
続いて、データベースへアクセスする為の情報を設定します。
設定を記述する場所は、プロジェクトディレクトリ/config/autoload/global.phpです。
下記のコードを追加しましょう。
return array( 'db' => array( 'driver' => 'Pdo', 'dsn' => 'mysql:dbname=zf2tutorial;host=localhost', 'driver_options' => array( PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'' ), ), 'service_manager' => array( 'factories' => array( 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory', ), ), );
dsnの中にデータベース名とホスト、DBの種類として今回はMySQLを選択します。
そして、データベースへアクセスする為のユーザ名やパスワードは
セキュリティの観点から別のファイルに記述します。
記述するファイルは
プロジェクトディレクトリ/config/autoload/local.php
です
return array( 'db' => array( 'username' => 'YOUR USERNAME HERE', 'password' => 'YOUR PASSWORD HERE', ), );
コントローラから実際にデータベースへアクセスする
それでは、いよいよコントローラ内からデータベースへ接続して見ましょう。
コントローラ内に、データベースを取得し、メンバに保持する一連の流れを記した
メソッドを追加します。
public function getAlbumTable() { if (!$this->albumTable) { $sm = $this->getServiceLocator(); $this->albumTable = $sm->get('Album\Model\AlbumTable'); } return $this->albumTable; }
上記のサンプルの場合は、メンバ変数として
protected $albumTable;
をクラス上部に記述しておいてください。
これで、albumのテーブルを表すオブジェクトとして$this->albumTableでアクセス出来る様になります。
後は、albumTable内に記述したメソッドを使用する事が出来るので、
アルバム一覧を取得する場合は
$this->getAlbumTable()->fetchAll();
で取得する事が出来ます。
ビュー側にそのまま取得した値を渡せば、
foreach等で列挙する事が出来ます。
その際に、
This result is a forward only result set, calling rewind() after moving forward is not supported
といったエラーが出力される場合があります。
これは、データベース内の一覧を取得する際に、走査してしまっている事が原因です。
データベースの取得結果は反復してアクセスする事が出来ないので、
バッファに一旦取り込んで上げる事で、上記のエラーは取り除く事が出来ます。
これらの要素を組み込んで、実際にアルバム一覧を取得し、ビューへ渡すサンプルとして
下記を参考にして下さい。
public function indexAction() { $resultSet = $this->getAlbumTable()->fetchAll(); // ループさせる為にバッファに読み込む $resultSet->buffer(); // ビューを作成し、取得した一覧を埋め込み返却 return new ViewModel(array( 'albums' => $resultSet, )); }
ビュー側では下記の様に、コントローラから渡ってきたアルバム一覧を走査し、
表示します。
foreach ($albums as $album): $album->title; $album->artist; endforeach;
これらで大抵のテーブルを扱える様になります。
基本的なWEBシステムはデータベースへの値の出し入れが大半の処理ですので、
モデル作成からデータベースアクセス、操作を覚えてしまえば
ZendFramework2(ZF2)で実際にWEBアプリを作成する事が可能です。