Zend Framework2 入门教程



 

图片

因为篇幅过长使用过QQ空间的自动清理功能,不知道是否被删减有内容。javascript

zend framework2 入门教程源码php

http://pan.baidu.com/s/1kTuRGn9css


 

目录html

序言 5前端

第 1章 Zend Framework2 简介 6java

1.1 Zend Framework2 简介 6node

1.2 下载安装 6mysql

1.3 搭建开发环境 6jquery

第2章 建立ZF2项目 7web

2.1 新建一个项目 7

2.2 配置网站 8

2.3 伪静态.htaccess文件 8

2.4 启动/入口文件 8

2.5 添加全局配置文件 9

2.6 添加自动加载文件 init_autoloader.php 9

2.7  IndexController 控制器 10

第3章 建立模块 12

3.1  Module 文件 12

3.2  module.config 文件 13

3.2.1 router 路由配置 15

3.2.2 controllers控制器配置 15

3.2.3 view_manager 视图管理器 16

3.2.4 service_manager 服务管理器 16

3.2.5 translator 翻译器 17

3.2.5.1 语言文件 zh_CN.po 内容 17

3.2.5.2 语言文件 en_US.po 内容 19

3.2.6 navigation 导航条 22

第4 章 建立控制器 23

4.1 控制器简介 23

4.2 新建控制器 23

4.3 添加控制器的Action 23

第 5 章 建立视图 26

5.1 建立模板 26

5.1.1 创建布局目录 26

5.1.2 创建布局文件 26

5.1.3 创建错误异常目录 26

5.1.4 创建错误异常模板文件 26

5.1.5 创建 NewsController 模板目录 26

5.1.6 创建 NewsController 对应的Action 模板文件 27

5.1.7 视图中经常使用函数 27

5.2 模板配置 27

5.3 编写布局和错误异常模板 28

5.3.1  模板文件layout.phtml 28

5.3.2  错误异常模板 index.phtml 29

5.3.3  404错误模板 404.phtml 31

5.4 编写Action 对应的模板文件 34

5.5 访问 IndexAction 34

第 6 章 建立模型 36

6.1 ORM 对象映射法 36

6.1.1 建立 News 类 37

6.1.2 建立 NewsTable 类 38

6.1.3 使用模型读取数据库数据 38

6.1.3.1 模块配置 38

6.1.3.2 控制器中使用模型 40

6.1.3.3 经过模板显示数据库查询结果 41

6.1.3.4 插入数据 42

6.1.3.4.1 建立表单文件 42

6.1.3.4.2 添加过滤器 44

6.1.3.4.3 建立表单 46

6.1.3.4.4 模板输出表单 47

6.1.3.4.5 添加模型方法saveNews 47

6.1.3.4.6 修改新闻内容 48

6.1.3.4.6.1修改模块路由 48

6.1.3.4.6.2修改editAction 方法 49

6.1.3.4.6.3修改edit.phtml模板 50

6.1.3.4.7 删除新闻记录 51

6.1.3.4.7.1修改deleteAction 方法 51

6.1.3.4.7.2添加模型 deleteNews方法 52

6.1.3.4.7.2修改delete.phtml模板 52

6.2 使用分页导航 53

6.2.1 修改模块配置文件 53

6.2.2 修改模型文件 53

6.2.3 修改控制器文件 54

6.2.4 添加分页导航模板 54

6.2.4 修改新闻列表模板 56

6.3 自定模型 57

6.4 章节总结 60

第 7 章 实例应用 61

7.1 创建Album 模块 61

7.1.1创建模块目录 61

7.1.2 配置模块全局设置 61

7.2 添加模块文件 62

7.3 添加模块配置文件 63

7.4 建立数据表 album 64

7.5 添加模型文件 64

7.5.1 添加 Album.php 64

7.5.2 添加AlbumTable.php 66

7.6 添加表单 AlbumForm 68

7.7 添加控制器 AlbumController 69

7.8 添加模板文件 71

7.8.1 列表模板 index.phtml 71

7.8.2 列表模板 add.phtml 72

7.8.3 列表模板 edit.phtml 72

7.8.4 列表模板 delete.phtml 72

7.8.5 列表模板 paginator.phtml 73

第 8 章 用户认证 76

8.1 创建数据表 76

8.2 新建认证类 76

8.3 引用认证类 77

第 9 章 结束语 79

 

 

序言

在教程的制做前先作一些做者的自我介绍,做者赖少林,男,毕业于 广州市南洋理工职业学院 计算机应用科学网络专业 和 海南师范大学 计算机应用科学 应用专业。于2008开始实习工做,从2008年起至今在两家公司任职过,一个是实习单位,另外一个就是目前就任的企业--深圳市奇华基业信息技术有限公司,目前担任公司的技术总监职位。

提及互联网你们就可能立刻想到网站,一说到网站就会想到JAVA  ,.NET ,PHP,ASP 等开发语言;而对于这几个的优缺在互联网的有各类谈论在此就再也不细说了。PHP同时也是个人一个选择,这或许也就我今天为何要写Zend Framwork2 教程的缘由根源之一。当前不论使用哪种语言进行网站的开发都离不开一个东西---框架,框架到是什么呢?形象的说是一个网站的主体架构,能够理解为一座房屋的主体结构。而Zend Framework2 就是一个基于MVC形式的一个框架;那么MVC 究竟是什么呢?他可以用来作什么的? 在此就简单的说一下MVC,MVC是Model,Controller,View 三个单词的缩写,本意为模型,控制器,视图;MVC可以把用户界面,业务逻辑,数据处理等工做分离开来,使不一样的层次来处理不一样的工做,从而提升代码的重用性,项目可维护性。

PHP的框架的有不少,如 Zend Framwork , Symfony ,Codeilgniter, ThinkPHP 等;那么我为何就选择Zend Framework2(如下Zend Framework简写为ZF) 呢。其实之前选择ZF 缘由很简单,主要是有这几个方面的缘由:①Zend 官方出的一个框架;②对执行效率高;③使用灵活;④插件丰富,也易于自写插件;⑤适用于大型项目 等。

在此说说为何要写ZF2 教程的缘由,做者使用ZF1框架已经有多年的时间,在最开始接触ZF的时候就已经据说ZF 很难学,当时我不大相信不就是一个框架吗,有什么难的,当时就是那样的想法的。可当真的开始学习ZF的时候问题就不断的出现问题了,不问题多并且解决方法又少;由于PHP自己在国内发展及ZF在国内的应用缘故(因为国内较少有大学开设PHP语言课程,使得国内使用PHP技术的人员相对较少),致使要找到问题的相关解决方法真不简单,在国内的网站不多有ZF的相关资料,即便有一些资料也是比较零散的,并且也是已经比较过期的资料,对于解决问题基本上没有什么帮助;而对国外的资料就丰富多了,由于国外对PHP技术的发展及流行程度比较国内高,资料虽多但全是英文的,若是没有必定英文的基础根本没法从中找到有用帮助。直到今日做者发现无论是互联网上仍是实体书本对于ZF的中文版教程仍是少之又少。因此决定编写一本关于ZF 开发的系列教程,但愿可以帮助到一些在ZF迷途的PHPER。

本书中的主要内容都是从项目的实例开发为出发点,并非对ZF2官方资料的直接翻译;因此此书不可能将ZF2 类库的全部内容及配置都进行讲解;在写本书的同时本人也同在开发某款CMS系统,书中大部分代码均为CMS原文件中的片断,全部代码都经过本人的调试。本书比较适合用于ZF2 的项目入门指导书籍,书中集中讲述了怎样去使用及掌握ZF2的技术与技能。致以ZF2的底层实现能够查阅ZF2官方网站的开发手册。

Zend Framework 官方网址:http://www.zendframework.com/

第 1章 Zend Framework2 简介

1.1 Zend Framework2 简介

ZF2是一个基于PHP的开源框架,能够用来开发WEB应用程序的各类服务。ZF2是一个基于面向对象的框架,一切都是以对象为基础。ZF2有很是丰富的组件库,并且大部组件之间相互独立,互不依赖,因此开发者能够独自开发并使用自定义组件。

ZF2 拥有一个强大并且高效的MVC实现,他具备强大的数据库操做、路由控制、视图渲染、HTML表单解析、表单验证、数据过滤等功能;同时ZF2还提供了多种用户认证功能,经过证书来保存用户认证和受权信息,也能够经过Amf 来为Flash等其余语言开发的软件提供相应的服务。总的来讲不论你须要什么功能,你均可以从ZF2中找到相应的组件来实现,从而有效的减小开发时间,提升项目开发的效率。ZF2提供的各类组件能够用来实现你想要的各类功能,也能够添加一些你自定义组件来搭建你强大的WEB应用程序。

1.2 下载安装

ZF2 的安装要求PHP的版本不低于5.3,不过做者仍是建议能够升级到更高的版本,由于每一个更高的版本都会对前一个版本的安全性和性能发挥上作了相应的改善和提升。本书中使用的PHP版本为PHP5.4,通过做者一些相关测试,ZF2框架在PHP 5.5 的版本上运行也是彻底正常,因此PHP的版本选择范围仍是比较广的。

致以安装ZF2与ZF1相比明显要复杂不少,二者即有明显的区别,又有一些本质上的联系;要想了解ZF1与ZF2的之间的区别能够到ZF的官网去找相关的说明与帮助。ZF2框架类库能够在ZF的官方网站(官网网址:http://www.zendframework.com/,下载网址:http://www.zendframework.com/downloads/latest)下载,本书使用的ZF版本为ZF2.15。至于怎样安装使用ZF2的框架,下面会作详细的介绍。

1.3 搭建开发环境

在开始使用ZF2框架前须要把开发平台先搭建好,在此做用选择 xampp 做为开发测试环境,最新版本的xampp已经集成了apache2.4与php5.4.7及其余组件,选择netbeans 做为开发工具。做者将网站的开发目录网址设置为:http://127.0.0.1/  | http://localhost/ 这两个网址是同样的。

开发环境安装好之后须要对 apache 作一些相关修改以便支持 .htaccess 文件。经过须要修改的地方为设置你网站目录的地方(httpd.conf),将 AllowOverride None 修改成 AllowOverride All

在vhost.conf下添加

网站的配置并无太多的要求,对于目录的命名等能够根据自已的状况来配置,网站只要能支持.htaccess 文件就行。

 

 

第2章 建立ZF2项目

2.1 新建一个项目

方法一:手动添加目录,结构以下

/

└appliction

└css

└js

└images

└library

    └Zend

└module

└Application

└config

└language

└src

└Application

└Controller

└Model

└views

└vendor

目录解释:

/application                      你网站的根目录

/application/css | js | images     这些主要存放样式表、js、图片等文件

/library                            存放类库文件

/module                             存放各类模块,通常在此目录下的一个子目录为一个模块

/module/Application               表一个名叫 Application 的模块

/module/Application/config          Application 模块的配置文件目录

/module/Application/language         语言文件目录,用来支持多国语言实现项目的国际化

/module/Application/src    Application 模块的资源文件目录,下面包含此模块的控制器、模型、表单等一系列文件

/module/views                    Application 模块的视图文件目录

/vendor                             自定义类库或其余第三方类库

日后须要添加模块能够根据类似的目录结果进行添加。

 

方法二:使用netbeans 或 zend studio 新建一个项目,在建立项目的过程当中选择使用 Zend Framework 框架,这样就能够建立出一个基于 Zend Framework 框架的项目,目录结构有些许差别,但目录功能与上面结构说明相似,你能够在项目找到他们对应的结构说明。下面做者使用Zend studio 来建立一个基于Zend Framework2的项目操做:打开zend studio 软件 --> File(打开) --> New(新建) --> Project(项目) --> Local PHP Porject(本地PHP项目) --> Next(下一步) --> Project Name(项目名称,填写你的项目名称) --> Location(项目放在位置,选择项目的保存位置) --> Content(项目内容,选择 Zend Framework) --> Version(版本,选择使用框架版本) --> Finish(完成);这样一个基于Zend Framework 2的项目就已经创建好了,而后调整一个apache的目录指定。经过这种方法创建项目后能够直接使用 http://localhost/ 来打开项目了。

 

上面两种建立项目的方法各有优缺点,方法一:手动输入相对麻烦,但目录结构比较灵活;方法二:项目建立简单,即建即用,但类库很差找(其实就是放在vendor 下面了)。项目的建立方法无论使用哪种,只要清楚各个目录的做用便可。本书建立项目的方法为第一种方法,此方法建立并运行项目须要添加多个文件,而第二种方法则直接建立后就能够直接运行。本书使用第一种方法建立项目的缘由仍是基于对ZF2框架的深化理解,使用阅读者可以真正的了解到ZF2的运行机制,同也使用读者能更多灵活的掌握和使用ZF2框架。

 

2.2 配置网站

ZF2项目的基本目录建立好之后,在你的 apache 服务器上添加一个虚拟网站,配置示例详情以下:

<VirtualHost *:80>

ServerName localhost

DocumentRoot /path/application

<Directory /path/application>

DirectoryIndex index.php

AllowOverride All

Order allow,deny

Allow from all

</Directory>

</VirtualHost>

若是对 apache 配置比较熟练的话能够根据自已的须要进行配置,对配置格式没有什么特殊的要求。惟一须要注意的就是要将 AllowOverride All 打开伪静态的支持。

 

2.3 伪静态 .htaccess文件

添加/application/.htaccess

若是使用记事原本写这个文件,那么保存的时候要使用另存为的方式进行保存,若是在netbeans中建立的话就能够直接保存。同时还应当注意在书写这种文件的时候最后至少要有一行空白行,有时候有些文件就有这样要求。此文件的主要功能就是实现URL的重写,根据URL的访问地址经过前端控制器找到相应的路由,从而实现对资源文件准肯定位。重写URL的好处还在于可以让搜索引擎更容易抓取。

在文件中输入如下内容:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^.*$ index.php [NC,L]

 

 

2.4 添加启动/入口文件

路径:/application/index.php

添加如下内容:

chdir(__DIR__);

if (!defined('APP_PATH'))

    define ('APP_PATH', __DIR__ . '/../');

if (!defined('LIB'))

    define('LIB', APP_PATH . 'library');

require 'init_autoloader.php';

Zend\Mvc\Application::init(require APP_PATH . 'config/application.config.php')->run(); // 启动应用程序

下面代码解释:

lchdir         修改当前运行目录

lAPP_PATH     指定网站根目录

lLIB            指定类库目录

linit_autoloader.php     自动加载文件

config/application.config.php 应用程序全局配置文件

Zend\Mvc\Application::init(require APP_PATH . 'config/application.config.php')->run() 启动应用程序

2.5 添加全局配置文件

路径:/config/application.config.php

内容以下:

return array(

    'modules' => array(

        'Application'

    ),

    'module_listener_options' => array(

        'config_glob_paths' => array(

            APP_PATH.'config/autoload/{,*.}{global,local}.php',

        ),

        'module_paths' => array(

            APP_PATH.'module',

            APP_PATH.'vendor',// 就要应用于phpunit

        ),

    ),

);

代码解释:

lmodules=>array() 这是模块配置,网站系统的每个模块都要添加到此,以便ZF2框架可以正确的找到模块

lmodule_listener_options=>array() 此处用于设置模块的事件侦听

lconfig_glob_paths=>array() 配置全局路径,以便系统自动加载相关文件类库

lmodule_paths=>array() 配置模块路径

2.6 添加自动加载文件 init_autoloader.php

路径:/application/init_autoloader.php

if (defined('LIB')) {

        include LIB . '/Zend/Loader/AutoloaderFactory.php';

        Zend\Loader\AutoloaderFactory::factory(array(

            'Zend\Loader\StandardAutoloader' => array(

                'autoregister_zf' => true

            )

        ));

}

if (!class_exists('Zend\Loader\AutoloaderFactory')) {

    throw new RuntimeException('Unable to load ZF2. ');

}

代码解释:

lif (defined('LIB'))  判断是否有定义预约义变量指向ZF2类库

linclude LIB . '/Zend/Loader/AutoloaderFactory.php' 导入ZF2框架自动加载工厂文件

lZend\Loader\AutoloaderFactory::factory(array()) 对自动加载工厂类进行设置

lif (!class_exists('Zend\Loader\AutoloaderFactory')) 判断工厂类是存在,若是不存在则抛出异常

 

下面是 init_autoloader.php 的另外一个写法,此写法实际上是 Zend studio 或 netbeans 建立项目时自动生成的写,这样的写法实际上是加入对 phpunit 单元测试的支持。phpunit 的测试环境通常都是在命令行上操做完成,因此这样的写法也是对命令行环境的一种设置,在此就很少加详解;下面只贴出代码。

if (file_exists('vendor/autoload.php')) {

    $loader = include 'vendor/autoload.php';

}

if (defined('LIB')) {

    if (isset($loader)) {

        $loader->add('Zend', LIB);

    } else {

        include LIB. '/Zend/Loader/AutoloaderFactory.php';

        Zend\Loader\AutoloaderFactory::factory(array(

            'Zend\Loader\StandardAutoloader' => array(

                'autoregister_zf' => true

            )

        ));

    }

}

 

if (!class_exists('Zend\Loader\AutoloaderFactory')) {

    throw new RuntimeException('Unable to load ZF2.');

}

2.7  IndexController 控制器

路径:/module/Application/src/Application/controller/IndexController.php

代码以下:

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

class IndexController extends AbstractActionController{

    public function indexAction(){

        echo “hello world”;

exit;

    }

}

代码说明:

lnamespace Application\Controller 指定命名空间

luse Zend\Mvc\Controller\AbstractActionController | use Zend\View\Model\ViewModel 导入相关类库

lclass IndexController extends AbstractActionController  定义 IndexController 类库,同时此类必需继承 AbstractActionController 类,这是ZF2 的硬性要求,除非你重写此类的实现。

lpublic function indexAction(){} 控制器的一个响应动做,其中indexAction 这个名称为ZF默认动做

lecho "hello world" 在屏幕上打印出 hello world

到此一个基本的控制器类就已经编写完成,可是不是如今就能够经过 http://localhost/ 就能够访问控制器,并能够看到屏幕上的hello world 了呢?答案固然是否认的。若是这是ZF1的话,就添加完这样一个控制器后应该是能够访问的了。但此处使用的是ZF2框架,因此要想经过 http://localhost/ 访问并在屏幕上打印出 hello world 来还须要添加多个文件来共同实现;这也是为何ZF2比ZF1的使用要更为复杂,也是ZF2比ZF1更增强大、灵活的缘由所在。

 

 

第3章建立模块文件

ZF2 使用模块系统将应用程序的主要代码集成到各个模块中去。同时应用模块还应提供用于引导、错误异常、路由等所有的配置信息。在模块文件里能够根据自已的须要去调整关于 实图、路由、模型等一系列应用程序级的设置,同时Module不单起到配置信息的做用,同时也是应用程序的必需中间件或桥梁,由于程序从前端控制器的分配及引导下进入的下层级就是Module类,经过解析Module类到达指定资源位置。由此也能够看出ZF2的灵活性仍是比较高的。

下面开始添加模块文件。

3.1  Module 文件

路径:/moudle/Application/Module.php

内容以下:

namespace Application;

use Zend\Mvc\ModuleRouteListener;

use Zend\Mvc\MvcEvent;

class Module {

public function onBootstrap(MvcEvent $e){

$e->getApplication()->getServiceManager()->get('translator');// 多国语言支持,这个语言文件须要自已添加

        $eventManager = $e->getApplication()->getEventManager();// 获取当前已经有事件管理器

        $moduleRouteListener = new ModuleRouteListener();// 新建一个路由模块监听器

        $moduleRouteListener->attach($eventManager);// 附加事件管理器

    }

    public function getConfig(){

        return include __DIR__ . '/config/module.config.php';// 引入模块配置文件

    }

    public function getAutoloaderConfig(){

        return array(

            'Zend\Loader\StandardAutoloader'=>array(

                'namespaces'=>array(

                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__  // 导入自动加载空间

                )

            )

        );

    }

}

代码解释:

lnamespace Application       建立或访问指定命名空间

luse Zend\Mvc\ModuleRouteListener | use Zend\Mvc\MvcEvent 导入包或类

lclass Module 定义类

lpublic function onBootstrap  启动模块,onBootstrap() 将调用每一个已经实现此功能的模块,而且用于执行轻量级任务和注册事件监听器等

lpublic function getConfig       获取此模块中的配置信息,返回一个符合ZF2自动加载工厂规则的数组

lpublic function getAutoloaderConfig 此模块中自动加载配置信息

 

在此说明一下,在ZF2开始引入了namespeace 空间的概念,使得ZF2 与java的相关概念进一步的靠近,这对于已经掌握了java开发的人来讲是将是一个好的消息。空间的含义就至关于一个用来装东西的容器,而对于程序来讲,空间能够简单的理解为装类的容器;有了空间的出现,全部的类库都将被包含到一个指定的空间里面,由于ZF2的文件搜索或路由也是经过空间来定位的。再者就是有了空间能够更好的去管理各类类,方便文件功能归类及使用。

3.2  module.config 文件

路径:/module/Application/config/module.config.php

内容以下:

return array(

    'router' => array(

        'routes' => array(

            'application' => array(

                'type' => 'segment',

                'options' => array(

                    'route' => '/[application][:controller][/:action]',

                    'constraints' => array(

                        'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',

                        'action' => '[a-zA-Z0-9_-]*',

                    ),

                    'defaults' => array(

                        '__NAMESPACE__' => 'Application\Controller',

                        'controller' => 'Index',

                        'action' => 'index'

                    ),

                ),

            ),

        ),

    ),

    'controllers' => array(

        'invokables' => array(

            'Application\Controller\Index' => 'Application\Controller\IndexController'

        ),

    ),

    'view_manager' => array(

        'display_not_found_reason' => true,

        'display_exceptions' => true,

        'doctype' => 'HTML5',

        'not_found_template' => 'error/404',

        'exception_template' => 'error/index',

        'template_map' => array(

            'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',

            'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',

            'error/404' => __DIR__ . '/../view/error/404.phtml',

            'error/index' => __DIR__ . '/../view/error/index.phtml',

        ),

        'template_path_stack' => array(

            'application' => __DIR__ . '/../view'

        ),

    ),

    'service_manager' => array(

        'factories' => array(

            'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',

'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory',

        ),

    ),

    'translator' => array(

        'locale' => 'en_US',

        'translation_file_patterns' => array(

            array(

                'type' => 'gettext',

                'base_dir' => __DIR__ . '/../language',

                'pattern' => '%s.mo',

            ),

        ),

), 

'navigation' => array(

        'default' => array(

            array(

                'label' => 'Home',

                'route' => 'applicaton’

            ),

            array(

                'label' => 'Application',

                'route' => 'application’,

                'pages' => array(

                    array(

                        'label' => 'List',

                        'route' => 'application’,

                        'action' => 'list',

                    ),

                ),

            ),

        ),

    ), 

);

先对以上配置进行归类:

array(// 总配置

‘router’                     =>array(),// 路由

‘controllers’              =>array(),// 控制器

‘view_manager’       =>array(),// 视图管理器

‘service_manager’       =>array(),// 服务器管理器

‘translator’              =>array(),// 译码器或翻译器

‘navigation’              =>array(),// 页面导航

);

 

下面对 router、controllers、view_manager、service_manager、translator 、navigation进行逐个解释。

3.2.1 router 路由配置

路由的配置是对前台页面访问地址的具体配置,此处配置的格式将影响到前台页面访问此模块的全部地址

链:router--->routes--->模块--->具体配置

lrouter 此数组块为路由配置信息段

lrouter-->routes 表示此模块的中路由,路由至少1条以上

lrouter-->routes-->application 表示你的模块名称,在此如下的信息为具体配置信息

lrouter-->routes-->application-->type              表示路由模式,可选 segment 或 literal,区别在于 segment 已经处理好告终尾的斜杠,而literal 会把结尾带与不带斜杠表示不一样的路由进行处理; 若是使用literal 时须要特别注意这一点。

lrouter-->routes-->application-->options 路由具体选项信息区块

lrouter-->roytes-->application-->options-->route 路由规则,此处规则将最终决定此模块的路由访问格式

lrouter-->roytes-->application-->options-->constraints  路由匹配规则

lrouter-->roytes-->application-->options-->constraints-->controller  控制器的路由正规匹配规则

lrouter-->roytes-->application-->options-->constraints-->action  action(动做)的路由正规匹配规则

lrouter-->roytes-->application-->options-->defaults 默认路由处理规则

lrouter-->roytes-->application-->options-->defaults-->__NAMESPACE__ 指定模块控制器所在的命名空间

lrouter-->roytes-->application-->options-->defaults-->controller 指定默认使用的控制器名称

lrouter-->roytes-->application-->options-->defaults-->action  指定默认使用的action(动做)名称

3.2.2 controllers控制器配置

控制器的配置将决定哪些控制器类可以被访问及使用,在此配置后ZF2自动加载厂能够很快的定位到控制所在的位置,对资源进行快速访问、使用。

链:controllers--->invokables--->控制器

lcontrollers 表示此数组块为控制器配置信息段

lcontrollers-->invokables 这个是控制器区块的固定表示方法,表示此区块下的控制器为可用控制器

lcontrollers-->invokables-->Application\Controller\Index  表示一个控制器,数组的键表示DI注入的引用,数组值则表示对应控制器所在的具体路径

控制器的配置不局限于某一个控制器,能够把全部已经存在而且有效控制器加入到此区块来进行使用。

3.2.3 view_manager 视图管理器

视图管理器主要负责视图信息的配置,如:错误显示、页面类型、布局文件、视图文件位置、404页面等。

链:view_manager-->N , view_manager-->template_map , view_manager-->template_path_stack

lview_manager 表示此数组块为视图管理器配置信息段

lview_manager-->display_not_found_reason  是否显示404缘由

lview_manager-->display_exceptions  是否显示异常信息

lview_manager-->doctype 指定视图页面类型

lview_manager-->not_found_template 指定404的视图模板

lview_manager-->exception_template 指定异常模板文件

lview_manager-->template_map  视图模块地图

lview_manager-->template_map-->’layout/layout’ 指定布局文件

lview_manager-->template_map-->’application/index/index’ 指定 application 模块的视图文件

lview_manager-->template_map-->’error/404’ 指定404页面的视图文件

lview_manager-->template_map-->’error/index’ 指定错误异常页面的视图文件

lview_manager-->template_path_stack 视图模板堆栈路径

lview_manager-->template_path_stack-->application 指定模块application 视图目录所在路径

3.2.4 service_manager 服务管理器

服务管理器主要负责一些工厂类的配置,使用系统可以在运行时自动的加载运行某些服务性功能。

链:service_manager-->factories

lservice_manager  表示此数组块为服务管理器配置信息段

lservice_manager-->factories 工厂类配置

lservice_manager-->factories-->translator  语言转换工厂,主要功能是实现多国语言的支持,语言文件须要自已编写;ZF2框架自己并不提供语言包,但提供对语言包的解析功能,经过语言包经过指定的语言进行转换;同时语言之间的转换及格式的变化比较而随意性也比较大,因此语言包能够根据项目的实现需求来进行订制,若是实际的项目开发中并不使用到国际化的功能时,能够将多国语言国际功能删除。

lservice_manager-->factories-->translator-->navigation  导航工厂,主要用来实现页面的导航和分页导航

3.2.5 translator 翻译器

翻译器的主要工做是负责对各类支持语言的转换以此为目的,从而实现网站应用程序的多国化甚至全球化。本书内容有涉及到使用语言包,语言包的生成能够参考po,mo 文件建立的其余文献;你也能够经过 Zend Studio 来建立项目以获取ZF2 默认生成的language 包。下面将会提供两个语言包内容 zh_CN.po ,en_US.po 这个为中英文件互转文件,这两语言由Zend Studio项目生成时自动建立;他们对应的mo文件能够经过 poedit 软件来生成,也可能过poedit 来修改po文件。若是在开发时不想使用任何语言转换,能够不进行任何关于语言转换相关的配置。

链:translator-->locale , translator-->translation_file_patterns

ltranslator 表示此数组块为翻译器配置信息段

ltranslator-->locale 指明应用程序的本地使用语言,或是应用程序使用的默认语言

ltranslator-->translation_file_patterns  翻译文件的配置设置

ltranslator-->translation_file_patterns-->type 翻译文件类型

ltranslator-->translation_file_patterns-->base_dir 指定语言文件目录

ltranslator-->translation_file_patterns-->pattern 语言文件的匹配规则

下面提供两个语言包,语言包为中英语言包,能够在开发的时候对两种语言环境进行切换。

3.2.5.1 语言文件 zh_CN.po 内容

msgid ""

msgstr ""

"Project-Id-Version: ZendSkeletonApplication\n"

"Report-Msgid-Bugs-To: \n"

"POT-Creation-Date: 2012-07-05 22:17-0700\n"

"PO-Revision-Date: 2013-05-06 11:26+0800\n"

"Last-Translator: \n"

"Language-Team: ZF Contibutors <zf-devteam@zend.com>\n"

"Language: en_US\n"

"MIME-Version: 1.0\n"

"Content-Type: text/plain; charset=UTF-8\n"

"Content-Transfer-Encoding: 8bit\n"

"X-Poedit-KeywordsList: translate\n"

"X-Poedit-Basepath: .\n"

"X-Generator: Poedit 1.5.5\n"

"X-Poedit-SearchPath-0: ..\n"

msgid "Home"

msgstr "主页"

msgid "All rights reserved."

msgstr "版权全部."

msgid "Help &amp; Support"

msgstr "帮助 &amp; 支持"

msgid "An error occurred"

msgstr "发生错误"

msgid "Additional information"

msgstr "附加信息"

msgid "File"

msgstr "文件"

msgid "Message"

msgstr "消息"

msgid "Stack trace"

msgstr "Stack trace"

msgid "Previous exceptions"

msgstr "上一个异常"

msgid "No Exception available"

msgstr "没有可用的Exception"

msgid "A 404 error occurred"

msgstr "404 缺乏目标文件"

msgid "The requested controller was unable to dispatch the request."

msgstr "所请求的控制器不能分发该请求"

msgid ""

"The requested controller could not be mapped to an existing controller class."

msgstr "所请求的控制器不能映射到已存在的控制器类"

msgid "The requested URL could not be matched by routing."

msgstr "所请求的URL不能与路由对应"

msgid "We cannot determine at this time why a 404 was generated."

msgstr "咱们不能肯定为何此次会出现404"

msgid "Controller"

msgstr "控制器"

msgid "resolves to %s"

msgstr "解决: %s"

msgid "Exception"

msgstr "异常"

msgid "Add"

msgstr "添加"

msgid "Delete"

msgstr "删除"

msgid "Edit"

msgstr "修改"

msgid "Add new album"

msgstr "添加新闻"

msgid "Title"

msgstr "标题"

msgid "Artist"

msgstr "文章内容"

3.2.5.2 语言文件 en_US.po 内容

msgid ""

msgstr ""

"Project-Id-Version: ZendSkeletonApplication\n"

"Report-Msgid-Bugs-To: \n"

"POT-Creation-Date: 2012-07-05 22:17-0700\n"

"PO-Revision-Date: 2012-07-05 22:17-0700\n"

"Last-Translator: Evan Coury <me@evancoury.com>\n"

"Language-Team: ZF Contibutors <zf-devteam@zend.com>\n"

"Language: \n"

"MIME-Version: 1.0\n"

"Content-Type: text/plain; charset=UTF-8\n"

"Content-Transfer-Encoding: 8bit\n"

"X-Poedit-KeywordsList: translate\n"

"X-Poedit-Language: English\n"

"X-Poedit-Country: UNITED STATES\n"

"X-Poedit-Basepath: .\n"

"X-Poedit-SearchPath-0: ..\n"

#: ../view/layout/layout.phtml:6

#: ../view/layout/layout.phtml:33

msgid "Skeleton Application"

msgstr ""

#: ../view/layout/layout.phtml:36

msgid "Home"

msgstr ""

#: ../view/layout/layout.phtml:50

msgid "All rights reserved."

msgstr ""

#: ../view/application/index/index.phtml:2

#, php-format

msgid "Welcome to %sZend Framework 2%s"

msgstr ""

#: ../view/application/index/index.phtml:3

#, php-format

msgid "Congratulations! You have successfully installed the %sZF2 Skeleton Application%s. You are currently running Zend Framework version %s. This skeleton can serve as a simple starting point for you to begin building your application on ZF2."

msgstr ""

#: ../view/application/index/index.phtml:4

msgid "Fork Zend Framework 2 on GitHub"

msgstr ""

#: ../view/application/index/index.phtml:10

msgid "Follow Development"

msgstr ""

#: ../view/application/index/index.phtml:11

#, php-format

msgid "Zend Framework 2 is under active development. If you are interested in following the development of ZF2, there is a special ZF2 portal on the official Zend Framework website which provides links to the ZF2 %swiki%s, %sdev blog%s, %sissue tracker%s, and much more. This is a great resource for staying up to date with the latest developments!"

msgstr ""

#: ../view/application/index/index.phtml:12

msgid "ZF2 Development Portal"

msgstr ""

#: ../view/application/index/index.phtml:16

msgid "Discover Modules"

msgstr ""

#: ../view/application/index/index.phtml:17

#, php-format

msgid "The community is working on developing a community site to serve as a repository and gallery for ZF2 modules. The project is available %son GitHub%s. The site is currently live and currently contains a list of some of the modules already available for ZF2."

msgstr ""

#: ../view/application/index/index.phtml:18

msgid "Explore ZF2 Modules"

msgstr ""

#: ../view/application/index/index.phtml:22

msgid "Help &amp; Support"

msgstr ""

#: ../view/application/index/index.phtml:23

#, php-format

msgid "If you need any help or support while developing with ZF2, you may reach us via IRC: %s#zftalk on Freenode%s. We'd love to hear any questions or feedback you may have regarding the beta releases. Alternatively, you may subscribe and post questions to the %smailing lists%s."

msgstr ""

#: ../view/application/index/index.phtml:24

msgid "Ping us on IRC"

msgstr ""

#: ../view/error/index.phtml:1

msgid "An error occurred"

msgstr ""

#: ../view/error/index.phtml:8

msgid "Additional information"

msgstr ""

#: ../view/error/index.phtml:11

#: ../view/error/index.phtml:35

msgid "File"

msgstr ""

#: ../view/error/index.phtml:15

#: ../view/error/index.phtml:39

msgid "Message"

msgstr ""

#: ../view/error/index.phtml:19

#: ../view/error/index.phtml:43

#: ../view/error/404.phtml:55

msgid "Stack trace"

msgstr ""

#: ../view/error/index.phtml:29

msgid "Previous exceptions"

msgstr ""

#: ../view/error/index.phtml:58

msgid "No Exception available"

msgstr ""

#: ../view/error/404.phtml:1

msgid "A 404 error occurred"

msgstr ""

#: ../view/error/404.phtml:10

msgid "The requested controller was unable to dispatch the request."

msgstr ""

#: ../view/error/404.phtml:13

msgid "The requested controller could not be mapped to an existing controller class."

msgstr ""

#: ../view/error/404.phtml:16

msgid "The requested controller was not dispatchable."

msgstr ""

#: ../view/error/404.phtml:19

msgid "The requested URL could not be matched by routing."

msgstr ""

#: ../view/error/404.phtml:22

msgid "We cannot determine at this time why a 404 was generated."

msgstr ""

#: ../view/error/404.phtml:34

msgid "Controller"

msgstr ""

#: ../view/error/404.phtml:41

#, php-format

msgid "resolves to %s"

msgstr ""

#: ../view/error/404.phtml:51

msgid "Exception"

msgstr ""

3.2.6 navigation 导航条

导航条的主要功能是生成页面导航或分页导航

链:navigation-->N

lnavigation 表示此数组块为页面导航配置信息段

lnavigation-->default 默认页面导航

lnavigation-->default-->array() 一个导航标签配置

lnavigation-->default-->label 导航的标签

lnavigation-->default-->route 导航的路由,其实就是指向的控制器

 

 

经过以上对路由、控制器、视图、服务等各项功能的配置以后,如今已经能够经过 http://localhost/ 或 http://localhost/index/index 的连接来访问咱们的操控了。经过 http://localhost/ 访问就能看到屏幕打印出 hello world ,你会发现这个连接即没有控制器也没有动做(action),怎么就能够输出内容了呢,其实经过上面的路由配置,已经设置一个默认的路由,默认路由规则中规定了默认使用的控制器为IndexController,默认访问的动做为indexAction;而 http://localhost/index/index 也是一样由于路由设置,同时该链接符合路由规则,所以一样达到了打印输出 hello world 的效果

 

第4 章 建立控制器

4.1 控制器简介

控制器是ZF2的核心功能,其实现了前端控制器所需的所有接口。如:路由分发、视图渲染、助手、请求、响应等一系列的功能。同时也能够利用继承来设计自已的助手类或一些实用性较的插件等,来增强自已的系统功能。

4.2 新建控制器

在ZF2中,控制器是一个类一般称为{控制器名称}控制器。 请注意,{控制器名称}必须以大写字母开头。这个类保存在控制器模块目录内以名为{控制器名称}控制器类.php的文件中。 控制器的每一个操做都是在一个公共方法内的{动做名称}中完成。通常状况下{动做名称}是以小写字母开头。

 

根据前面章节的相关设置,当前项目中的全部控制器都将放在 /module/Application/src/Application/Controller 的目录下;在本章节及接下来的几个章节都以一个新闻系统来对相关的知识内容来进行讲解。

如今添加一个控制器,在控制器目录下新一个控制器 NewsController 控制器,路径:/module/Application/src/Application/Controller/NewsController.php

代码以下:

class NewsController extends AbstractActionController {}

经过以上代码便建立了一个标准的控制器类,虽然些控制器只有短短的一行代码,但他拥有操做器所需的所有基本功能;由于他已经继承了 AbstractActionController 类中的所有方法。

4.3 添加控制器的Action

下面在NewsController控制器中添加几个 Action:

public function indexAction(){

echo “NewsController indexAction”;

exit;

}

 

public function listAction(){

echo “NewsController listAction”;

exit;

}

 

public function addAction(){

echo “NewsController addAction”;

exit;

}

 

public function editAction(){

echo “NewsController editAction”;

exit;

}

 

public function deleteAction(){

echo “NewsController deleteAction”;

exit;

}

注意:ZF2控制器的action方法都必需为 public 类型,否则ZF2前端控制器可能没法访问致使出错。同时应该注意action 的名称都是动做名+Action组成的,须要注意大写(若是项目未来是布置在Linux系统的服务器上时这点就显得尤其重要)。

 

通过添加以上的代码就创建了NewsController 控制器中创建了5个不一样的action,在此就能够利用这5个不一样的action 来实现5个不一样的功能。下面说明一下上面添加的5个 action 的主要做用,indexAction 为控制器的默认action ;listAction 用来实现新闻列表功能;addAction 用来实现添加新闻的功能;editAction 用来实现修改/编辑新闻功能;deleteAction 用来实现删除新闻的功能。

 

有了控制器及控制器的action,那么是否就能够直接经过 http://localhost/news 来对NewsController进行访问了呢?答案是否认的。在前面的章节有提到过关于路由的概念或相关的内容,ZF2 中的全部控制的访问都须要先经过对控制器路由设定才能进行使用,没有通过路由设置的控制器就至关于一部不会割草的割草机;这种路由的设定也体现了ZF2中强大的路由功能,你能够将控制器的访问路径配置成各类各样的形式,这种路由的设置模式区别于传统PHP网址路径的访问形式,传统的访问地址每每都是包括了文件名,而ZF2的路由配置规则则可彻底将文件名隐藏起来。那下面就开始对 NewsController 控制器进行路由的进行设定。

找到模块配置文件 /module/Application/config/module.config.php,打开文件并找到 router-->routes-->application 节点的未尾,在此节点的末尾添加以下代码:

'news'=>array(

'type'=>'segment',

'options'=>array(

'route'=>'/news[/:action]',

'constraints'=>array(

'action'=>'[a-zA-Z]'

),

'defaults'=>array(

'controller'=>'Application\Controller\News',

'action'=>'index'

),

),

),

注意:请确认好 application 与 news 的节点是处于同一层次

下面对 NewsController 路由配置进行解释:

lnews=>array()  表示一个路由节点,此节点的路由名称为 news

lnews-->type=>segment 表示路由使用 segment 模式进行解析

lnews-->options=>array()  表示路由配置选项

lnews-->options-->route => /news[/:action] 表示路由地址

lnews-->options-->constraints=>array() 对路由约束规则,其实就是对路由的正则匹配

lnews-->options-->constraints-->action 表示 action 的匹配规则

lnews-->defaults  表示路由默认访问的配置

lnews-->defaults-->controller 表示默认使用的控制器

lnews-->defaults-->action 表示控制器默认使用的action

 

如今能够经过

http://localhost/news         访问到 indexAction

http://localhost/news/list     访问到 listAction

http://localhost/news/add        访问到 addAction

http://localhost/news/edit    访问到 editAction

http://localhostnews/delete     访问到 deleteAction

 

经过以上的几个环节便完成了ZF2中的控制器的建立和使用,因而可知ZF2的使用比较ZF1更为复杂,也能够看出路由的设置及访问方式更加的灵活。在ZF2框架中控制器、视图、模型 是缺一不可的一个总体体系,缺失任何一个都将损害ZF2的彻底性;致以本章节前面提到的要实现控制器中的增、删、改 的功能将会在视图及模型章节中加以补充。

 

第 5 章 建立视图模板

视图是任何网站应用程序不可或缺的一个组成部分,它提供了与用户交互的良好界面,也提供了数据输入与输出的接口。ZF2 视图类主要有 Zend\View 包,其主要功能简单的说包括:变量传递,数据转换、视图渲染、请求映射、渲染策略、响应策略等。此外ZF2还经过 Zend\MVC\View 提供了事件侦听的一系列包,在进行项目开发的时候能够根据需求加入侦听事件。下面开始建立视图并开始使用他们。

5.1 建立模板

为要呼应本书各章节的内容,在此将创建三种模板:布局模板、错误异常模板、控制器模板

5.1.1 创建布局目录

路径:/module/Application/view/layout

此目录主要用来放置网站应用程序的布局文件,在建站的时候能够根据页面的不一样须要来选择不一样的布局文件。布局的功能能够实现不一样模块不一样布局,不一样模块相同布局的实际须要。

5.1.2 创建布局文件

路径:/module/Application/view/layout/layout.phtml

在此须要注意一下,ZF2默认的视图文件均以.phtml 为后缀名,若是有其余特殊要求能够修改成其余的后缀名

5.1.3 创建错误异常目录

路径:/module/Application/view/error

在此目录下主要用来放置一些关于错误异常处理的模板文件

5.1.4 创建错误异常模板文件

/module/Application/view/error/index.phtml   错误异常信息显示模板文件

/module/Application/view/error/404.phtml       404错误异常信息显示模板文件

5.1.5 创建 NewsController 模板目录

路径:/module/Application/view/application/news

此目录主要用放置 NewsController 中Action 对应的模板文件。通常状况一个控制会对应一个模板目录,同时模版目录的名称与与控制的名称一致(不包含Controller)。

5.1.6 创建 NewsController 对应的Action 模板文件

l/module/Application/view/application/news/index.phtml  indexAction 使用的模板文件

l/module/Application/view/application/news/list.phtml    listAction 使用的模板文件

l/module/Application/view/application/news/add.phtml    addAction   使用的模板文件

l/module/Application/view/application/news/edit.phtml    editAction  使用的模板文件

l/module/Application/view/application/news/delete.phtml  deleteAction 使用的模板文件

从上面的4个模板文件能够看出一个规律,模板的文件名都是控制器Action 的名称。其实在ZF2里面有一个默认规定,那就是在各个Action 进行模板渲染里默认搜索与Action名相同的模板文件,因此在会命名模板文件名的时候须要注意。若是不想使用默认的模板对应名称,能够在控制器中返回模板时经过 setTemplate() 函数来设置自已须要的模板文件。为了方便项目的往后维护做者在此也建议不一样的action对就不一样的模板。

5.1.7 视图中经常使用函数

l$this->doctype()   指定文件的文档类型

l$this->headTitle()->appendName() 输出文件标题

l$this->headMeta() 设置并输出文件的Meta 属性

l$this->headLink() ->prependStylesheet() 加载格式表文件

l$this->headScript()->prependFile() 加载 js 文件

l$this->basePath()    获取网站根路径

l$this->navigation()->menu() 输出导航菜单

l$this->url()            设置超连接

l$this->content        输出页面内容(其实就是将其余页面的内容输出到布局页面上来)

l$this->escapeHmtl()  过滤HTML标签

l$this->translate()   进行语言转换(若是有设置多国语言支持)

以上是一些相对较为经常使用的函数功能,其余的函数能够查看Zend\View\Renderer\PhpRenderer.php 文件中的相关描述

5.2 模板配置

创建好布局文件、模板文件以后须要对他们进行配置,以便后续使用中可以让ZF2自动的搜索并加载模板文件。其实对模板的配置在前面的章节已经有一些讲解,由于模板的配置也是一个重点的内容,在此对模板的配置再详细的解释一遍。打开文件:/module/Application/config/module.config.php 在配置文件中加入以下代码(已有就不用添加):

'view_manager' => array(

        'display_not_found_reason' => true,

        'display_exceptions' => true,

        'doctype' => 'HTML5',

        'not_found_template' => 'error/404',

        'exception_template' => 'error/index',

        'template_map' => array(

            'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',

            'error/404' => __DIR__ . '/../view/error/404.phtml',

            'error/index' => __DIR__ . '/../view/error/index.phtml',

        ),

        'template_path_stack' => array(

            'application' => __DIR__ . '/../view'

        ),

),

 

view_manager 节点与 router、controllers 节点属于同一级。

lview_manager 表示此数组块为视图管理器配置信息段

lview_manager-->display_not_found_reason  是否显示404缘由

lview_manager-->display_exceptions  是否显示异常信息

lview_manager-->doctype 指定视图页面类型

lview_manager-->not_found_template 指定404的视图模板

lview_manager-->exception_template 指定异常模板文件

lview_manager-->template_map  视图模块地图

lview_manager-->template_map-->’layout/layout’ 指定布局文件

lview_manager-->template_map-->’error/404’ 指定404页面的视图文件

lview_manager-->template_map-->’error/index’ 指定错误异常页面的视图文件

lview_manager-->template_path_stack 视图模板堆栈路径

lview_manager-->template_path_stack-->application 指定模块application 视图目录所在路径

 

通过以上 创建目录、文件、配置后 NewsController 就是能够直接自动的搜索对应的布局和模板等资源文件。因为以上都只是创建了空文件,在实际应用中没有什么意义,因此接下将对布局、错误异常的模板添加一些代码,致以news 目录里的模板文件的内容将在后续的讲解中逐一的进行添加填充。

5.3 编写布局和错误异常模板

为了使全部的模板文件可以看起来足够简洁和便于理解,在模板文件的编写上将尽可能的用少的代码及多的经常使用代码来进行讲解,并且在模板文件中较多的代码仍为普通的HTML代码;因此在下面涉及到的 css 文件和 js 文件都是以空文件的形式来引用,使用空文件的缘由主要是为说明相关函数的功能特性,同时对模板文件进行解释的主要内容也在ZF2的函数上。

5.3.1  模板文件layout.phtml

下面是代码内容:

<?php echo $this->doctype();  ?>

<html>

    <head>

        <meta charset="utf-8">

        <?php echo $this->headTitle($this->translate('doc title'));  ?>

        <?php echo $this->headMeta()->appendName('viewport', 'width=device-width, initial-scale=1.0');  ?>

        <?php echo $this->headLink()->prependStylesheet($this->basePath() . '/css/style.css'); ?>

        <?php echo $this->headScript()->prependFile($this->basePath() . '/js/jquery.min.js'', 'text/javascript');?>

    </head>

    <body>

        <table border="1" cellspacing="0" cellspadding="0" width="100%">

            <tr>

                <td>header</td>

            </tr>

            <tr><td><?php echo $this->content; ?></td></tr>

            <tr><td>footer</td></tr>

        </table>

    </body>

</html>

 

模板内容解释:

lecho $this->doctype()  文档使用的类型,这个类型与在模块配置文件中设置的类型有关

lecho $this->headTitle();  输出文档标题

l$this->translate('doc title') 转换文档标题,此函数功能的实现须要语言包的支持

lecho $this->headMeta() 输出HTML人 Meta 属性

lappendName('viewport', 'width=device-width, initial-scale=1.0') 设置Meta 属性的具体内容

lecho $this->headLink()  输出link标签

lprependStylesheet($this->basePath() . '/css/style.css')  设置link标签属性

l$this->basePath()   获取站点根路径

lecho $this->headScript() 输出 script 标签

lprependFile($this->basePath() . '/js/jquery.min.js'', 'text/javascript') 设置 script 标签属性

lecho $this->content  输出控制器对应的模板页面内容

以上的内容就是一个简单的layout 而已模板,没有复杂的代码,没有复杂的样式;布局的结构最后将呈现出  上-中-下 的三行结构;上部放置导航内容,中部放置页面主要内容,下部放置版权信息等。因此最终看到的界面大概以下所示:

header    头部内容

content   正文内容

footer    底部内容

 

5.3.2  错误异常模板 index.phtml

下面是代码内容:

<h1><?php echo $this->translate('An error occurred') ?></h1>

<h2><?php echo $this->message ?></h2>

<?php if (isset($this->display_exceptions) && $this->display_exceptions): ?>

<?php if(isset($this->exception) && $this->exception instanceof Exception): ?>

<hr/>

<h2><?php echo $this->translate('Additional information') ?>:</h2>

<h3><?php echo get_class($this->exception); ?></h3>

<dl>

    <dt><?php echo $this->translate('File') ?>:</dt>

    <dd>

        <pre class="prettyprint linenums"><?php echo $this->exception->getFile() ?>:<?php echo $this->exception->getLine() ?></pre>

    </dd>

    <dt><?php echo $this->translate('Message') ?>:</dt>

    <dd>

        <pre class="prettyprint linenums"><?php echo $this->exception->getMessage() ?></pre>

    </dd>

    <dt><?php echo $this->translate('Stack trace') ?>:</dt>

    <dd>

        <pre class="prettyprint linenums"><?php echo $this->exception->getTraceAsString() ?></pre>

    </dd>

</dl>

<?php

    $e = $this->exception->getPrevious();

    if ($e) :

?>

<hr/>

<h2><?php echo $this->translate('Previous exceptions') ?>:</h2>

<ul>

    <?php while($e) : ?>

    <li>

        <h3><?php echo get_class($e); ?></h3>

        <dl>

            <dt><?php echo $this->translate('File') ?>:</dt>

            <dd>

                <pre class="prettyprint linenums"><?php echo $e->getFile() ?>:<?php echo $e->getLine() ?></pre>

            </dd>

            <dt><?php echo $this->translate('Message') ?>:</dt>

            <dd>

                <pre class="prettyprint linenums"><?php echo $e->getMessage() ?></pre>

            </dd>

            <dt><?php echo $this->translate('Stack trace') ?>:</dt>

            <dd>

                <pre class="prettyprint linenums"><?php echo $e->getTraceAsString() ?></pre>

            </dd>

        </dl>

    </li>

    <?php

        $e = $e->getPrevious();

        endwhile;

    ?>

</ul>

<?php endif; ?>

<?php else: ?>

<h3><?php echo $this->translate('No Exception available') ?></h3>

<?php endif ?>

<?php endif ?>

 

代码解释:

lecho $this->message    输出错误信息

lif (isset($this->display_exceptions) && $this->display_exceptions)  判断是否显示异常信息

lecho get_class($this->exception) 输出异常类型名称

lecho $this->exception->getFile()  输出致使异常的文件名

lecho $this->exception->getLine()  输出致使异常文件的所在行

lecho $this->exception->getMessage()       输出异常信息

lecho $this->exception->getTraceAsString()  输出异常堆栈信息

l$e = $this->exception->getPrevious()  获取上一个异常

以上是错误异常模板内容,模板可以输出致使错误异常的文件名、出错所在行、错误类型等信息。在开发项目的时候即可以经过错误的信息提示来查找相关出错缘由。理解并正确使用使用错误信息可以有效的提升开发效率。

5.3.3  404错误模板 404.phtml

下面是代码内容:

<h1><?php echo $this->translate('A 404 error occurred') ?></h1>

<h2><?php echo $this->message ?></h2>

<?php if (isset($this->reason) && $this->reason): ?>

<?php

$reasonMessage= '';

switch ($this->reason) {

    case 'error-controller-cannot-dispatch':

        $reasonMessage = $this->translate('The requested controller was unable to dispatch the request.');

        break;

    case 'error-controller-not-found':

        $reasonMessage = $this->translate('The requested controller could not be mapped to an existing controller class.');

        break;

    case 'error-controller-invalid':

        $reasonMessage = $this->translate('The requested controller was not dispatchable.');

        break;

    case 'error-router-no-match':

        $reasonMessage = $this->translate('The requested URL could not be matched by routing.');

        break;

    default:

        $reasonMessage = $this->translate('We cannot determine at this time why a 404 was generated.');

        break;

}

?>

<p><?php echo $reasonMessage ?></p>

 

<?php endif ?>

 

<?php if (isset($this->controller) && $this->controller): ?>

 

<dl>

    <dt><?php echo $this->translate('Controller') ?>:</dt>

    <dd><?php echo $this->escapeHtml($this->controller) ?>

<?php

if (isset($this->controller_class)

    && $this->controller_class

    && $this->controller_class != $this->controller

) {

    echo '(' . sprintf($this->translate('resolves to %s'), $this->escapeHtml($this->controller_class)) . ')';

}

?>

</dd>

</dl>

<?php endif ?>

<?php if (isset($this->display_exceptions) && $this->display_exceptions): ?>

<?php if(isset($this->exception) && $this->exception instanceof Exception): ?>

<hr/>

<h2><?php echo $this->translate('Additional information') ?>:</h2>

<h3><?php echo get_class($this->exception); ?></h3>

<dl>

    <dt><?php echo $this->translate('File') ?>:</dt>

    <dd>

        <pre class="prettyprint linenums"><?php echo $this->exception->getFile() ?>:<?php echo $this->exception->getLine() ?></pre>

    </dd>

    <dt><?php echo $this->translate('Message') ?>:</dt>

    <dd>

        <pre class="prettyprint linenums"><?php echo $this->exception->getMessage() ?></pre>

    </dd>

    <dt><?php echo $this->translate('Stack trace') ?>:</dt>

    <dd>

        <pre class="prettyprint linenums"><?php echo $this->exception->getTraceAsString() ?></pre>

    </dd>

</dl>

<?php

    $e = $this->exception->getPrevious();

    if ($e) :

?>

<hr/>

<h2><?php echo $this->translate('Previous exceptions') ?>:</h2>

<ul>

    <?php while($e) : ?>

    <li>

        <h3><?php echo get_class($e); ?></h3>

        <dl>

            <dt><?php echo $this->translate('File') ?>:</dt>

            <dd>

                <pre class="prettyprint linenums"><?php echo $e->getFile() ?>:<?php echo $e->getLine() ?></pre>

            </dd>

            <dt><?php echo $this->translate('Message') ?>:</dt>

            <dd>

                <pre class="prettyprint linenums"><?php echo $e->getMessage() ?></pre>

            </dd>

            <dt><?php echo $this->translate('Stack trace') ?>:</dt>

            <dd>

                <pre class="prettyprint linenums"><?php echo $e->getTraceAsString() ?></pre>

            </dd>

        </dl>

    </li>

    <?php

        $e = $e->getPrevious();

        endwhile;

    ?>

</ul>

<?php endif; ?>

<?php else: ?>

<h3><?php echo $this->translate('No Exception available') ?></h3>

<?php endif ?>

<?php endif ?>

 

代码解析:

lecho $this->message   输出错误信息

lif (isset($this->reason) && $this->reason)  判断是否存在错误,$this->reason 有多种类型,控制器路由分发错误(error-controller-cannot-dispatch)、控制器不存在(error-controller-not-found)、无效控制器(error-controller-invalid)、路由不匹配(error-router-no-match)及其余

l$this->controller 表示控制器名

l$this->controller_class 表示控制器类名

以上内容是404错误提示模板内容;模板可以输出致使错误异常的文件名、出错所在行、错误类型等信息。在后继开发中能够经过404的相关提示信息找到出错的问题点。

5.4 编写Action 对应的模板文件

针对于 Action 对应的模板文件在此就先只写一个indexAction 对应的模板文件,其余各个Action对应的模板文件内容将在后续的讲解中添加,以便与其余内容相互对应。

下面是 index.phtml 内容:

<table border="1">

<tr>

<td>Welcome to ZF2 world</td>

</tr>

</table>

模板的内容极其简单,就是一个表格并在单元格中有句 Welcome to ZF2 world,他的意义就是在访问 indexAction 的时候能够在页面上看 Welcome to ZF2 world。

5.5 访问 IndexAction

通过以上众多的准备工做,如今咱们已经能够经过 http://localhost/news 来访问到咱们的 NewsController 控制器的indexAction 对应的模板了。在访问地址前咱们先将以前文件 /module/Application/src/Application/Controller/NewsController.php 中的indexAction 函数进行一些修改。具体修改以下:

public function indexAction(){

       $view = new ViewModel();

       return $view;

}

 

讲解:

l$view = new ViewModel()       实例化一个视图模型,视图模型前面已经讲解,主要是用来解析模板

lreturn $view 将视图模型返回给前端控制器

如今能够经过 http://localhost/news 来打开咱们的网页了,这时咱们的页面应该显示以下相似表格:

header

Welcome to ZF2 world

footer

这个表格就是咱们在 index.phtml模板中编写的表格。但为何会在 Welcome to ZF2 world 的上面出现header,下面出footer 呢?其实header和footer 是由咱们的layout 布局模板所产生的,前面在讲解布局模板文件的时候咱们有说到咱们的布局是 “上-中-下“这样的一个结构;header 就是表示咱们未来的导航条,footer 就是表示咱们未来的版权信息。

经过上面的代码能够看出 $view 视图模型并无指定使用的模板文件,但ZF2却可以准确的找到 index.phtml模板文件。这是由于ZF2的默认模板搜索机制就是直接查找对应模块下的视图目录,而后再根据模块配置信息(module.config.php)来搜索相关目录。其完整的搜索模式以下:

① 先到达模块下的视图目录

② 根据控制器名称在视图目录找与控制器名称相同的视图子目录

③ 根据action名称最终在视图子目录下找到与action名相同的模板文件

若是只是须要访问一个默认的模板文件的话,还有一个更简单的方式,就是在Action 函数里什么也不写直接一个空函数,这样控制器也能够根据框架的默认模板使用规则找到对应的模板。那固然你也能够经过$view视图模型来指定你想使用的视图模板。

以上内容就是关于视图模板使用的主要内容,模板样式能够根据自已或用户的需求进行各类各样的定制,能够把UI模板作得丰富多彩、漂亮。

第 6 章 建立模型

模型不只是ZF2的重要组成部分,同时也是众MVC框架的重要组成部分。他的重要性主要在于处理用户与数据库之间的访问与操做功能。ZF2 自己并不直接直接提供 Zend\Model 组件,由于模型是一种业务逻辑,针对不一样的项目可能会用不一样的商业业务处理逻辑,模型的具体工做流程取决于你对相关模型组件个体设计。虽然ZF2自己并不提供模型,但ZF2提供了不少用于实现用户模型的各类组件,用户用经过ZF2提供的组件来构建自已的模型类,而且能够经过映射器对其进行映射,以方便应用程序的前端控制对他进行引用及使用,最终实现对数据库的一系列操做。

 

模型类的编写没有一个统一的写法,不一样的人有不一样的想法及写法,不一样的业务逻辑有不一样的实现方法,最终需求根据实际状况进行编写。在本章节中将介绍两种做者在开发中经常使用到的写法,一种是ORM对象映射技术,另外一种是自定义对象。本章节的内容会结合前面章节中包括内容 控制器、视图模板等,同时也会涉及到ZF2 Zend\Db,Zend\Form 等相关知识内容进行综合的讲解。

6.1 ORM 对象映射法

ORM 对象映射法是在ZF2开发指南中引用的一种模型编写方法,能够看成是ZF2的推荐写法,此方法的实现主要经过TableGateway(做者称为数据库网关);此方法经过Di来实现,对其进行引用前须要对他作相关配置工做;总的来讲引用简单、模型与模块关联性较强。

在编写模型代码前先进行数据表的设计,数据表建立在Mysql数据库的test默认数据库里表名为news;如下里数据表的设计及多条测试数据。

CREATE TABLE news (id int(10) NOT NULL AUTO_INCREMENT,title varchar(100) NOT NULL,content varchar(1000) NOT NULL,PRIMARY KEY(id));

INSERT INTO news(title,content) VALUES(‘First news’,’This is the first news’);

INSERT INTO news(title,content) VALUES(‘Second news’,’This is the second news’);

INSERT INTO news(title,content) VALUES(‘Third news’,’This is the third news’);

INSERT INTO news(title,content) VALUES(‘fourth news’,’This is the fourth news’);

INSERT INTO news(title,content) VALUES(‘Fifth news’,’This is the fifth news’);

INSERT INTO news(title,content) VALUES(‘Sixth news’,’This is the sixth news’);

已经有了数据库、数据表、数据须要对数据库的访问属性(数据库适配器Adapter)进行设置后模型才可以正常的链接到咱们的数据库,找到文件 /config/autoload/global.php 文件内容以下:

return array(

    'db' => array(

        'driver' => 'Pdo',

        'dsn' => 'mysql:dbname=test;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'

        ),

    ),

);

ldb 表示数据库配置信息节点

ldriver 表示数据库使用的驱动程序类型

ldsn 数据库链接串,也称为数据源

ldriver_options 数据库驱动选项

lservice_manager 表示服务器管理器节点

lfactories 表示服务器管理器须要加载的工厂类

 

为要安全起见,将数据库的用户名与密码写入到 /config/autoload/local.php 文件,你一样也能够将他写入到global文件的db 节点中。local.php文件内容以下:

return array(

  'db' => array(

      'username' => 'root',

      'password' => ''

  ),

);

6.1.1 建立 News 类

News 类主要包括数据表中个各字段的映射,以及实现数组与对象之间的数据转换

路径:/module/Application/src/Application/Model/News.php

在文件中添加收下代码:

namespace Application\Model;

class News {

    public $id;

    public $title;

    public $content;

    public function exchangeArray($data){

        $this->id              = (isset($data['id'])) ? $data['id'] : null;

        $this->artist       = (isset($data['title'])) ? $data['title'] : null;

        $this->title        = (isset($data['content'])) ? $data['content'] : null;

    }

    public function getArrayCopy(){

        return get_object_vars($this);

}

}

代码讲解:

lpublic $id,$title,$content 这些公共变量与数据表字段一一对应

lpublic function exchangeArray($data)  对数组数据进行转换或都说是提取数组数据

lpublic function getArrayCopy() 将类属性转化为一个关联数组,方便后续的使用

 

6.1.2 建立 NewsTable 类

NewsTable 类的主要是经过TableGateway 数据网关来实现对数据库操做。

路径:/module/Application/src/Application/Model/NewsTable.php

在文件中添加如下代码:

namespace Application\Model;

use Zend\Db\TableGateway\TableGateway;

use Zend\Db\ResultSet\ResultSet;

use Zend\Db\Sql\Select;

class NewsTable {

    protected $tableGateway;

    public function __construct(TableGateway $tg)

    {

        $this->tableGateway = $tg;

    }

    public function fetchAll()

    {

        $resultSet  = $this->tableGateway->select();

        return $resultSet;

}

}

public function __construct(TableGateway $tg)  构造函数

public funciton fetchAll() 获取数据表的数据

6.1.3 使用模型读取数据库数据

在使用模型的时候须要对其余进行模块配置,以便ZF2可以地运行的时候自动加载。

6.1.3.1 模块配置

找到文件 /module/Application/Module.php ,在添加函数的时候注意导入相关的命名空间,添加函数 public function getServiceConfig(){},函数名称是固定的,ZF2会在运行的时候自动调用Module 中的所有方法。添加内容后的文件以下:

namespace Application;

use Zend\Mvc\ModuleRouteListener;

use Zend\Mvc\MvcEvent;

use Zend\Db\ResultSet\ResultSet;

use Zend\Db\TableGateway\TableGateway;

use Application\Model\News;

use Application\Model\NewsTable;

class Module {

    public function onBootstrap(MvcEvent $e){

        $eventManager = $e->getApplication()->getEventManager();

        $moduleRouteListener = new ModuleRouteListener();

        $moduleRouteListener->attach($eventManager);

    }

    public function getConfig(){

        return include __DIR__ . '/config/module.config.php';

    }

    public function getAutoloaderConfig(){

        return array(

            'Zend\Loader\StandardAutoloader'=>array(

                'namespaces'=>array(

                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__

                )

            )

        );

    }

    public function getServiceConfig(){

        return array(

            'factories'=>array(

                'Application\Model\NewsTable'=>function($sm){

                    $tg = $sm->get('NewsTableGateway');

                    $table = new NewsTable($tg);

                    return $table;

                },

                'NewsTableGateway'=>function($sm){

                    $adapter = $sm->get('Zend\Db\Adapter\Adapter');

                    $rs = new ResultSet();

                    $rs->setArrayObjectPrototype(new News());

                    return new TableGateway('news',$adapter,null,$rs);

                }

            ),

        );

    }  

}

经过以上的函数就配置好了模块对模型的引用,从函数getServiceConfig 的内容中能够看出函数自己只返回一个关联数组,这个关联数据的 键-值 都将在后续中被引用;同时也能够看出咱们目录的配置是针对news 表的操做,也是为何咱们在上面的模型中fetchAll()函数里没有看到数据表的缘由。

6.1.3.2 控制器中使用模型

找到文件 /module/Application/src/Application/Controller/NewsController.php,添加函数 public function getNewsTable(){},同时修改 public function listAction(){}函数内容,注意导入相关包;文件修改后以下:

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

use Application\Model\NewsTable;

class NewsController extends AbstractActionController{

    protected $newsTalbe;

    public function __construct(){

    }

    public function indexAction(){

       $view = new ViewModel();

       return $view;

    }

    public function listAction(){

        $paginator = $this->getNewsTalbe()->fetchAll();

        var_dump($paginator);

exit;

    }

    public function addAction(){

        echo 'NewsController addAction';

        exit;

    }

    public function editAction(){

        echo 'NewsController editAction';

        exit;

    }

public function deleteAction(){

echo 'NewsController deleteAction';

        exit;

 

    }

    public function getNewsTalbe(){

        if(!$this->newsTalbe){

            $sm = $this->getServiceLocator();

            $this->newsTalbe = $sm->get('Application\Model\NewsTable');

        }

        return $this->newsTalbe;

    }

}

lpublic function getNewsTalbe(){} 的主要工做就是完成对数据网关的实例化

l$sm = $this->getServiceLocator() 获取本地已经初化的服务管理器及服务

l$this->newsTalbe = $sm->get('Application\Model\NewsTable') 获取在模块文件中的相关函数

l$paginator = $this->getNewsTalbe()->fetchAll() 经过模型(数据网关)访问数据库

 

经过添加以上代码就能够经过 http://localhost/news/list 来查看模型对数据库的相关操做信息了。在此处只是经过 var_dump 函数对模型的操做结果进行打印输出,而并无经过模板来呈现;要想经过模板来呈现模型对数据库查询的结果还须要进行一些小的修改。

6.1.3.3 经过模板显示数据库查询结果

模板是聚集网站应用全部操做的一个最终集合点,最终将全部聚集的数据集中展示给用户。在使用模板前咱们还得修改下控制器,以便控制器能将模型操做的结果传递到模板中去。修改 listAction 控制器内容为:

public function listAction(){

        $paginator = $this->getNewsTalbe()->fetchAll();

$view = new ViewModel();

        $view->setTemplate('application/news/list.phtml');

        $view->setVariable('paginator', $paginator);

        return $view;

}

l$paginator = $this->getNewsTalbe()->fetchAll() 获取模型查询的数据

l$view = new ViewModel() 实例化一个视图模型

l$view->setTemplate('application/news/list.phtml') 设置视图模型所使用的模板

l$view->setVariable('paginator', $paginator) 给视图传递数据

lreturn $view       将视图模型返回给前端控制器

或者是使用如下代码:

public function listAction(){

        $paginator = $this->getNewsTalbe()->fetchAll();

        return new ViewModel(array('paginator'=>$paginator));

}

之后两种方法的最终结果是同样的。

 

接下来修改咱们的模板文件 /module/Application/view/application/news/list.phtml,模板的内容以下:

<table>

    <tr>

        <th>Title</th>

        <th>Content</th>

        <th>Add news</a></th>

    </tr>

    <?php foreach ($paginator as $news) : ?>

        <tr>

            <td><?php echo $this->escapeHtml($news->title); ?></td>

            <td><?php echo $this->escapeHtml($news->content); ?></td>

            <td>

                <a href="<?php echo $this->url('news', array('action' => 'edit', 'id' => $news->id));?>"><?php echo $this->translate("Edit") ?></a>

                <a href="<?php echo $this->url('news', array('action' => 'delete', 'id' => $news->id));?>"><?php echo $this->translate("Delete") ?></a>

            </td>

        </tr>

    <?php endforeach; ?>

</table>

lforeach ($paginator as $news) 使用foreach 来循环模型查询结果的数据行

lecho $this->escapeHtml($news->title)  经过对象操做方式输出新闻标题

lecho $this->escapeHtml($news->content) 经过对象操做方式输出新闻内容

lecho $this->url('news', array('action' => 'edit', 'id' => $news->id)) 经过url 方法构造编辑新的连接

lecho $this->url('news', array('action' => 'delete', 'id' => $news->id)) 经过url 方法构造删除新的连接

 

如今经过 http://localhost/news/list 看看是否是已经把以前咱们插入到数据的数据已经所有输出了呢。结果以下所示:

header

Title

Content

Add news

First news

This is the first news

Edit Delete

Second news

This is the second news

Edit Delete

Third news

This is the third news

Edit Delete

fourth news

This is the fourth news

Edit Delete

Fifth news

This is the fifth news

Edit Delete

Sixth news

This is the sixth news

Edit Delete

footer

6.1.3.4 插入数据

插入数据的功能经过添加新闻的方式来进行讲解,在使用插入数据的功能时同时涉及到过滤器、表单生成的相关内容,本小节将这三个内容进行结合讲解。

 

6.1.3.4.1 建立表单文件

添加表单文件,路径:/module/Application/src/Application/Form/NewsForm.php

内容以下:

namespace Application\Form;

use Zend\Form\Form;

class NewsForm extends Form{

    public function __construct($name='news')

    {

        parent::__construct($name);

        $this->setAttribute('method', 'post');

        $this->add(array(

            'name'=>'id',

            'type'=>'Hidden'

        ));

        $this->add(array(

            'name'=>'title',

            'type'=>'Text',

            'options'=>array(

                'label'=>'Title'

            ),

        ));

       

        $this->add(array(

            'name'=>'content',

            'type'=>'Text',

            'options'=>array(

                'label'=>'Content'

            ),

        ));

       

        $this->add(array(

            'name'=>'submit',

            'type'=>'submit',

            'attributes'=>array(

                'value'=>'Go',

                'id'=>'submit'

            ),

        ));

       

    }

}

代码解析:

lpublic function __construct($name='news')  就是一个普通的构造函数,$name 为表单名称

l$this->setAttribute('method', 'post')  设置表单属性

l$this->add(array('name'=>'id','type'=>'Hidden'));  添加一个表单隐藏域,做为新闻ID

l$this->add(array('name'=>'title','type'=>'Text','options'=>array('label'=>'Title' ))); 添加一个input 标签,做为新闻标题输入

l$this->add(array('name'=>'content','type'=>'Text','options'=>array('label'=>'Content'))); 添加一个input标签,做为新闻内容输入

l$this->add(array('name'=>'submit','type'=>'submit','attributes'=>array('value'=>'Go','id'=>'submit'))); 添加一个提交按钮

以上代码就包含了一个新闻记录所需的所有表单元素。

6.1.3.4.2 添加过滤器

文件:/module/Application/src/Application/Model/News.php 在此文件原来的基础上添加了内容,文件内容:

namespace Application\Model;

use Zend\InputFilter\Factory as InputFactory;// 新加导入包

use Zend\InputFilter\InputFilter;// 新加导入包

use Zend\InputFilter\InputFilterAwareInterface;// 新加导入包

use Zend\InputFilter\InputFilterInterface;// 新加导入包

class News implements InputFilterAwareInterface {// 添加了接口

    public $id;

    public $content;

    public $title;

    protected $inputFilter;

 

 

    public function exchangeArray($data){

        $this->id       = (isset($data['id'])) ? $data['id'] : null;

        $this->content   = (isset($data['content'])) ? $data['content'] : null;

        $this->title    = (isset($data['title'])) ? $data['title'] : null;

    }

   

    public function getArrayCopy(){

        return get_object_vars($this);

    }

 

    public function getInputFilter() {// 新添加,实现接口方法

        if(!$this->inputFilter){

            $this->inputFilter = new InputFilter();

            $factory           = new InputFactory();

            $this->inputFilter->add($factory->createInput(array(

                'name'=>'id',

                'required'=>true,

                'filters'=>array(

                    array('name'=>'Int'),

                ),

            )));

           

            $this->inputFilter->add($factory->createInput(array(

                'name'=>'content',

                'required'=>true,

                'filters'=>array(

                    array('name'=>'StripTags'),

                    array('name'=>'StringTrim'),

                ),

                'validators'=>array(

                    array(

                        'name'=>'StringLength',

                        'options'=>array(

                            'encoding'=>'UTF-8',

                            'min'=>5,

                            'max'=>100,

                        ),

                    ),

                ),

            )));

           

            $this->inputFilter->add($factory->createInput(array(

                'name'=>'title',

                'required'=>true,

                'filters'=>array(

                    array('name'=>'StripTags'),

                    array('name'=>'StringTrim'),

                ),

                'validators'=>array(

                    array(

                        'name'=>'StringLength',

                    'options'=>array(

                        'encoding'=>'UTF-8',

                        'min'=>5,

                        'max'=>100,

                    ),

                    ),

                ),

            )));

        }

        return $this->inputFilter;

    }

 

    public function setInputFilter(InputFilterInterface $inputFilter) {// 新添加,实现接口方法

        throw new \Exception('Not used');

    }代码解析:

lpublic function getInputFilter()  获取收入类型过滤器,对指定的表单元素进行过滤。

l$this->inputFilter = new InputFilter(); 实例化一个InputFilter过滤器

l$factory= new InputFactory(); 实例化一个InputFactory 输入工厂

l$this->inputFilter->add($factory->createInput(array('name'=>'id','required'=>true,'filters'=>array(array('name'=>'Int'))))); 建立过滤规则并将附加到InputFilter上,规则内容:name为id的标签为必填项,而且限制为整形输入

l$this->inputFilter->add($factory->createInput(array('name'=>'content','required'=>true,'filters'=>array(array('name'=>'StripTags'),array('name'=>'StringTrim'))'validators'=>array(array('name'=>'StringLength','options'=>array('encoding'=>'UTF-8','min'=>5,'max'=>100))))));建过滤规则并将附加到InputFilter上,此处的过滤规则为一个过滤链,规则内容:name 为 content的标签为必填项,并对其余输入进行去HTML标签(StripTags)和去空格(StringTrim)处理,同时对输入内容进一步校验,校验规则为将输入内容限制为utf-8,同时长度为5~100的个字符。

lpublic function setInputFilter(InputFilterInterface $inputFilter) 设置过滤,实现接口的方法

6.1.3.4.3 建立表单

经过上面两个小节的内容已经完成了建立表单的基本要素,下面将经过控制器中的方法来引用上面的内容来生成一个新闻表单。

打开文件:/module/Application/src/Application/Controller/NewsController.php,添加以下内容:

①导入包

use Application\Form\NewsForm;

use Application\Model\News;

②修改public function addAction(){} 函数内容,具体内容以下:

public function addAction(){

        $form = new NewsForm();

        $form->get('submit')->setValue('Add');

        $request = $this->getRequest();

        if($request->isPost()){

            $news= new News();

            $form->setInputFilter($news->getInputFilter());

            $form->setData($request->getPost());

            if($form->isValid()){

                $album->exchangeArray($form->getData());

                $this->getNewsTalbe()->saveNews($news);

                return $this->redirect()->toRoute('news');// 或者使用URL$this->redirect()->toUrl('/news/list');

            }

        }

        return array('form'=>$form);

}

addAction 函数内容代码解释:

l$form = new NewsForm();    实例化一个新闻表单

l$form->get('submit')->setValue('Add');修改新闻表单的提交按钮名称

l$request = $this->getRequest(); 获取用户请求

lif($request->isPost()){} 判断 是否为 POST请求

l$form->setInputFilter($news->getInputFilter());  为表单添加过滤器

l$form->setData($request->getPost()); 设置表单数据

lif($form->isValid()){} 判断表单是否经过校验

l$news->exchangeArray($form->getData()); 能表单数据进行转换

l$this->getNewsTalbe()->saveNews($news); 经过模型将表单提交的数据保存到数据库里

lreturn $this->redirect()->toRoute('news'); 实现路由跳转

lreturn array('form'=>$form); 返回一个表单对象

6.1.3.4.4 模板输出表单

收到从控制器中传递过来数据并将数据在模板中输出,打开文件:/module/Application/view/application/news/add.phtml,文件具体内容以下:

$form = $this->form;  // 接收到控制器传递过来的表单对象

$form->setAttribute('action',$this->url('news',array('action'=>'add')));// 设置表单的action属性

echo $this->form()->openTag($form);// 打开form表单

echo $this->formCollection($this->form);// 输出表单里的元素集合

echo $this->form()->closeTag();// 闭合form表单

此处是使用简洁法输出表单,即经过打开表单,输出表单、闭合表单这个动做一次性把表单里的全部元素输出。这种方法的好处是只用3行代码就能把表单里的所有元素输出,缺点就是所有属性都使用$form对象的默认设置属性,灵活度没那么好。另外一种表单输出的方法就是对$form表单对象里的元素一个一个输出,而且能够对表单对象元素进行相关修改,灵活度较好,但代码量较大。

 

经过前面四节的课内容如今能够经过 http://localhost/news/add 打开新闻表单了,并能够经过表单将将数据提交到数据库进行保存。页面结果以下:

header

窗体顶端

Title窗体底端

 

Content

footer

6.1.3.4.5 添加模型方法saveNews

要把新闻表单的数据可以提交到数据库中进行保存,还须要在模型中添加保存新闻的模型方法,打开模型文件 /module/Application/src/Application/Model/NewsTables.php 文件,添加以下方法:

public function saveNews(News $news)

    {

        $data = array(

            'content' =>$news->content,

            'title' =>$news->title

        );

        $id = (int) $news->id;

        if($id == 0){

            $this->tableGateway->insert($data);

        }else{

            if($this->getNews($id)){

                $this->tableGateway->update($data,array('id'=>$id));

            }else{

                throw new \Exception("Could not find row {$id}");

            }

        } 

}

代码解释:

l$data = array( 'content' =>$news->content,'title' =>$news->title);  将传递过来的数据保存到数组中,由于在ZF2中对数据的操做不少是经过数组来传递的

l$this->tableGateway->insert($data); 若是id不存在的时候将数据里的数据插入到数据库,此处实现插入功能

l$this->tableGateway->update($data,array('id'=>$id)); 若是id存在的时候,对数据库里指定id的数据行进行更新

lthrow new \Exception("Could not find row {$id}"); 若是更新出现错误则抛出一个异常

 

public function saveNews(News $news){} 方法说明 ,此方法不单用来保存添加新闻时的数据,也将用来保存更新新闻内容后的数据,即包含了插入和更新功能。

模型方法saveNews 创建好后就能够经过 http://loaclhost/news/add 来添加新闻并保存到数据库了。

6.1.3.4.6 修改新闻内容

上面一节内容已经讲解了怎么经过表单将一个新插入到数据库里,接下来就是要实现若是使用表单来修改一条新闻记录并将他保存到数据库。在前一节讲解内容的时候已经说过 saveNews 保存数据功能不只用于添加新闻,也用于新闻的修改,表单也是重用以前内容的表单,因此这些部分的内容就再也不重复进行讲解。下面将重点放在控制器的 editAction方法和edit.phtml模板中。

6.1.3.4.6.1修改模块路由

在继续制做editAction 和 edit.phtml 前我须要对咱们的module.config.php 的模块文件作一个小的修改,在修改前能够看一下以前输出的新闻列表的最后一个列中 Edit 种 Delete 的连接,看看连接地址的后面是否是没有出现咱们平时作网站时应该出现的id 值。这是因为咱们以前对模块路由的配置中并无包括对参数传递的功能,若是路由上没有配置这些传递参数的功能,即便你强行在连接地址的后面加上去也会被路由匹配规则给过滤掉,最终可能致使一个404的错误出现。

打开文件:/module/Application/config/module.config.php 将路由 news 区段修改成以下内容:

'news'=>array(

                'type'=>'segment',

                'options'=>array(

                    'route'=>'/news[/][:action][/:id]',

                    'constraints'=>array(

                        'action'=>'[a-zA-Z]*',

                        'id'=>'[0-9]+'

                    ),

                    'defaults'=>array(

                        'controller'=>'Application\Controller\News',

                        'action'=>'index'

                    ),

                ),

 ),

路由作过调整的地方:

l'route'=>'/news[/][:action]'  修改成 route'=>'/news[/][:action][/:id]',

l'id'=>'[0-9]+' 添加了路由中id 的匹配规则,只匹配数字类型的id

 

添加模型方法 public function getNews($id){},此方法功能是根据$id查找数据库中的新闻记录并返回查询结果行。打开文件:/module/Application/src/Application/Model/NewsTable.php 在文件原来的基础上添加以下内容:

public function getNews($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;

    }

模型方法内容解释:

l$id = (int) $id;  将传递过来的id强制转换为整形

l$rowset = $this->tableGateway->select(array('id'=>$id));  根据id查询新闻结果集

l$row = $rowset->current(); 取出结果集的第一行记录

lif(!$row){} 判断是否存在指定id 的新闻记录行,若是不存在则抛出一个异常

lreturn $row 返回查询结果的新闻记录行

6.1.3.4.6.2修改editAction 方法

打开文件:/module/Application/src/Application/Controller/NewsController.php,找到editAction 方法并将内容修改成以下:

public function editAction(){

        $id = (Int) $this->params()->fromRoute('id',0);

        if(!$id){

            return $this->redirect()->toRoute('news',array('action'=>'add'));

        }

        try{

            $news = $this->getNewsTalbe()->getNews($id);

        }catch(\Exception $e){

            return $this->redirect()->toRoute('news',array('action'=>'list'));

        }

        $form = new NewsForm();

        $form->bind($news);

        $form->get('submit')->setAttribute('value', 'Edit');

        $request = $this->getRequest();

        if($request->isPost()){

            $form->setInputFilter($news->getInputFilter());

            $form->setData($request->getPost());

            if($form->isValid()){

                $this->getNewsTalbe()->saveNews($news);

                $this->redirect()->toUrl('/news/list');

            }

        }

        return array('id'=>$id,'form'=>$form);

}

代码解释:

l$id = (Int) $this->params()->fromRoute('id',0);  从路由中分离id,也就是获取新闻id

lif(!$id){} 若是id 不存在则直接跳转到添加新闻页面

l$news = $this->getNewsTalbe()->getNews($id); 经过数据网关获取指定id的新闻记录

lreturn $this->redirect()->toRoute('news',array('action'=>'list')); 若是在获取新闻记录中出现异常则直接跳转到列表页

l$form = new NewsForm(); 实例化一个新闻表单

l$form->bind($news); 给表单绑定数据

l$form->get('submit')->setAttribute('value', 'Edit');设置表单提交按钮名称

l$request = $this->getRequest(); 获取用户请求

lif($request->isPost()){} 判断是否经过post提交的请求

l$form->setInputFilter($news->getInputFilter()); 为表单添加过滤器

l$form->setData($request->getPost());为表单附加数据

lif($form->isValid()){} 判断表单数据是否经过校验

l$this->getNewsTalbe()->saveNews($news);将编辑后的数据更新到数据库

l$this->redirect()->toUrl('/news/list'); 跳转到新闻列表

lreturn array('id'=>$id,'form'=>$form); 返回一个表单对象和新闻id到模板,此处的表单对象与前面章节中插入数据的表单有所区别,此表单里面的标签都已经有数据的了,而以前插入新闻的表单只是一个空的表单。

6.1.3.4.6.3修改edit.phtml模板

打开文件:/module/Applicaiton/view/application/news/edit.phtml,将文件内容修改成以下:

$form = $this->form;

$form->setAttribute('action',$this->url('news',array('action'=>'edit','id'=>$this->id))); // 设置表单的action 属性

echo $this->form()->openTag($form);// 打开form 表单

echo $this->formCollection($this->form);// 生成表单元素

echo $this->form()->closeTag();// 关闭表单

到目前为止就已经完成了新闻修改功能的所有工做,如今能够经过新闻列表中的 Edit 连接来打开修改新闻的页面了,修改新闻的页面与添加新闻的页面外观上看上去是同样的;只不过新闻修改页面多了一重判断,当指定id的新闻记录存在时则能够进行修改,若是指定的id还在,则进行的是添加功能。

6.1.3.4.7 删除新闻记录

本节将讲解关于数据库CURD中的最后一个是重要环节--数据库的删除操做,本章节所讲解的主要任务是实现对指定新闻id的删除功能。

6.1.3.4.7.1修改deleteAction 方法

打开文件:/module/Application/src/Application/Controller/NewsController.php,找到deleteAction 方法并将内容修改成以下:

public function deleteAction(){

        $id = (Int) $this->params()->fromRoute('id',0);

        if(!$id){

            $this->redirect()->toUrl('/news/list');

        }

        $request = $this->getRequest();

        if($request->isPost()){

            $del = $request->getPost('del','No');

            if($del=='Yes'){

                $id = (Int)$request->getPost('id');

                $this->getNewsTalbe()->deleteNews($id);

            }

            $this->redirect()->toUrl('/news/list');

        }

        return array('id'=>$id,'news'=>$this->getNewsTalbe()->getNews($id));

}

代码解释:

l$id = (Int) $this->params()->fromRoute('id',0) 获取新闻记录id

lif(!$id){$this->redirect()->toUrl('/news/list');} 判断是否有传递id 值,若是没有则直接跳转到新闻列表页面

lif($request->isPost()){} 判断用户请求类型是否为post 请求

l$del = $request->getPost('del','No'); 获取用户处理动做{Yes或No}

lif($del=='Yes'){} 若是用户操做就连Yes,则进行删除操做

l$id = (Int)$request->getPost('id'); 获取新闻id

l$this->getNewsTalbe()->deleteNews($id); 删除指定的新闻记录

l$this->redirect()->toUrl('/news/list'); // 完成删除后跳转到新闻列表

lreturn array('id'=>$id,'news'=>$this->getNewsTalbe()->getNews($id)); 若是用户请求为非post 请求,则返回数据给模板

6.1.3.4.7.2添加模型 deleteNews方法

打开模型文件 /module/Application/src/Application/Model/NewsTables.php 文件,添加以下方法:

public function deleteNews($id)

{

    $this->tableGateway->delete(array('id'=>$id));

}

代码解释:

$this->tableGateway->delete(array('id'=>$id)); 根据传递过来的id删除新闻记录

 

6.1.3.4.7.2修改delete.phtml模板

打开文件:/module/Applicaiton/view/application/news/delete.phtml,将文件内容修改成以下:

$title = 'Delete news';

$this->headTitle($title);

?>

<h1><?php echo $this->escapeHtml($title); ?></h1>

<p>Are you sure that you want to delete

'<?php echo $this->escapeHtml($news->title); ?>' by

'<?php echo $this->escapeHtml($news->content); ?>'?

</p>

<?php

$url = $this->url('news', array(

'action' => 'delete',

'id' => $this->id,

));

?>

<form action="<?php echo $url; ?>" method="post">

<div>

<input type="hidden" name="id" value="<?php echo (int) $news->id; ?>" />

<input type="submit" name="del" value="Yes" />

<input type="submit" name="del" value="No" />

</div>

</form>

代码解释:

l$this->headTitle($title);  设置文件标题

lecho $this->escapeHtml($news->title);  输出新闻标题

lecho $this->escapeHtml($news->content); 输出新闻内容

l$url = $this->url('news', array('action' => 'delete','id' => $this->id)); 构造表单的action连接

以上为主要的php内容,致以表单中其余的html代码就再也不作解释。下面转到新闻列表页面,http://localhost/news/list

在新闻列表中点击Delete将跳转到删除的确认页面,而后确认是否删除。

6.2 使用分页导航

当天新闻记录不断增长的时候,必然致使新闻列表不的加长以至用户不能在一屏内显示完全部内容,导致用户须要不停的拉动滚动条来获取更多的内容,这样无形之中给用户浏览新闻添加了很多障碍;所以对数据进行分页将是必然。以前作过网站的都应该知道分页样式及功能的实现有多种方法,分页能够根据不一样的须要进行定制,但有一个缺点就是开发者基本上都须要自已写一个分页类库来加以调用。ZF2为了减小开发自已类库的麻烦ZF2类库自己就已经集成了分页的类库,ZF2提供的分页类库简单易用,开发都也能够根据须要重写分页类或对分类的CSS样式进行从新设定;接下来的内容将重点讲解ZF2分页类库的使用方法。

6.2.1 修改模块配置文件

打开文件 /module/Application/config/module.config.php,对news 路由区段块进行修改,具体修改内容以下:

'news'=>array(

                'type'=>'segment',

                'options'=>array(

                    'route'=>'/news[/][:action][[/:id][/page/:page]]',

                    'constraints'=>array(

                        'action'=>'[a-zA-Z]*',

                        'id'=>'[0-9]+',

                        'page'=>'[0-9]+',

                    ),

                    'defaults'=>array(

                        'controller'=>'Application\Controller\News',

                        'action'=>'index'

                    ),

                ),

)

修改的地址:

l'route'=>'/news[/][:action][/:id]' 修改成 'route'=>'/news[/][:action][[/:id][/page/:page]]' 此处修改的主要做用是为使用路由能匹配出/page/n 这样的分页连接路径

l添加page'=>'[0-9]+' 路由正则区别规则

6.2.2 修改模型文件

打开文件 /module/Application/src/Model/NewsTable.php,修改public function fetchAll(){}函数,具体内容以下:

public function fetchAll($paginated=false)

    {

        if($paginated){

            $select = new Select('news');

            $rs = new ResultSet();

            $rs->setArrayObjectPrototype(new News());

            $pageAdapter = new DbSelect($select,$this->tableGateway->getAdapter(),$rs);

            $paginator = new Paginator($pageAdapter);

            return $paginator;

        }

        $resultSet  = $this->tableGateway->select();

        return $resultSet;

}

代码解释:

lif($paginated){} 判断是否使用分页

l$select = new Select('news'); 实例化一个 select ,对指定表进行操做

l$rs = new ResultSet(); 实例化一个结果集,用来保存查询结果

l$rs->setArrayObjectPrototype(new News()); 设置结果集的操做属性

l$pageAdapter = new DbSelect($select,$this->tableGateway->getAdapter(),$rs); 实例化一个DbSelect,并经过数据网关及select来对数据库进行操做,并将最终结果传递到$rs结果集中

l$paginator = new Paginator($pageAdapter);  实例化一个分页导航,并将DbSelect 传递过去

lreturn $paginator; 返回分页导航实例

6.2.3 修改控制器文件

打开文件 /module/Application/src/Application/Controller/NewsController.php,对public function listAction(){} 方法进行修改,具体内容以下:

public function listAction(){

        $paginator = $this->getNewsTalbe()->fetchAll(true);

        $paginator->setCurrentPageNumber((int)$this->params()->fromRoute('page',1));

        $paginator->setItemCountPerPage(5);

        return new ViewModel(array('paginator'=>$paginator));

}

代码解释:

l$paginator = $this->getNewsTalbe()->fetchAll(true); 表示使用分页技术进行操做

l$paginator->setCurrentPageNumber((int)$this->params()->fromRoute('page',1)); 设置当前页,若是不存在页面则默认设置为第一页

l$paginator->setItemCountPerPage(5);设置每一个分页将显示的记录行数

lreturn new ViewModel(array('paginator'=>$paginator)); 将分页导航对象返回给模板调用

6.2.4 添加分页导航模板

添加文件 /module/Application/view/application/partial/parginator.phtml, 具体内容以下:

<?php if ($this->pageCount): ?>

    <div class="pagination pagination-centered">

        <ul>

            <!-- Previous page link -->

            <?php if (isset($this->previous)): ?>

                <li>

                    <a href="<?php echo $this->url($this->route) . $this->action; ?>/page/<?php echo $this->previous;?>"><<</a>

        </li>

        <?php else: ?>

                       <li class="disabled">

                       <a href="#">

                            <<

                        </a>

                </li>

            <?php endif; ?>

                    <?php foreach ($this->pagesInRange as $page): ?>

                        <?php if ($page != $this->current): ?>

                    <li>

                        <a href="<?php echo $this->url($this->route) . $this->action; ?>/page/<?php echo $page; ?>">

                    <?php echo $page; ?>

                        </a>

                    </li>

                <?php else: ?>

                    <li class="active">

                        <a href="#"><?php echo $page; ?></a>

                    </li>

                <?php endif; ?>

    <?php endforeach; ?>

    <?php if (isset($this->next)): ?>

                <li>

                    <a href="<?php echo $this->url($this->route) . $this->action; ?>/page/<?php echo $this->next; ?>">

                        >>

                    </a>

                </li>

    <?php else: ?>

                <li class="disabled">

                    <a href="#">

                        >>

                    </a>

                </li>

    <?php endif; ?>

        </ul>

    </div>

<?php endif; ?>

 

代码解释:

lif ($this->pageCount) 判断分页数量决定是否显示分页导航

lif (isset($this->previous)) 判断是否有上一页

l<a href="<?php echo $this->url($this->route) . $this->action; ?>/page/<?php echo $this->previous;?>"><<</a>上一页连接

lforeach ($this->pagesInRange as $page) 循环首页连接页码

l<a href="<?php echo $this->url($this->route) . $this->action; ?>/page/<?php echo $page; ?>"><?php echo $page; ?></a>生成各页的导航连接

lif (isset($this->next)) 判断是否有下一页

l<a href="<?php echo $this->url($this->route) . $this->action; ?>/page/<?php echo $this->next; ?>">>></a>下一页连接

6.2.4 修改新闻列表模板

打开文件 /module/Appliction/view/application/news/list.phtml,在此文件末尾添加收下内容:

<?php

echo $this->paginationControl($this->paginator,'sliding',array('application/partial/paginator.phtml','News'),array('route'=>'news','action'=>'list'));

?>

此内容的主要功能是将分页模板输出。

 

通过以上内容的添加修改整合后,如今能够经过 http://localhost/news/list 看到新的新闻列表页,与以前惟一的不一样之处就是有分页导航条了,各个可能点击分页的页面数字对各个页面进行切换显示。结果以下:

header

Title

Content

Add news

First news

This is the first news

Edit Delete

Second news

This is the second news

Edit Delete

Third news

This is the third news

Edit Delete

fourth news

This is the fourth news

Edit Delete

Fifth news

This is the fifth news

Edit Delete

 

<< 1 2 >>

 

footer

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6.3 自定模型

在任何一个网站系统中数据库的操做都是一个重心核心问题,在不少时候作为一个开发都有自已已经熟练使用的一套数据库操做类库,使用自已熟悉的类库不只有助于提升开发效率,也有助于发现问题。在此做者根据自已的使用习惯套用ZF2中的相关数据库操做类库重写了一个实用模型。此节的内容重不在于类库自己,而是经过这个类库来扩展自已的思惟,以便往后能够自已的须要重写自已使用的类库。

新建模型文件:/module/Application/src/Application/Model/NewsModel.php,文件的内容以下:

namespace Application\Model;

use Zend\Db\Adapter\Adapter;

use Zend\Db\Sql\Sql;

use Zend\Db\ResultSet\ResultSet;

class NewsModel {

    protected $adapter;

    /**

     * 构造函数

     * @param Array $config 数据库链接配置

     */

    public function __construct($config=null)

    {

        if($config==null)

            $this->adapter = new Adapter(array(

                            'driver'=>'Pdo_Mysql',

                            'database'=>'test',

                            'hostname'=>'localhost',

                            'username'=>'root',

                            'password'=>''

            ));

        else

            $this->adapter = new Adapter($config);

    }

   

    /**

     * 返回查询结果的第一行数据

     * @param String $table  操做的数据表名

     * @param String $where   查询条件

     * @return  Array

     */

    public function fetchRow($table,$where=null){

        $sql = "SELECT * FROM {$table}";

        if($where!=null) $sql .= "WHERE {$where}";

        $statement = $this->adapter->createStatement($sql);

        $result = $statement->execute();

        return $result->current();

    }

   

    /**

     * 返回查询的全部结果

     * @param String $table 数据表名

     * @param String $where 查询条件

     * @return  Array

     */

    public function fetchAll($table,$where=null){

        $sql = "SELECT * FROM {$table}";

        if($where!=null) $sql .= "WHERE {$where}";

        $stmt = $this->adapter->createStatement($sql);

        $stmt->prepare();

        $result = $stmt->execute();

       

        $resultset = new ResultSet;

        $resultset->initialize($result);

        $rows = array();

        $rows = $resultset->toArray();

        return $rows;

    }

   

    /**

     * 返回指定表的全部数据

     * @param String $table 表名

     * @return  Array

     */

    public function getTableRecords($table)

    {

        $sql = new Sql($this->adapter);

        $select = $sql->select();

        $select->from($table);

        $stmt = $sql->prepareStatementForSqlObject($select);

        $result = $stmt->execute();

        $resultSet = new ResultSet();

        $resultSet->initialize($result);

        return $resultSet->toArray();

    }

   

    /**

     * 插入数据到数据表

     * @param String $table

     * @param Array $data

     * @return  Int 返回受影响的行数

     */

    public function insert($table,$data){

        $sql = new Sql($this->adapter);

        $insert=$sql->insert($table);

        $insert->values($data);

        return $sql->prepareStatementForSqlObject($insert)->execute()->getAffectedRows();

    }

   

    /**

     * 更新数据表

     * @param String $table  数据表名

     * @param String $data   须要更新的数据

     * @param String|Array $where  更新条件

     * @return  Int 返回受影响的行数

     */

    public function update($table,$data,$where){

        $sql = new Sql($this->adapter);

        $update=$sql->update($table);

        $update->set($data);

        $update->where($where);

        return $sql->prepareStatementForSqlObject($update)->execute()->getAffectedRows();

    }

   

    /**

     * 删除数据

     * @param String $table 数据表名

     * @param String|Array $where 删除条件

     * @return  Int 返回受影响的行数

     */

    public function delete($table,$where){

        $sql = new Sql($this->adapter);

        $delete = $sql->delete($table)->where($where);

        return $sql->prepareStatementForSqlObject($delete)->execute()->getAffectedRows();

    }

   

    /**

     * 返回最后插入的主键值

     * @return  Int

     */

    public function lastInsertId(){

        return $this->adapter->getDriver()->getLastGeneratedValue();

    }  

}

以上代码为一个完整的模型代码,这个模型中使用了多个ZF2中的DB类库来实现不能的功能需求,上面只是一个范例且已经对各个函数方法给出了注释,在此就不对该模型作一一详解。

6.4 章节总结

第6章节是综合性的一个章节,章节内容包含从模块配置到创建模型、模板、使用模型、模板等内容。知识要点多,掌握不易,要想可以轻松快捷的使用ZF2框架给开发提供的数据库驱动,就须要不断的练习数据操做类库的使用。本章节内容的的重点及难道就是如何使用ZF2框架提供的数据库驱动对完成对数据库的彻底操做,掌握本章节内容至少能够说已经基本完成了对ZF2的入门。为了进一步巩固前面第1章至第6章的内容,在接下来的章节里将再经过两个实例来增强ZF2的开发的重点要点内容。两个实例:一个是ZF2官网的Album实例整合应用;另外一个是用户登陆验证,使用持久性验证。

第 7 章 实例应用

在接下来的内容中将以Album 为实例模块名进行讲解, 读者可能会发现这个名字很熟悉,不错ZF2官网也有一个Album实例相似内容,官网上的对该实例的讲解比较分散,对于ZF2初入门者来讲不易掌握;之因此在本章节也以Album 来命名是由于实例的内容符合本书的要求,同时做者也为了使阅读者可以更加清晰及准确掌握相关内容知识要点;此章节的内容阅读者能够与ZF2官网的实例进行对比,找出二者之间的不一样点及相同点,但本章节的内容与官网所要表达的结果是一致,都是为让开发者掌握ZF2对数据库的基本操做。本章的全部内容都在前面6章节的内容上彻底,这样更能体现出一个网站应用的完整性。

7.1 创建Album 模块

实例内容经过一个模块来进行讲解,能够更好的了解模块之间的对比性,以及模块与模块以前的耦合性。

7.1.1创建模块目录

目录结构以下:

/module/Album  模块目录

/module/Album/config 模块配置文件目录

/module/Album/src 模块资源文件目录

/module/Album/src/Album/Controller  控制器文件目录

/module/Album/src/Album/Form 表单文件目录

/module/Album/src/Album/Model 模型文件目录

/module/Album/view 模块模板文件目录

/module/Album/view/album/album 模板文件目录

/module/Album/view/partial  其余通用模板文件目录

7.1.2 配置模块全局设置

要让一个新添加的模块加入到ZF2搭建的网站系统中就必需为对新的模块进行设置。

打开所有配置文件:/config/application.config.php 内容以下:

return array(

    'modules' => array(

        'Application',

        'Album'  // 此行为新加内容

    ),

    'module_listener_options' => array(

        'config_glob_paths' => array(

            APP_PATH.'config/autoload/{,*.}{global,local}.php',

        ),

        'module_paths' => array(

            APP_PATH.'module',

            APP_PATH.'vendor',// 就要应用于phpunit

        ),

    ),

);

此文件只添加了一个行:在modules 区块中的 ‘Album’;在前面章节的内容已经有说明,每增长一个模块都须要在全局配置文件中添加进行,也就是对模块进行注册使用。

7.2 添加模块文件

添加文件:/module/Album/Module.php,内容以下:

namespace Album;

 

use Album\Model\Album;

use Album\Model\AlbumTable;

use Zend\Db\ResultSet\ResultSet;

use Zend\Db\TableGateway\TableGateway;

class Module{

    public function getAutoloaderConfig(){

        return array(

            'Zend\Loader\StandardAutoloader'=>array(

                'namespaces'=>array(

                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,

                ),

            ),

        );

    }

    public function getConfig(){

        return include __DIR__ . '/config/module.config.php';

    }

   

    public function getServiceConfig()

    {

        return array(

            'factories'=>array(

                'Album\Model\AlbumTable'=>function($sm){

                    $tg = $sm->get('AlbumTableGateway');

                    $table = new AlbumTable($tg);

                    return $table;

                },

                'AlbumTableGateway'=>function($sm){

                    $adapter = $sm->get('Zend\Db\Adapter\Adapter');

                    $rs = new ResultSet();

                    $rs->setArrayObjectPrototype(new Album());

                    return new TableGateway('album',$adapter,null,$rs);

                }

            ),

        );

    }

   

}

代码简单解释:

lpublic function getAutoloaderConfig(){} 配置文件加载路径

lpublic function getConfig(){} 获取模块配置文件

lpublic function getServiceConfig(){} 获取模块服务配置信息

7.3 添加模块配置文件

模块配置文件主要对路由、视图等进行配置,此处配置关系到整个模块的访问方式及其余使用方式。

添加文件:/module/Album/config/module.config.php ,添加内容以下:

return array(

    'router' => array(

        'routes' => array(

            'album' => array(

                'type' => 'segment',

                'options' => array(

                    'route' => '/album[/][:action][/:id]',

                    'constraints' => array(

                        'action' => '[a-zA-Z0-9_-]*',

                        'id'=>'[0-9]*'

                    ),

                    'defaults' => array(

                        'controller' => 'Album\Controller\Album',

                        'action' => 'index'

                    ),

                ),

            ), 

        ),

    ),

    'controllers' => array(

        'invokables' => array(

            'Album\Controller\Album' => 'Album\Controller\AlbumController'

        ),

    ),

    'view_manager' => array(

        'template_path_stack' => array(

            'album' => __DIR__ . '/../view',

        ),

    ),

);

代码解释:

l'router' => array() 路径配置区块,能够包括有多条路由

l'controllers' => array() 控制器配置区块,此处能够配置控制的使用状况

l'view_manager' => array() 视图配置区块,此处配置视图存放路径;Album 模块没有再单独使用layout配置,与以前 的Application共用同一们layout布局

7.4 建立数据表 album

在此咱们仍而后前面章节提到的 test 数据库,在test数据库里添加一个album表并插入数据,具体以下:

CREATE TABLE album(id int(10) NOT NULL AUTO_INCREMENT,title varchar(100) NOT NULL,artist varchar(1000) NOT NULL,PRIMARY KEY(id));

INSERT INTO news(title,artist) VALUES(‘First album’,’artist01’);

INSERT INTO news(title,artist) VALUES(‘Second album’,’artist02’);

INSERT INTO news(title,artist) VALUES(‘Third album’,’artist03’);

INSERT INTO news(title,artist) VALUES(‘fourth album’,’artist04’);

INSERT INTO news(title,artist) VALUES(‘Fifth album’,’artist05’);

INSERT INTO news(title,artist) VALUES(‘Sixth album’,’artist06’);

7.5 添加模型文件

模型是ZF2对数据库操做的核心内容,也是进行数据过滤、数据交换的功能专区。

7.5.1 添加 Album.php

此文件包括数据交换、表单数据过滤功能;添加 /module/Album/src/Album/Model/Album.php 内容以下:

namespace Album\Model;

use Zend\InputFilter\Factory as InputFactory;

use Zend\InputFilter\InputFilter;

use Zend\InputFilter\InputFilterAwareInterface;

use Zend\InputFilter\InputFilterInterface;

class Album implements InputFilterAwareInterface {

    public $id;

    public $artist;

    public $title;

    protected $inputFilter;

    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;

    }

    public function getArrayCopy(){

        return get_object_vars($this);

    }

    public function getInputFilter() {

        if(!$this->inputFilter){

            $this->inputFilter = new InputFilter();

            $factory           = new InputFactory();

            $this->inputFilter->add($factory->createInput(array(

                'name'=>'id',

                'required'=>true,

                'filters'=>array(

                    array('name'=>'Int'),

                ),

            )));

            $this->inputFilter->add($factory->createInput(array(

                'name'=>'artist',

                'required'=>true,

                'filters'=>array(

                    array('name'=>'StripTags'),

                    array('name'=>'StringTrim'),

                ),

                'validators'=>array(

                    array(

                        'name'=>'StringLength',

                        'options'=>array(

                            'encoding'=>'UTF-8',

                            'min'=>5,

                            'max'=>100,

                        ),

                    ),

                ),

            )));

            $this->inputFilter->add($factory->createInput(array(

                'name'=>'title',

                'required'=>true,

                'filters'=>array(

                    array('name'=>'StripTags'),

                    array('name'=>'StringTrim'),

                ),

                'validators'=>array(

                    array(

                        'name'=>'StringLength',

                    'options'=>array(

                        'encoding'=>'UTF-8',

                        'min'=>5,

                        'max'=>100,

                    ),

                    ),

                ),

            )));

        }

        return $this->inputFilter;

    }

    public function setInputFilter(InputFilterInterface $inputFilter) {

        throw new \Exception('Not used');

    }

   

}

代码解释:

lpublic function exchangeArray($data){} 数据转换

lpublic function getArrayCopy(){} 克隆对象内属性

lpublic function getInputFilter() {} 过滤器

7.5.2 添加AlbumTable.php

此文件为数据库操做网关,实现对数据库的一系列操做;添加文件:/module/Album/src/Album/Model/AlbumTable.php,具体内容以下:

namespace Album\Model;

use Zend\Db\TableGateway\TableGateway;

use Zend\Db\ResultSet\ResultSet;

use Zend\Db\Sql\Select;

use Zend\Paginator\Adapter\DbSelect;

use Zend\Paginator\Paginator;

class AlbumTable {

    protected $tableGateway;

    public function __construct(TableGateway $tg)

    {

        $this->tableGateway = $tg;

    }

    public function fetchAll($paginated=false)

    {

        if($paginated){// 分页

            $select = new Select('album');

           

            $rs = new ResultSet();

            $rs->setArrayObjectPrototype(new Album());

           

            $pageAdapter = new DbSelect($select,$this->tableGateway->getAdapter(),$rs);

           

            $paginator = new Paginator($pageAdapter);

            return $paginator;

           

        }

        $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("Could not find row {$id}");

            }

        }

       

    }

    public function deleteAlbum($id)

    {

        $this->tableGateway->delete(array('id'=>$id));

    }

 

}

代码解释:

lpublic function fetchAll($paginated=false){} 获取数据表中的全部记录

lpublic function getAlbum($id){} 获取指定ID的记录行

lpublic function saveAlbum(Album $album){} 保存数据到数据库

lpublic function deleteAlbum($id){} 删除指定ID的记录行

7.6 添加表单 AlbumForm

添加文件:/module/Album/src/Album/Form/AlbumForm.php,具体内容以下:

namespace Album\Form;

use Zend\Form\Form;

class AlbumForm extends Form{

    public function __construct($name=null)

    {

        parent::__construct('album');

        $this->setAttribute('method', 'post');

        $this->add(array(

            'name'=>'id',

            'type'=>'Hidden'

        ));

        $this->add(array(

            'name'=>'title',

            'type'=>'Text',

            'options'=>array(

                'label'=>'Title'

            ),

        ));

        $this->add(array(

            'name'=>'artist',

            'type'=>'Text',

            'options'=>array(

                'label'=>'Artist'

            ),

        ));

        $this->add(array(

            'name'=>'submit',

            'type'=>'submit',

            'attributes'=>array(

                'value'=>'Go',

                'id'=>'submit'

            ),

        ));

       

    }

}

 

7.7 添加控制器 AlbumController

添加文件:/module/Album/src/Controller/AlbumController.php 具体内容以下:

namespace Album\Controller;

use Zend\Mvc\Controller\AbstractActionController;

use Zend\View\Model\ViewModel;

use Album\Model\Album;

use Album\Form\AlbumForm;

class AlbumController extends AbstractActionController{

    protected $albumTalbe;

    public function indexAction(){

        $paginator = $this->getAlbumTalbe()->fetchAll(true);

        $paginator->setCurrentPageNumber((int)$this->params()->fromQuery('page',1));

        $paginator->setItemCountPerPage(5);

        return new ViewModel(array('paginator'=>$paginator));

    }

    public function addAction(){

        $form = new AlbumForm();

        $form->get('submit')->setValue('Add');

        $request = $this->getRequest();

        if($request->isPost()){

            $album = new Album();

            $form->setInputFilter($album->getInputFilter());

            $form->setData($request->getPost());

            if($form->isValid()){

                $album->exchangeArray($form->getData());

                $this->getAlbumTalbe()->saveAlbum($album);

                return $this->redirect()->toRoute('album');

            }

        }

        return array('form'=>$form);

    }

    public function editAction(){

        $id = (Int) $this->params()->fromRoute('id',0);

        if(!$id){

            return $this->redirect()->toRoute('album',array('action'=>'add'));

        }

        try{

            $album = $this->getAlbumTalbe()->getAlbum($id);

        }catch(\Exception $e){

            return $this->redirect()->toRoute('album',array('action'=>'index'));

        }

        $form = new AlbumForm();

        $form->bind($album);

        $form->get('submit')->setAttribute('value', 'Edit');

        $request = $this->getRequest();

        if($request->isPost()){

            $form->setInputFilter($album->getInputFilter());

            $form->setData($request->getPost());

            if($form->isValid()){

                $this->getAlbumTalbe()->saveAlbum($form->getData());

                return $this->redirect()->toRoute('album');

            }

        }

        return array('id'=>$id,'form'=>$form);

    }

    public function deleteAction(){

        $id = (Int) $this->params()->fromRoute('id',0);

        if(!$id){

            return $this->redirect()->toRoute('album');

        }

        $request = $this->getRequest();

        if($request->isPost()){

            $del = $request->getPost('del','No');

            if($del=='Yes'){

                $id = (Int)$request->getPost('id');

                $this->getAlbumTalbe()->deleteAlbum($id);

            }

            return $this->redirect()->toRoute('album');

        }

        return array('id'=>$id,'album'=>$this->getAlbumTalbe()->getAlbum($id));

       

    }

    public function getAlbumTalbe(){

        if(!$this->albumTalbe){

            $sm = $this->getServiceLocator();

            $this->albumTalbe = $sm->get('Album\Model\AlbumTable');

        }

        return $this->albumTalbe;

    }

       

}

代码解释:

lpublic function indexAction(){} album默认访问action,也是album列表action

lpublic function addAction(){} 添加album 的 action

lpublic function editAction(){} 编辑修改album的action

lpublic function deleteAction(){} 删除album 的action

lpublic function getAlbumTalbe(){}  设置数据库网关

7.8 添加模板文件

模板是数据处理后的最终展示平台,也是用户操做与感知的入口。Album模块使用的模板有4个:index.phtml , add.phtml , edit.phtml , delete.phtml , paginator.phtml 分别 列表、添加、修改、删除、分页导航

7.8.1 列表模板 index.phtml

添加文件:/module/Album/view/album/album/index.phtml,内容以下:

<table>

    <tr>

        <th><?php echo $this->translate("Title") ?></th>

        <th><?php echo $this->translate("Artist") ?></th>

        <th><a href="<?php echo $this->url('album', array('action' => 'add')); ?>"><?php echo $this->translate("Add new album") ?></a></th>

    </tr>

    <?php foreach ($paginator 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));

    ?>"><?php echo $this->translate("Edit") ?></a>

                <a href="<?php echo $this->url('album', array('action' => 'delete', 'id' => $album->id));

               ?>"><?php echo $this->translate("Delete") ?></a>

            </td>

        </tr>

    <?php endforeach; ?>

</table>

<?php

 echo $this->paginationControl($this->paginator,'sliding',array('partial/paginator.phtml','Album'),array('route'=>'album'));

?>

7.8.2 列表模板 add.phtml

添加文件:/module/Album/view/album/album/add.phtml,内容以下:

<?php

$form = $this->form;

$form->setAttribute('action',$this->url('album',array('action'=>'add')));

echo $this->form()->openTag($form);

echo $this->formCollection($this->form);

echo $this->form()->closeTag();

?>

7.8.3 列表模板 edit.phtml

添加文件:/module/Album/view/album/album/edit.phtml,内容以下:

<?php

$form = $this->form;

$form->setAttribute('action',$this->url('album',array('action'=>'edit','id'=>$this->id)));

echo $this->form()->openTag($form);

echo $this->formCollection($this->form);

echo $this->form()->closeTag();

?>

7.8.4 列表模板 delete.phtml

添加文件:/module/Album/view/album/album/delete.phtml,内容以下:

<?php

$title = 'Delete album';

$this->headTitle($title);

?>

<h1><?php echo $this->escapeHtml($title); ?></h1>

<p>Are you sure that you want to delete

'<?php echo $this->escapeHtml($album->title); ?>' by

'<?php echo $this->escapeHtml($album->artist); ?>'?

</p>

<?php

$url = $this->url('album', array(

'action' => 'delete',

'id' => $this->id,

));

?>

<form action="<?php echo $url; ?>" method="post">

<div>

<input type="hidden" name="id" value="<?php echo (int) $album->id; ?>" />

<input type="submit" name="del" value="Yes" />

<input type="submit" name="del" value="No" />

</div>

</form>

7.8.5 列表模板 paginator.phtml

添加文件:/module/Album/view/partial/paginator.phtml,内容以下:

<?php if ($this->pageCount): ?>

    <div class="pagination pagination-centered">

        <ul>

            <!-- Previous page link -->

            <?php if (isset($this->previous)): ?>

                <li>

                    <a href="<?php echo $this->url($this->route); ?>?page=<?php echo $this->previous;?>"><<</a>

        </li>

        <?php else: ?>

                       <li class="disabled">

                       <a href="#">

                            <<

                        </a>

                </li>

            <?php endif; ?>

            <!-- Numbered page links -->

                    <?php foreach ($this->pagesInRange as $page): ?>

                        <?php if ($page != $this->current): ?>

                    <li>

                        <a href="<?php echo $this->url($this->route); ?>?page=<?php echo $page; ?>">

                    <?php echo $page; ?>

                        </a>

                    </li>

                <?php else: ?>

                    <li class="active">

                        <a href="#"><?php echo $page; ?></a>

                    </li>

                <?php endif; ?>

    <?php endforeach; ?>

            <!-- Next page link -->

    <?php if (isset($this->next)): ?>

                <li>

                    <a href="<?php echo $this->url($this->route); ?>?page=<?php echo $this->next; ?>">

                        >>

                    </a>

                </li>

    <?php else: ?>

                <li class="disabled">

                    <a href="#">

                        >>

                    </a>

                </li>

    <?php endif; ?>

        </ul>

    </div>

<?php endif; ?>

 

通过以上的准备工做,接下能够经过 http://localhost/album 来打开album 列表的,打开的页面结果以下所示:

header

Title

Artist

Add new album

First album

artist01

EditDelete

Second album

artist02

EditDelete

Third album

artist03

EditDelete

fourth album

artist04

EditDelete

Fifth album

artist05

EditDelete

<<  1  2  >>

 

footer

 

 

点击 列表上面的Add new album 能够进行 album 添加,页面结果以下所示:

header

窗体顶端

Title窗体底端

 

Artist

footer

 

点击列表右边的 Edit 能够对album 的信息进行修改,页面结果以下所示:

header

窗体顶端

Title窗体底端

 

Artist


footer

 

点击列表右边的 Delete 能够对album 记录进行删除,确认删除页面以下所示:

header

Delete album

Are you sure that you want to delete 'First album' by 'artist01'?

窗体顶端

 

 

窗体底端

 

footer

 

到此已经完成了对整个Album模块的的构造及功能的实现,此实例虽然没有实际的应用意义,但他已经完整的展现了在ZF2一个完整模块的存在形式,以及与其余模块同时并存且同时协同工做的具体应用,在进行具体项目开发的时候能够借鉴或参考此例以便开发出不一样功能的模块,使用项目模块可以共同协同工做。

 

第 8 章 用户认证

用户认证在项目的开发过程是一个不可或缺的重要组成部分,他的做用担负着对整个的项目的合法认证及准入机制。

8.1 创建数据表

在开始前先创建一个数据表用来存放用户的认证字段,通俗的说就是用户名与密码。还使用以前的test数据库,创建一个user表,具体内容以下:

CREATE TABLE user(id int(10) NOT NULL AUTO_INCREMENT,username varchar(100) NOT NULL,password varchar(1000) NOT NULL,PRIMARY KEY(id));

INSERT INTO news(username,password) VALUES(‘admin’,’admin’);

INSERT INTO news(username,password) VALUES(‘test’,’test’);

 

8.2 新建认证类

为了方便讲解与引用,将认证类放在Album模块的模型目录下。用户认证的方式有多种,在这里介绍的一种是做者在开发中经常使用到的一种,数据库认证的持久性认证。ZF2中的持久性认证其本质仍是经过Session来实现的,只不过开发者在开发的时候根据就不会察觉到Session在这期间的存在。ZF2在使用持久性认证的时候若是没有对认证空间进行从新命名,ZF2使用使用一个Zend_auth为其Session的默认命名空间,当你在new一个认证的实例的时候系统会自动的找到Zend_auth对应的Session命名空间。在此也能够看认证类与其余类在进行new 的时候可能会有所不一样,这种不一样也正是因为Session的相关机制所带来的。

添加文件:/module/Album/src/Album/Model.MyAuth.php,具体内容以下:

namespace Album\Model;

use Zend\Db\Adapter\Adapter as DbAdapter;

use Zend\Authentication\Adapter\DbTable  as AuthAdapter;

use Zend\Authentication\AuthenticationService;

class MyAuth {

    protected $adapter;

    public function __construct() {

        $this->adapter = new DbAdapter(array(

                      'driver'=>'Pdo_Mysql',

                      'database'=>'test',

                      'host'=>'localhost',

                      'username'=>'root',

                      'password'=>''

        ));

    }

    public function auth() {

        $authAdapter = new AuthAdapter($this->adapter);

        $authAdapter

                ->setTableName('user')             // 认证的数据表

                ->setIdentityColumn('username')     // 认证字段

                ->setCredentialColumn('password');  // 校验字段

        $authAdapter

                ->setIdentity('admin')  // 认证值

                ->setCredential('admin');// 校验值

        $auth = new AuthenticationService();

        $result = $auth->authenticate($authAdapter);

                if($result->isValid()){

            $auth->getStorage()->write($authAdapter->getResultRowObject());

            return true;

        }

       return false;

    }

    public function isAuth(){

        $auth = new AuthenticationService();

        if($auth->hasIdentity()) return true;

        return false;

    }

}

代码解释:

lpublic function auth() {} 进行认证

lpublic function isAuth(){} 经过持久性认证判断是否已经经过认证

l$authAdapter = new AuthAdapter($this->adapter); 实例为一个认证适配器

l$auth = new AuthenticationService(); 实例化一个认证服务,以实现持久性认证

8.3 引用认证类

认证类已经创建好,将在AlbumController 中进行引用,以验证认证类是否可用,打开文件:/module/Album/src/Album/Controller/AlbumController.php,添加以下两个方法:

public function authAction(){

        $auth = new \Album\Model\MyAuth();

        if($auth->auth())

            echo "Authentication Success";

        else

            echo "Authentication Failure";

        exit;

    }

    public function isauthAction(){

        $auth = new \Album\Model\MyAuth();

        if($auth->isAuth())

            echo "Already Authentication Success";

        else

            echo "Authentication Failure";

        exit;

}

代码解释:

lpublic function authAction(){} 验证是否可能对指定的用户名与密码进行认证

lpublic function isauthAction(){} 验证持久性验证是否有效

添加代码后,在浏览器中先打开:http://localhost/album/auth 查看是否经过了认证,接着在浏览器打开:http://localhost/album/isauth 查看是否在其余页面也经过了认证。

以上认证的用户名与密码做者固定的设置为了admin,这个能够根据需求进行修改。也能够根据自已的需求对MyAuth的认证类进行改进和扩展以适应具体项目的要求。

第 9 章 结束语

通过前面8个章节的讲解,本书也就能够说已经完成了他的使命;本书从零开始对ZF2框架的使用进行了一翻的讲解,内容主要包括:下载ZF2框架、搭建适合ZF2运行的服务器环境、ZF2项目的建立方法、模块的配置、模型的创建、模型的配置、控制器的创建、路由的配置、视图模板配置等一系列内容;本书的内容虽然比较简单的,讲法也比较通俗,但他的内容已经基本覆盖了通常普通项目所需的所有要素。做者自己作为一个开发者,全书的内容也是以一个开发的身份去写、去讲解,尽可能使全书的内容表达更直接,更直白,直易于理解,以便达到书名的要求--ZF2 入门教程。这个教程是做者的第一个比较大篇幅的教程,对于写教程的起因在开始写这个文章前已经有所介绍。因为国内Zend Framework2 的开发资料相对匮乏,对于刚刚接触ZF2的开发来是确实是件很头痛的事,有些时候可能在电脑盲目的弄了几天,但最后仍是连个 hello world 都没搞出来。做者但愿本书的阅读者可能从这些简单的例子入手,逐渐的去接近ZF2的核心内容。ZF系列的框架其余各类强大的功能做者也再也不重述,相信可以接触到ZF系列框架的开发者已经很明确了。

对于本书中的例子做者也作了一一的测试,所有功能均可以正常运行并到预期效果。书中例子若是在某些特定的状况下使用的话,开发者也能够根据自已的需求状况对文中的例子作进行一步扩展与完善。例如模型的功能,开发能够根据不一样的环境要求对模型进行重构或直接根据须要重写,还有多国语言支持,若是开发须要作一个大型项目也能够根据项目要求添加各个国家语言。做者在此再交但愿阅读者可以从中书的例子触类旁通进行大量反复的练习,熟练掌握ZF2框架的使用方法;而后再对ZF2框架的相关底层实现进行有针对性的研究,进而从更大的深度及广度上去使用ZF2框架。在此做者也向阅读者们推荐使用ZF官网上的开发使用手册,若是必需寻找相关的开发例程请使用Google 进行搜索,主要搜索英文网站。经过做者的相关经验ZF还有不少的英文实例的,但中文的例程可能不太多了,即便有中文的例程也免不了你抄我,我抄的习惯,因此在国内搜索出来的文章能够说是大多雷同,基本上就是直接复制粘贴行为,没人进一步的验证例程的可用性;以此同时即浪费了时间,也误导了很多开发者。

ZF官网开发帮助:http://framework.zend.com/learn/ 这里基本上能够找到你所须要的全部的ZF分类的内容,或一些简短的例子。

本书到此结束,做者真心但愿此书已经引导您进入了ZF2的世界。祝愿全部开发者一路顺利。谢谢。

相关文章
相关标签/搜索