Database and models
在這裡,我們使用了:Zend\Db\TableGateway\TableGateway 做為對資料庫中的資料表進行新增,查詢,修改以及刪除。
我們使用 MySQL 並透過 PHP 的 PDO 層作為存取資料庫,我們先建立一個名為:zf2tutorial 的資料庫作為資料庫的名稱,接著執行下面的 SQL 檔的指令
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'); |
The model files
Zend Framework 並沒有提供 Model 之類的 component 原因是因為這部分是我們自己的商業邏輯,我們需要自己寫的
我們建立一個名為 Album.php 並放在 /path/to/project-name/module/Album/src/Album/Model 目錄下
Album.php
<?php | |
namespace Album\Model; | |
class Album | |
{ | |
public $id; | |
public $artist; | |
public $title; | |
public function exchangeArray($data) | |
{ | |
$this->id = (!empty($data['id'])) ? $data['id'] : null; | |
$this->artist = (!empty($data['artist'])) ? $data['artist'] : null; | |
$this->title = (!empty($data['title'])) ? $data['title'] : null; | |
} | |
} | |
?> |
在 Album.php 中,就只有一個簡單的 Album class 我們為了要與 Zend\Db 中的 TableGateway 運作正常,因此我們需要實做 exchangeArray() 方法,這個方法可以簡易的從另一個項目設定中去複製一個陣列中的資料,並把資料可以印出在 view 上 (或表單)
我們建立了一個 AlbumTable.php 檔在: /path/to/project-name/module/Album/src/Album/Model 目錄下
AlbumTable.php
其中裡面的方法功能介紹如下:fetchAll 就是得到一個查詢所有 Album 的集合,getAlbum 則是得到某一行的且傳回物件,saveAlbum 則是儲存一行 Album 相關的資料,最後的 deleteAlbum 則是刪除某一行指定的 Album 記錄。
<?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('Album id does not exist'); | |
} | |
} | |
} | |
public function deleteAlbum($id) { | |
$this -> tableGateway->delete(array('id' => (int) $id)); | |
} | |
} | |
?> |
Using ServiceManager to configure the table gateway and inject into the AlbumTable
修改前面的 Module.php,位置在:/path/to/project-name/module/Album/Module.php
<?php | |
namespace Album; | |
use Zend\ModuleManager\Feature\AutoloaderProviderInterface; | |
use Zend\ModuleManager\Feature\ConfigProviderInterface; | |
use Album\Model\Album; | |
use Album\Model\AlbumTable; //後來新增 | |
use Zend\Db\ResultSet\ResultSet; //後來新增 | |
use Zend\Db\TableGateway\TableGateway; //後來新增 | |
class Module implements AutoloaderProviderInterface, ConfigProviderInterface { | |
public function getAutoloaderConfig() { | |
return array( | |
'Zend\Loader\ClassMapAutoloader' => array( | |
__DIR__ . '/autoload_classmap.php', | |
), | |
'Zend\Loader\StandardAutoloader' => array( | |
'namespaces' => array( | |
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, | |
), | |
), | |
); | |
} | |
public function getConfig() { | |
return include __DIR__ . '/config/module.config.php'; | |
} | |
//getServiceConfig 為後來新增 | |
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); | |
}, | |
), | |
); | |
} | |
} | |
?> |
接下來要加入有關資料庫登入的驗證資訊,所以我們要分別編輯:/path/to/project-name/config/autoload/global.php 與 /path/to/project-name/config/autoload/local.php
global.php
就是加入 db 資料庫相關的,像這裡就是定義 PDO 的,下面則是加入 servive_manager 與 Zend\Db\Adapter\Adapter 內建操作資料庫有關的。
<?php | |
/** | |
* Global Configuration Override | |
* | |
* You can use this file for overriding configuration values from modules, etc. | |
* You would place values in here that are agnostic to the environment and not | |
* sensitive to security. | |
* | |
* @NOTE: In practice, this file will typically be INCLUDED in your source | |
* control, so do not include passwords or other sensitive information in this | |
* file. | |
*/ | |
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', | |
), | |
) | |
); |
local.php
則是填入登入 MySQL 的驗證資訊,如帳號與密碼。
<?php | |
/** | |
* Local Configuration Override | |
* | |
* This configuration override file is for overriding environment-specific and | |
* security-sensitive configuration information. Copy this file without the | |
* .dist extension at the end and populate values as needed. | |
* | |
* @NOTE: This file is ignored from Git by default with the .gitignore included | |
* in ZendSkeletonApplication. This is a good practice, as it prevents sensitive | |
* credentials from accidentally being committed into version control. | |
*/ | |
return array( | |
'db' => array( | |
'username' => 'your user-name', | |
'password' => 'your password', | |
) | |
); | |
?> |
Back to the controller
Listing albums
AlbumController.php 前面已經有使用過了,在這裡可以看到一些註解,可以知道加了哪幾行。
<?php | |
namespace Album\Controller; | |
use Zend\Mvc\Controller\AbstractActionController; | |
use Zend\View\Model\ViewModel; | |
class AlbumController extends AbstractActionController { | |
//加入這一行 | |
protected $albumTable; | |
public function indexAction() { | |
return new ViewModel(array( | |
'albums' => $this->getAlbumTable()->fetchAll(), | |
)); | |
} | |
public function addAction() { | |
} | |
public function editAction() { | |
} | |
public function deleteAction() { | |
} | |
//加入這一段方法 | |
public function getAlbumTable() { | |
if (!$this->albumTable) { | |
$sm = $this->getServiceLocator(); | |
$this->albumTable = $sm->get('Album\Model\AlbumTable'); | |
} | |
return $this->albumTable; | |
} | |
} | |
?> |
index.phtml
下面是有關於視圖 (view) index.phtml 的 code
由 index.phtml 得知:
<?php | |
// module/Album/view/album/album/index.phtml: | |
$title = 'My albums'; | |
$this->headTitle($title); | |
?> | |
<h1><?php echo $this->escapeHtml($title); ?></h1> | |
<p> | |
<a href="<?php echo $this->url('album', array('action'=>'add'));?>">Add new album</a> | |
</p> | |
<table class="table"> | |
<tr> | |
<th>Title</th> | |
<th>Artist</th> | |
<th> </th> | |
</tr> | |
<?php foreach ($albums as $album) : ?> | |
<tr> | |
<td><?php echo $this->escapeHtml($album->title);?></td> | |
<td><?php echo $this->escapeHtml($album->artist);?></td> | |
<td> | |
<a href="<?php echo $this->url('album', | |
array('action'=>'edit', 'id' => $album->id));?>">Edit</a> | |
<a href="<?php echo $this->url('album', | |
array('action'=>'delete', 'id' => $album->id));?>">Delete</a> | |
</td> | |
</tr> | |
<?php endforeach; ?> | |
</table> |
We always use the escapeHtml() view helper to help protect ourselves from Cross Site Scripting (XSS) vulnerabilities (see http://en.wikipedia.org/wiki/Cross-site_scripting).
我們常會使用 escapeHtml() 來防止跨站腳本的漏洞。
最後,輸入網址:http://localhost/project-name/public/album 就會看到如下的畫面
到這裡就完成了一個簡單的表格列出專輯清單,下一篇我們會介紹:Styling and Translations 樣式與翻譯。