本文是基於官方入門教程列出概要理解,詳細細節參見官方入門教程:
http://framework.zend.com/manual/2.1/en/index.html
1. 在 zf2 所給的 skeleton application 中創建自己的 Module。
1.1) Setup Module:
* 目錄結構要符合規則。因為 zf2 的 ModuleManager 等組件會根據配置到相應的目錄結構下尋找相應的文件。
* 在 "module/<YourModuleName>" 下創建 Module.php。zf2 的 ModuleManager 會在 "module/<YourModuleName>" 目錄下尋找 "Module.php" 來加載和配置一個 module。這里 module的名字、 namespace 的名字、文件夾的文字保持一致。下面我們都以 Album 來表示一個示例的module。
* zf2 的 ModuleManager 在加載module時會自動調用 Module.php 中的 getAutoloaderConfig() 和 getConfig()。在這兩個方法內,我們要完成對這個module的一些配置。
(zf2.ModuleManager) module/Album/Module.php ---> getAutoloaderConfig() + getConfig()
1.2) Autoloading files:
* Module.php 中的 getAutoloaderConfig() 需要返回一個與 zf2 的 AutoloaderFactory 相兼容的 array。
這里我們添加一個 class map file 並賦值給 Zend\Loader\ClassMapAutoloader;同時將這個module的 namespace 賦值給 Zend\Loader\StandardAutoloader(StandardAutoloader需要一個namespace 和 尋找這個namespace所包含的文件的路徑)。這樣我們就注冊了 autoloader,等着系統來加載相關信息。
getAutoloaderConfig():
zf2.AutoloaderFactory ---> array --->
autoload_classmap.php => Zend\Loader\ClassMapAutoloader
+
namespace => Zend\Loader\StandardAutoloader
1.3) Configuration:
* Module.php 中的 getConfig() 會去加載 Album/config/module.config.php 這個文件。
在這個文件中的配置信息會由 zf2 的 ServiceManager 來傳遞給相關的組件。在這里需要初始化的內容是:
controllers 和 view_manager。
controllers : 列出所有這個module 所提供的 controllers。
view_manager : 該module 的 view directory(存放前端頁面代碼)的路徑。 這個路徑會被添加到 zf2 的 TemplatePathStack 。這樣便可以使系統找到 Album 這個module的view scripts。
getConfig():
controllers : (zf2.ServiceManager) Album\Controller\*Controller
+
view_manager : (zf2.TemplatePathStack) <view directory>
1.4) Inform the application about our new module:
* 在整個項目中注冊新添加的 Album 這個 module。這樣 ModuleManager 就能知道了。
在 config/application.config.php 的 modules 這個 array 中添加 Album。
(ModuleManager) config/application.config.php : modules += Album
2. 添加 actions、view scripts ,並配置 routing and controllers.
2.1) 在 Album/config/module.config.php 配置相應的路由規則來映射 URL 和 對應的action。
*如:
'router'
=>
array
(
'routes'
=>
array
(
'album'
=>
array
(
'type'
=>
'segment'
,
'options'
=>
array
(
'route'
=>
'/album[/:action][/:id]'
,
'constraints'
=>
array
(
'action'
=>
'[a-zA-Z][a-zA-Z0-9_-]*'
,
'id'
=>
'[0-9]+'
,
),
'defaults'
=>
array
(
'controller'
=>
'Album\Controller\Album'
,
'action'
=>
'index'
,
),
),
),
),
),
*這里這個名為 'album' 的route 的類型是 'segment' ,它允許我們在 URL pattern 中指定占位符。比如:
'/album[/:action][/:id]'
這種。
* '[ ]' 表示其中的內容是 optional 的; ':action' 表示這是一個變量,后面將可以對其定義,如:
'action'
=>
'[a-zA-Z][a-zA-Z0-9_-]*'
,
。
*This route allows us to have the following URLs:
URL | Page | Action |
---|---|---|
/album | Home (list of albums) | index |
/album/add | Add new album | add |
/album/edit/2 | Edit album with an id of 2 | edit |
/album/delete/4 | Delete album with an id of 4 | delete |
* 'controller'
=>
'Album\Controller\Album'
, // 這樣將controller做了指定。
前面我們已經這樣
'controllers'
=>
array
(
'invokables'
=>
array
(
'Album\Controller\Album'
=>
'Album\Controller\AlbumController'
,
),
),
注冊過這個controller了。
2.2) 創建相應的 Controller 。
* zf2 中, controller是一個名為
{ControllerName}Controller 的class。
*
'controller'
=>
'Album\Controller\Album'
, 則其對應的controller為
'Album\Controller\AlbumController'. 對應的文件是 module/Album/Controller/AlbumController.php。
* 每個 action 是在
AlbumController.php中的一個方法,其命名應為 {actionName}Action.
* Controller 類 需要 implement '
Zend\Stdlib\Dispatchable' interface. 通常我們可以 extends 'Zend\Mvc\Controller\AbstractActionController
' 或 '
Zend\Mvc\Controller\AbstractRestfulController
'(用於 RESTful webservice) 這兩個 abstract class 來達到目的。
* 那我們的controller看起來就類似這樣:
<?phpnamespace Album\Controller;use Zend\Mvc\Controller\AbstractActionController;use Zend\View\Model\ViewModel;class AlbumController extends AbstractActionController{public function indexAction(){}public function addAction(){}public function editAction(){}public function deleteAction(){}}
*
The URLs for each action are:
URL | Method called |
---|---|
http://zf2-tutorial.localhost/album | Album\Controller\AlbumController::indexAction |
http://zf2-tutorial.localhost/album/add | Album\Controller\AlbumController::addAction |
http://zf2-tutorial.localhost/album/edit | Album\Controller\AlbumController::editAction |
http://zf2-tutorial.localhost/album/delete | Album\Controller\AlbumController::deleteAction |
*
These view scripts are stored in our module’s views directory within a directory named after the controller.
* 如下文件將被 zf2.
DefaultViewStrategy 來執行。同時,從 controller action method 返回的各種值都會被傳遞到對應的 view page 去。
module/Album/view/album/album/index.phtml
module/Album/view/album/album/add.phtml
module/Album/view/album/album/edit.phtml
module/Album/view/album/album/delete.phtml
3. 添加數據庫和models。
3.1) 創建針對實體類 Album 的數據訪問層類 AlbumTable.
*使用 zf2 的 Zend\Db\TableGateway\TableGateway 可以來跟數據庫的數據表進行交互。
通常封裝‘數據訪問層’時可以用到這個。這里我們創建一個 AlbumTable.php 來做這個工作。
*Album 的實體類,Album.php. 為了能和 TableGateway 一起工作,需要在 Album 實體類中實現 exchangeArray() 方法。
*例:
AlbumTable 類中的一些方法:
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
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;
}
3.2) 使用 ServiceManager 來配置 TableGateway 從而實現向 AlbumTable 注入 TableGateway.
* 在 module/Album/Module.php 中新建 getServiceConfig() 方法,這個方法將會被 ModuleManager 自動調用,並被 applied to ServiceManager。
如:
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
);
},
),
);
}
這個方法返回一組 factories ,它會首先被 ModuleManager 合並后,再傳遞給 ServiceManager。
The factory for Album\Model\AlbumTable uses the ServiceManager to create an AlbumTableGateway to pass to the AlbumTable.
We also tell the ServiceManager that an AlbumTableGateway is created by getting a Zend\Db\Adapter\Adapter (also from the ServiceManager) and using it to create a TableGateway object. The TableGateway is told to use an Album object whenever it creates a new result row. The TableGateway classes use the prototype pattern for creation of result sets and entities. This means that instead of instantiating when required, the system clones a previously instantiated object.
在
AlbumTable
中,使用 ServiceManager 注入的 TableGateway 實例來完成各種對數據庫的操作。
如:
protected
$tableGateway
;
public
function
__construct
(TableGateway
$tableGateway
)
{
$this
->tableGateway =
$tableGateway
;
}
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
;
}
這樣配置以后,
在需要的時候
我們
就能在我們的 controller 中使用我們需要的實例。
如:在
AlbumController
中我們這樣來從 ServiceManager 獲得 AlbumTable 的實例。
protected
$albumTable
;
public
function
getAlbumTable() {
if
(!
$this
->albumTable) {
$sm
=
$this
->getServiceLocator();
$this
->albumTable =
$sm
->get(
'Album\Model\AlbumTable'
);
}
return
$this
->albumTable;
}
3.3) 配置 ServiceManager 及 Database相關。
*配置 ServiceManager,使其知道怎樣獲得 Zend\Db\Adapter\Adapter ,這里要用到一個 factory,Zend\Db\Adapter\AdapterServiceFactory which we can configure within the merged config system.
Zend Framework 2’s ModuleManager merges all the configuration from each module’s module.config.php file and then merges in the files in config/autoload (*.global.php and then *.local.php files).
We’ll add our database configuration information to global.php which you should commit to your version control system. You can use local.php (outside of the VCS) to store the credentials for your database if you want to.
數據庫配置相關信息:
Modify config/autoload/global.php (in the Zend Skeleton root, not inside the Album module) with following code:
<?phpreturn 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',),),);
數據庫權限相關信息:
You should put your database credentials in config/autoload/local.php so that they are not in the git repository (as local.php is ignored):
<?phpreturn array('db' => array('username' => 'YOUR USERNAME HERE','password' => 'YOUR PASSWORD HERE',),);
3.4) 上面的工作完成后,在controller里獲得 AlbumTable 並做相關的數據處理邏輯。
如:
// module/Album/src/Album/Controller/AlbumController.php:
protected $albumTable;
public function getAlbumTable()
{
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
}
return $this->albumTable;
}
*前面幾部的正確完成后,這個方法就能夠返回我們需要的 albumTable .
// module/Album/src/Album/Controller/AlbumController.php:
// Get all albums.
public function indexAction()
{
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
));
}
// ...
*在 zf2 中,為了設置 view 中的各種變量,我們返回一個 ViewModel 實例,它的 constructor 的第一個參數是一個包含我們需要的數據的 array.
ViewModel 也允許我們改變將要使用的 view script,但是 default 是 {controller name}/{action name}
這里我們將會 fill in the index.phtml view script.
3.5) 接下來就是在view script中處理並顯示數據。
如:
<?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>
*其中的代碼細節見教程。
4. 其他邏輯代碼和view scrip代碼詳見教程。
5. 設置 home page 顯示 list of albums.
* This is due to a route set up in the Application module’s module.config.php. To change it, open module/Application/config/module.config.php and find the home route:
'home' => array('type' => 'Zend\Mvc\Router\Http\Literal','options' => array('route' => '/','defaults' => array('controller' => 'Application\Controller\Index','action' => 'index',),),),
Change the controller from Application\Controller\Index to Album\Controller\Album:
'home' => array('type' => 'Zend\Mvc\Router\Http\Literal','options' => array('route' => '/','defaults' => array('controller' => 'Album\Controller\Album', // <-- change here'action' => 'index',),),),
That’s it - you now have a fully working application!