[ZF2][2]Zend Framework 2 入门教程

本文是基于官方入门教程列出概要理解,详细细节参见官方入门教程: 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:

URLPageAction
/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看起来就类似这样:
<?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()
    {
    }
}
 
The URLs for each action are:
URLMethod 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
2.3) 创建相应的views。
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:
<?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',
        ),
    ),
);
 
数据库权限相关信息:
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):
<?php
return 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>&nbsp;</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!
posted @ 2013-03-08 11:21  SamirChen  阅读(3035)  评论(1编辑  收藏  举报