ZendFramework2入门教程第6章 创建模型6.1 ORM 对象映射法

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'
        ),
    ),
);
  • db 表示数据库配置信息节点

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

  • dsn 数据库连接串,也称为数据源

  • driver_options 数据库驱动选项

  • service_manager 表示服务器管理器节点

  • factories 表示服务器管理器需要加载的工厂类

为要安全起见,将数据库的用户名与密码写入到 /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);
    }
}

代码讲解:

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

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

public 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;
    }
}

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

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

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

$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;
}

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

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

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

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

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

或者是使用以下代码:

public function listAction(){
    $paginator = $this->getNewsTalbe()->fetchAll();
    return new ViewModel(array('paginator'=>$paginator));
}

以后两种方法的最终结果是一样的。

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

Title Content Add news
escapeHtml($news->title); ?> escapeHtml($news->content); ?> translate("Edit") ?> translate("Delete") ?>

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

echo $this->escapeHtml($news->title) 通过对象操作方式输出新闻标题

echo $this->escapeHtml($news->content) 通过对象操作方式输出新闻内容

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

echo $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'
            ),
        ));
    }
}

代码解析:

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

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

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

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

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

$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');
    }

代码解析:

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

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

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

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

$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的个字符。

public 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 函数内容代码解释:

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

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

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

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

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

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

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

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

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

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

return 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}");
            }
        }
}

代码解释:

$data = array( 'content' =>$news->content,'title' =>$news->title); 将传递过来的数据保存到数组中,因为在ZF2中对数据的操作很多是通过数组来传递的

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

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

throw 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'
                    ),
                ),
 ),

路由做过调整的地方:

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

'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;
}

模型方法内容解释:

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

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

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

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

return $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);
}

代码解释:

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

if(!$id){} 如果id 不存在则直接跳转到添加新闻页面

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

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()){} 判断是否通过post提交的请求

$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); 返回一个表单对象和新闻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));
}

代码解释:

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

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

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

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

if($del=='Yes'){} 如果用户操作就连Yes,则进行删除操作

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

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

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

return 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);
?>

escapeHtml($title); ?>

Are you sure that you want to delete ' escapeHtml($news->title); ?>' by ' escapeHtml($news->content); ?>'?

url('news', array( 'action' => 'delete', 'id' => $this->id, )); ?>

代码解释:

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

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

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

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

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

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