路由及控制器
我们将会建立一个展示我们收集的唱片封面的系统。主页将会列出我们的唱片及添加、编辑、删除封面的链接。下面的页面是我们必须的:
| 页面 | 描述 |
| 唱片列表 | 此页面展示唱片列表,并且有着编辑、删除及添加页面的链接 |
| 添加新的唱片封面 | 提供一个添加表单 |
| 编辑一个唱片封面 | 提供编辑功能 |
| 删除 | 可以删除某个唱片封面 |
在我们创建文件之前,对于理解框架是如何组织页面的是非常重要的。应用的每个页面在模块的控制器中是按照操作(action)分组的。所以你一般会将有关联的操作放到同一个控制器中。例如,一个新闻控制器可能包括 current、archived及view等操作。
所以我们在 albums 有四个页面,我们将这些操作集中到 Album 模块的一个控制器中——AlbumController。四个操作如下:
| Page | Controller | Action |
| Home | AlbumController | index |
| Add new Album | AlbumController | add |
| Edit album | AlbumController | edit |
| Delete album | AlbumController | delete |
The mapping of a URL to a particular action is done using routes that are defined in the module’s module.config.php file. We will add a route for our album actions. This is the updated module config file with the new code highlighted.
使用定义在模块里面的 module.config.php 文件里的路由可以使得URL映射到某个特定的action。我们将为我们的封面操作定义一个路由。下面的模块配置文件是更新过的(红色部分是新添加的)。
// module/Album/config/module.config.php:
return array(
'controllers' => array(
'invokables' => array(
'Album\Controller\Album' => 'Album\Controller\AlbumController',
),
),
// The following section is new and should be added to your file
'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',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'album' => __DIR__ . '/../view',
),
),
);
上面配置文件中的路由名称是“album”,类型为 “segment”。segment类型路由可以允许我们使用特别的URL规矩(路由)而可以映射到命名的参数路由上。正因为如此,有路由是 “/album[/:action][/:id]”就可以匹配任何以 album开头的url。下一个片段是关于操作名的控制,最后一个一个映射到可选择的id。中括号的意思是我们可选择的。而 constraints 部分让我们确保在此片段中的字符是可以预料到的,所以我们可以限制操作是以字母开头然后子片段只可能是字母、下划线、或数字。我们同时也限制了id只能为数字。
此路由规则让我们的url一般像这样:
| 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 |
创建控制器
我们准备建立我们的控制器。在 ZF 2中,控制器是一般命名为 {Controller name}Controller 的类。注意 {Controller name}必须是以大写字母开头的。而这个类的文件在模块的 Controller 文件夹中一般为 {Controller name}Controller.php。在我们这个应用中为 module/Album/src/Album/Controller。每个动作是一个 Public 类型的方法,并命名为 {action name}Action。其中 {action name} 必须是以小写字母开头。
注意
这是约定俗成的。ZF 2 并没有约束它一定要实现 theZend\Stdlib\Dispatchable 接口。框架提供2个抽象类给我们: Zend\Mvc\Controller\AbstractActionController 及 Zend\Mvc\Controller\AbstractRestfulController。我们一般使用标准的 AbstractActionController,但是如果你想写一个 RESTful 架构的 web 服务,AbstractRestfulController 这个类应该更有用些。
现在就让我们来创建我们的控制器类:
// module/Album/src/Album/Controller/AlbumController.php:
namespace 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()
{
}
}
注意
我们已经通过配置 config/module.config.php 文件中的 “controller”部分将控制器通知给模块。
我们现在可以创建4个我们想使用的动作。他们并不能工作,除非我们已经建立了视图。这些url应该如下:
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
我们现在已经有个可以工作的路由及对应应用页面的操作。
现在就让我们来建立视图层(view)及模型层(model)吧。
初识视图脚本(view script)
为了将视图集成进应用我们需要创建一些视图脚本文件。这些文件会被 DefaultViewStrategy 执行,并且能够通过控制器的方法返回。这些脚本文件存储在我们的模块的 views 文件夹中,与控制器名称一一对应的。创建4个空的文件如下:
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
我们现在开始填写任何东西,同时开始我们的数据库及模型层。
写一些测试
我们的 Album 控制器没有处理更多东西,所以还是很方便测试的。
创建 zf2-tutorial/tests/module/Album/src/Album/Controller/AlbumControllerTest.php 文件,内容如下:
<?php
namespace Album\Controller;
use Album\Controller\AlbumController;
use Zend\Http\Request;
use Zend\Http\Response;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Router\RouteMatch;
use PHPUnit_Framework_TestCase;
class AlbumControllerTest extends PHPUnit_Framework_TestCase
{
protected $controller;
protected $request;
protected $response;
protected $routeMatch;
protected $event;
public function testAddActionCanBeAccessed()
{
$this->routeMatch->setParam('action', 'add');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(200, $response->getStatusCode());
$this->assertInstanceOf('Zend\View\Model\ViewModel', $result);
}
public function testDeleteActionCanBeAccessed()
{
$this->routeMatch->setParam('action', 'delete');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(200, $response->getStatusCode());
$this->assertInstanceOf('Zend\View\Model\ViewModel', $result);
}
public function testEditActionCanBeAccessed()
{
$this->routeMatch->setParam('action', 'edit');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(200, $response->getStatusCode());
$this->assertInstanceOf('Zend\View\Model\ViewModel', $result);
}
public function testIndexActionCanBeAccessed()
{
$this->routeMatch->setParam('action', 'index');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(200, $response->getStatusCode());
$this->assertInstanceOf('Zend\View\Model\ViewModel', $result);
}
protected function setUp()
{
$bootstrap = \Zend\Mvc\Application::init(include 'config/application.config.php');
$this->controller = new AlbumController();
$this->request = new Request();
$this->routeMatch = new RouteMatch(array('controller' => 'index'));
$this->event = $bootstrap->getMvcEvent();
$this->event->setRouteMatch($this->routeMatch);
$this->controller->setEvent($this->event);
$this->controller->setEventManager($bootstrap->getEventManager());
$this->controller->setServiceLocator($bootstrap->getServiceManager());
}
}
然后执行 phpunit:
PHPUnit 3.5.15 by Sebastian Bergmann.
.....
Time: 0 seconds, Memory: 5.75Mb
OK (5 tests, 10 assertions)

363

被折叠的 条评论
为什么被折叠?



