热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

菜菜鸟ZendFramework2不完全学习涂鸦(六)数据库和模式

2019独角兽企业重金招聘Python工程师标准这几天一直在看这部分的教程,非常纠结的一篇教程,完全不能保证大家都能看懂,所以仅供参

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

这几天一直在看这部分的教程,非常纠结的一篇教程,完全不能保证大家都能看懂,所以仅供参考。

数据库(Database)和模型(Models)

一、数据库(Database)

现在我们已经建立了 Album 模块中的控制器(Controller)和 action 方法以及视图(view)代码,是时候看看我们应用程序中的模式(model)部分了。模式(model)是涉及应用程序核心目的的一部分(也称作:商业规则),在我们的例子中涉及到数据库。我们使用 ZF2 框架的 Zend\Db\TableGateway\TableGateway 类来对数据表进行查找,插入,更新和删除操作。

我们通过 PHP 的 PDO 驱动来使用 MySQL,建立一个名为 zf2tutorial 的数据库,运行以下 SQL 声明来建立唱片数据表并且插入一些数据。

CREATE TABLE album (id int(11) NOT NULL auto_increment,artist varchar(100) NOT NULL,title varchar(100) NOT NULL,PRIMARY KEY (id)
);
INSERT INTO album (artist, title)VALUES ('The Military Wives', 'In My Dreams');
INSERT INTO album (artist, title)VALUES ('Adele', '21');
INSERT INTO album (artist, title)VALUES ('Bruce Springsteen', 'Wrecking Ball (Deluxe)');
INSERT INTO album (artist, title)VALUES ('Lana Del Rey', 'Born To Die');
INSERT INTO album (artist, title)VALUES ('Gotye', 'Making Mirrors');


我们现在已经在数据库中有了些数据,可以为它写一个非常简单的模式了。

二、模式(Model)文件

ZF2 并不提供 Zend\Model 组件,应为模式(model)是你项目的业务逻辑(business logic),需要你来确定要它如何工作。你可以根据你的需要使用有很多组件。一种方法是在你的项目中为每个实体构建模式类别(model classes),并且使用对象映射(mapper objects)来调用和保存实体到数据库中。另一种方法是使用Object-relational mapping (ORM)技术,就像 Doctrine 或者 Propel。

在这个教程中,我们将建立一个非常简单的模式。每个 album object 是 Album object(把它看做实体)中,使用 Zend\Db\TableGateway\TableGateway 类创建一个 AlbumTable 类。这是一种数据表数据通道(Table Data Getway)的实现,这种设计模式顾及到了在数据库中数据的接口连接。我们意识到虽然数据表数据通道模式可能在大型系统中成为一个瓶颈,但是依然吸引我们将数据库访问代码放到控制器里的 action 方法中。这样暴露了 Zend\Db\TableGateway\AbstractTableGateway 别这么做!

在 module/Album/src/Album/Model 目录下创建一个文件 Album.php

namespace Album\Model;class Album
{public $id;public $artist;public $title;public function exchangeArray($data){$this->id = (!empty($data['id'])) ? $data['id'] : null;$this->artist = (!empty($data['artist'])) ? $data['artist'] : null;$this->title = (!empty($data['title'])) ? $data['title'] : null;}
}


我们的 Album 实体对象是一个简单的 PHP 类。为了能和 Zend\Db 的 TableGateway 一起工作,我们需要实现 exchangeArray() 方法。这个方法简单的复制来自实体属性并通过数组传入的数据。我们将在今后添加一个针对表单的输入过滤器。

接下来我们在 module/Album/src/Album/Model 目录下建立一个 PHP 文件 AlbumTable.php,并输入以下代码:

namespace Album\Model;use Zend\Db\TableGateway\TableGateway;class AlbumTable
{protected $tableGateway;public function __construct(TableGateway $tableGateway){$this->tableGateway = $tableGateway;}public function fetchAll(){$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('Form id does not exist');}}}public function deleteAlbum($id){$this->tableGateway->delete(array('id' => $id));}
}

这里有很多代码,首先我们定义了受保护的成员变量 $tableGateway,在构造函数中把 TableGateway 类型的对象传递给它。我们将为我们的唱片在数据库上使用它。

我们也创建了一些辅助函数(helper methods),我们的应用程序将使用这些辅助函数来与数据表通道接口进行交互。fetchAll() 方法从数据库中检索所有的唱片数据行,返回结果集(ResultSet),getAlbum() 方法检索单个数据行并作为唱片对象(Album object)返回,saveAlbum() 方法创建一个新的唱片数据行或者更新一个已经存在的数据行,deleteAlbum() 方法完全移除一行数据行。每个方法的代码都是简单的不用说明的。

三、使用服务管理器(ServiceManager)配置数据表通道(Table Getway)并添加到唱片数据表

为了始终为我们的 AblumTable 使用相同的接口,我们要使用服务管理器(ServiceManager)来定义如何创建这些接口。这是非常容易实现的,在 Module 类中创建一个 getServiceConfig() 的方法,这个方法会被模块管理器(ModuleManager)自动调用并且应用于服务管理器(ServiceManager)。我们现在可以在我们需要的时候在控制器中检索了。

为了配置服务管理器(ServiceManager),在服务管理器(ServiceManager)需要的时候,我们可以提供类的名称来实例化或者使用工厂模式(闭包或者回调)实例化一个对象。我们从实现 getServiceConfig() 开始,getServiceConfig() 提供了一个工厂模式来创建一个 AlbumTable。在 module/Album 目录下的 Module.php 的底部添加这个方法,代码如下:

namespace Album;// Add these import statements:
use Album\Model\Album;
use Album\Model\AlbumTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;class Module
{// getAutoloaderConfig() and getConfig() methods here// Add this method:public function getServiceConfig(){return array('factories' => array('Album\Model\AlbumTable' => function($sm) {$tableGateway = $sm->get('AlbumTableGateway');$table = new AlbumTable($tableGateway);return $table;},'AlbumTableGateway' => function ($sm) {$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');$resultSetPrototype = new ResultSet();$resultSetPrototype->setArrayObjectPrototype(new Album());return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);},),);}
}

这个方法返回一个名为 factories 的数组,在传递给服务管理器(ServiceManager)之前被模块管理器(ModuleManager)组合在了一起。Album\Model\AlbumTable 的工厂模式使用 ServiceManager 创建了一个AlbumTableGateway 并传递给 AlbumTable。我们也可以告诉 ServiceManager,获取 Zend\Db\Adapter\Adapter 后创建了 AlbumTableGateway(同样来自于ServiceManager)而且使用它创建了 TableGateway 对象。无论何时创建一个新的结果行 TableGateway 都需要使用一个 Album 对象。数据表通道(TableGetway)类使用模板模式创建结果集和实体。也就是说当需要时代替实例,系统克隆一个预先实例化的对象。参考《PHP 构造函数最佳实践和模板模式》或者更多信息。


最后我们需要配置 Servicemanager,让它知道如何得到 Zend\Db\Adapter\Adapter。为了实现这个功能需要使用一个叫 Zend\Db\Adapter\AdapterServiceFactory 的工厂模式,我们可以在混合配置系统中配置这个模式。ZF2 的模块管理器(ModuleManager)合并所有来自于每个模块的 module.config.php 文件的配置,合并后保存在 config/autoload 目录中的文件中(*.global.php 文件以及 *.local.php文件)。我们将我们的数据库配置信息添加到 global.php 文件中,这个文件你应该提交到你的版本控制软件中。如果你需要可以使用 local.php(除了VCS)来存储你数据库的证书。修改 config/autoload/global.php(在 Zend 骨架的根目录下,不是在 Album 模块中)添加以下代码:

return array('db' => array('driver' => 'Pdo','dsn' => 'mysql:dbname=zf2tutorial;host=localhost','driver_options' => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''),),'service_manager' => array('factories' => array('Zend\Db\Adapter\Adapter'=> 'Zend\Db\Adapter\AdapterServiceFactory',),),
);

你要将你数据库证书放入 config/autoload/local.php 中,因此它们不在git仓库中(因为local.php会被忽略)

return array('db' => array('username' => 'YOUR USERNAME HERE','password' => 'YOUR PASSWORD HERE',),
);

四、回到控制器(Controller)

现在 ServiceManager 可以为我们创建一个 AlbumTable 实例了,我们可以在控制器(Controller)中添加一个方法来取回这个 AlbumTable 实例,在 AlbumController 类中添加 getAlbumTable() 方法。添加的代码如下:

// module/Album/src/Album/Controller/AlbumController.php:public function getAlbumTable(){if (!$this->albumTable) {$sm = $this->getServiceLocator();$this->albumTable = $sm->get('Album\Model\AlbumTable');}return $this->albumTable;}
同时你也要在类的头部添加以下声明:

protected $albumTable;
我们现在可以在我们需要和模式(Model)进行交互时在控制器(Controller)内部调用 getAlbumTable() 方法了。

如果服务探测器(service locator)在 Module.php 内得到了正确的配置,当调用 getAlbumTable() 方法时我们会得到一个 Album\Model\AlbumTable 的实例。

五、唱片列表

为了展示唱片列表,我们需要通过模式(Model)获取并传递给视图(view)。我们要在 AlbumController 中的 indexAction() 方法中输入些代码,将 AlbumController 中的 indexAction() 方法更新为以下代码:

// module/Album/src/Album/Controller/AlbumController.php:
// ...public function indexAction(){return new ViewModel(array('albums' => $this->getAlbumTable()->fetchAll(),));}
// ...

使用 ZF2,为了在视图(view)中设定变量,我们返回了一个视图模式(ViewModel)实例。视图模式结构的第一个参数是一个数组,这个数组来自于我们需要的包含数据的 action。会自动传递给视图(view)代码。视图模式(ViewModel)对象允许我们修改已经使用的视图(view)代码,但是默认使用的是 {controller name}/{action name}。我们现在可以在 index.phtml 中输入以下代码:

// module/Album/view/album/album/index.phtml:$title = 'My albums';
$this->headTitle($title);
?>

escapeHtml($title); ?>


url('album', array('action'=>'add'));?>">Add new album








TitleArtist 
escapeHtml($album->title);?>escapeHtml($album->artist);?>url('album',array('action'=>'edit', 'id' => $album->id));?>">Editurl('album',array('action'=>'delete', 'id' => $album->id));?>">Delete

首先我们做的是设定页面的标题(在布局(Layout)中使用)并且使用 headTitle() 这个视图辅助函数(view helper)为 段落设定了标题,这将在浏览器的标题栏中显示页面标题。然后我们为新建唱片添加了一个连接。

url() 视图辅助函数(view helper)是由 ZF2 提供的被用作创建我们需要的连接。url() 的第一个参数是我们希望构建 URL 时所用到的路由名称,第二个参数是一个包含所有变量的数组,这个数组中的变量是我们需要使用的而且合适的占位符。在这个例子中,我们使用 'album' 路由,同时接受两个占位符变量:action 和 id。

我们迭代来自于我们指定的控制器(Controller)中的 action 的 $albums。ZF2 视图系统(view system)自动确定变量被提取到了视图代码的作用域之内,所以我们不必担心在变量前面的前缀 $this->,因为我们在 ZF1 中已经不得不使用到了;不管怎样你可以按照你的想法来使用。

我们然后建立了一个表格来显示每个唱片的标题和艺术家并且提供了编辑和删除记录的链接。一个标准的 foreach: 循环被用来迭代唱片列表,我们使用冒号来交替使用,并用 endforeach; 来结尾,这样的结构比使用花括号更容易检测。最后,url() 视图辅助函数(view helper)创建了编辑和删除链接。

注意:

我们始终使用 escapeHtml() 视图辅助函数(view helper)来保护我们自己的代码免受 XSS 攻击(Cross Site Scripting (XSS) vulnerabilities),具体请看(http://en.wikipedia.org/wiki/Cross-site_scripting)

如果你现在打开 http://zf2-tutorial.localhost/album,你将会看到


未完待续......谢谢







转:https://my.oschina.net/ohcoding/blog/147359



推荐阅读
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文介绍了Python对Excel文件的读取方法,包括模块的安装和使用。通过安装xlrd、xlwt、xlutils、pyExcelerator等模块,可以实现对Excel文件的读取和处理。具体的读取方法包括打开excel文件、抓取所有sheet的名称、定位到指定的表单等。本文提供了两种定位表单的方式,并给出了相应的代码示例。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Python如何调用类里面的方法
    本文介绍了在Python中调用同一个类中的方法需要加上self参数,并且规范写法要求每个函数的第一个参数都为self。同时还介绍了如何调用另一个类中的方法。详细内容请阅读剩余部分。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
author-avatar
odile微笑头
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有