附录A -在模型层(推动)
大部分的讨论到目前为止一直致力于构建页面,和处理请求和响应。但是一个web应用程序的业务逻辑主要依赖其数据模型。ob娱乐下载Symfony的默认模型组件是基于对象/关系映射层。ob娱乐下载Symfony会与这两个最流行的PHP orm包:推动和学说。在symfob娱乐下载ony应用程序中,您访问的数据存储在数据库中并修改它通过对象;你永远不会显式地址数据库。这维护了一个高水平的抽象和可移植性。
本章解释了如何创建一个对象数据模型,以及在推动访问和修改数据。它还演示了推动在Symfony的集成。ob娱乐下载
为什么使用一个ORM和一个抽象层?
关系数据库。PHP 5和symfob娱乐下载ony是面向对象的。为了最有效地访问数据库在一个面向对象的上下文中,一个界面翻译对象的逻辑关系逻辑是必需的。作为第一章解释说,这个接口被称为一个对象关系映射(ORM),它是由对象提供对数据的访问和保持自身业务规则。
一个ORM的主要优点是可重用性,使得数据对象的方法被称为应用程序的各个部分,甚至从不同的应用程序。ORM层还封装了数据逻辑——例如,一个论坛的计算用户评级是基于多少贡献,这些贡献是多么受欢迎。当一个页面需要显示这样一个用户评级,它只调用一个方法的数据模型,而不用担心计算的细节。如果计算变化之后,你将只需要修改评级方法在模型中,使应用程序的其余部分保持不变。
使用对象而不是记录,和类表,另一个好处:它们允许您添加新访问器的对象不一定匹配表中的一列。例如,如果你有一个表客户端
与两个字段命名first_name
和last_name
,你可能会喜欢能够仅仅需要一个的名字
。在一个面向对象的世界里,这是容易添加一个新的访问器方法客户端
类,如清单8所示。从应用程序的角度来看,没有区别FirstName
,姓
,的名字
的属性客户端
类。只有类本身可以确定哪些属性对应一个数据库列。
清单8 - 1 -读写方法掩盖了实际模型类表结构
公共函数getName(){返回这个美元- >getFirstName()。' '。这个美元- >getLastName();}
所有的重复数据访问功能和数据的业务逻辑本身可以保持这样的对象。假设您有一个ShoppingCart
你保持类项目
(对象)。获得全额的购物车结帐,编写一个自定义的方法来封装的实际计算,如清单8所示。
清单8 - 2 -读写方法掩盖了数据逻辑
公共函数getTotal(){总美元=0;foreach(这个美元- >getItems()作为美元的项目){总美元+ =美元的项目- >getPrice()*美元的项目- >getQuantity();}返回总美元;}
还有另一个重要考虑,构建数据访问过程:数据库供应商使用不同的SQL语法变异。切换到另一个数据库管理系统(DBMS)迫使你重写SQL查询的一部分,是为上一个。使用独立于数据库的语法,如果你建立你的查询,把实际的SQL翻译第三方组件,您可以切换数据库系统没有痛苦。这是数据库抽象层的目的。它迫使你查询,使用特定的语法,也符合DBMS的肮脏工作细节和优化SQL代码。
一个抽象层的主要优点是可移植性,因为它使切换到另一个数据库,甚至到一个项目。假设您需要为应用程序编写一个快速原型,但是客户还没有决定哪个数据库系统最适合他的需要。SQLite可以开始构建您的应用程序,例如,并切换到MySQL、PostgreSQL,或Oracle客户端准备决定。只改变一行在配置文件,它的工作原理。
ob娱乐下载Symfony使用推动或教义的ORM,他们使用PHP数据对象数据库抽象。这两个第三方组件,开发的推动和教义团队,无缝地集成到symfony,您可以考虑他们作为框架的一部分。ob娱乐下载他们的语法和约定,在本章所描述的,是适应,使他们不同于symfony的尽可能小。ob娱乐下载
请注意
在symfob娱乐下载ony项目中,所有的应用程序共享相同的模型。的重点项目级别:重组的应用程序依赖于共同的业务规则。这是原因,模型是独立于应用程序和存储在一个模型文件lib /模型/
在项目的根目录。
ob娱乐下载Symfony的数据库模式
为了创建symfony将使用的数据对象模型,您需要翻译的任何关系模型数据库对象数据模型。ob娱乐下载ORM需求的描述映射关系模型,这就叫做一个模式。在模式中,您定义表,他们的关系,他们的特征列。
ob娱乐下载Symfony的语法模式使用YAML格式。的schema.yml
文件必须位于myproject / config /
目录中。
请注意
ob娱乐下载Symfony也理解推动原生XML schema格式,按照“超越的模式。yml: schema.xml" section later in this chapter.
模式的例子
你如何将一个数据库结构转化为一个模式?一个例子是最好的方式来理解它。想象一下你有一个博客数据库有两个表:blog_article
和blog_comment
,结构如图1所示。
图8 - 1 -博客数据库表结构
相关的schema.yml
文件应该类似于清单8 - 3。
清单8 - 3——示例schema.yml
推动:blog_article: _attributes: {phpName:文章}id: ~标题:varchar(255)内容:用longvarchar created_at: ~ blog_comment: _attributes: {} phpName:评论id: ~ blog_article_id: ~作者:varchar(255)内容:用longvarchar created_at: ~
注意,数据库本身的名称(博客
)不出现在schema.yml
文件。相反,在描述的数据库连接名称(推动
在本例中)。这是因为实际的连接设置可以取决于您的应用程序运行的环境。例如,当您运行您的应用程序在开发环境中,您将访问一个开发数据库(也许吧blog_dev
),但具有相同生产数据库的模式。将指定的连接设置databases.yml
“数据库连接”一节中描述的文件,在本章后面。模式不包含任何详细的连接设置,只有一个连接名称、维护数据库抽象。
基本模式的语法
在一个schema.yml
文件,第一个关键表示连接的名字。它可以包含多个表,每一方都有一组列。根据YAML语法,以冒号结束键,显示的结构是通过缩进(一个或多个空间,但是没有附表)。
一个表可以有特殊的属性,包括phpName
(将生成的类的名称)。如果你不提phpName
一个表,symfony创建ob娱乐下载基于camelCase版本的表名。
提示
camelCase公约删除下划线的单词,和内心的单词的首字母大写。默认camelCase版本的blog_article
和blog_comment
是BlogArticle
和BlogComment
。本公约的名字来自首都的出现在一个长词,暗示了骆驼的驼峰。
一个表包含的列。列值可以定义在三种不同的方式:
如果你定义什么(
~
YAML相当于零
在PHP), syob娱乐下载mfony会猜测最好的属性根据列名称和描述的一些约定,将在本章后面的“空列”一节。例如,id
列在清单8 - 3不需要定义。ob娱乐下载Symfony将一个自动递增的整数,表的主键。的blog_article_id
在blog_comment
表将被理解为一个外键blog_article
表(列结束_id
被认为是外键,自动确定和相关表的第一部分列名)。列被称为created_at
自动设置的吗时间戳
类型。对于所有这些列,您不需要指定任何类型。这是其中的一个原因schema.yml
很容易写。如果只定义一个属性,它是列类型。ob娱乐下载Symfony理解常见的列类型:
布尔
,整数
,浮动
,日期
,varchar(大小)
,用longvarchar
(例如,转换文本
在MySQL),等等。对于文本内容超过256字符,您需要使用用longvarchar
类型,它没有大小在MySQL(但不能超过65 kb)。如果你需要定义其他列属性(如默认值,必需的,等等),你应该写的列属性为一组
键:值
。这个扩展模式的语法描述后面的章节。
列也可以有phpName
属性,它是大写版本的名称(Id
,标题
,内容
等等),在大多数情况下不需要重写。
表也可以包含显式的外键和索引、以及一些特定于数据库结构定义。指的是“扩展模式语法”部分在本章后面学习更多。
模型类
模式是用来构建的模型类ORM层。保存执行时间,生成这些类与命令行任务推动:建造模式
。
php syob娱乐下载mfony推动美元:建造模式
提示
建立模型后,你必须记住symfony的内部缓存ob娱乐下载php ob娱乐下载symfony cc
所以sob娱乐下载ymfony可以找到您新创建的模型。
输入这个命令将启动模式的分析和生成基础数据模型类lib /模型/ om /
你的项目目录:
BaseArticle.php
BaseArticlePeer.php
BaseComment.php
BaseCommentPeer.php
此外,实际的数据模型类将被创建lib /模型/
:
Article.php
ArticlePeer.php
Comment.php
CommentPeer.php
你只有两个表定义,最后八个文件。没有错,但它值得一些解释。
基地和定制类
为什么让两个版本的数据对象模型在两个不同的目录吗?
您可能需要添加自定义模型对象的方法和属性(考虑getName ()
方法在清单8 - 1)。但随着项目的发展,您也会添加表或列。当你改变schema.yml
文件,您需要重新生成对象模型类,使一个新的推动:建造模式。如果您的自定义方法都写在类生成,每一代后他们会被删除。
的基地
类在lib /模型/ om /
直接从模式中生成目录的。你永远不应该修改它们,因为每一个新构建的模型会完全删除这些文件。
另一方面,自定义对象类,在lib /模型/
目录,实际上继承基地
的人。当推动:建造模式
任务要求现有的模型,这些类不修改。在这里你可以添加自定义方法。
清单8 - 4给出了一个自定义的模型类的一个例子是由第一个调用推动:建造模式
的任务。
清单8 - 4 -样本模型类文件,lib /模型/ Article.php
类文章扩展BaseArticle{}
它继承的方法BaseArticle
类,但是不会影响它的修改模式。
定制类的机制扩展基类允许您开始编码,甚至不知道最终数据库的关系模型。相关的文件结构模型和可定制的进化。
对象和同行类
文章
和评论
对象类是记录在数据库中。他们给访问的列记录和相关记录。这意味着您将能够知道一篇文章的标题的文章对象调用一个方法,如清单8 - 5所示的示例。
清单8 - 5 - getter备案列对象类是可用的
美元的文章=新文章();/ /……美元的标题=美元的文章- >getTitle();
ArticlePeer
和CommentPeer
是同行类;也就是说,包含静态方法的类来操作表。它提供了一种方法,从表中检索记录。通常他们的方法返回一个对象或一个对象集合的相关对象类,见清单之后。
清单之后,静态方法来检索记录在同行类中是可用的
/ /美元的文章是一个对象数组的类文章美元的文章= ArticlePeer::retrieveByPks(数组(123年,124年,125年));
请注意
从数据模型的观点,不能有任何同行对象。这就是为什么同行类的方法叫做和::
(静态方法调用),而不是通常的- >
(比如方法调用)。
所以结合对象和同行类在基地和一个定制的版本导致四类生成的每个表中所描述的模式。事实上,有五分之一的类创建的lib /模型/地图/
目录,其中包含元数据信息表所需的运行时环境。但正如你可能永远不会改变这类,你可以忘掉它。
访问数据
在syob娱乐下载mfony中,通过访问你的数据对象。如果你习惯于关系模型和使用SQL来检索和改变你的数据,可能看起来复杂的对象模型方法。但是一旦你尝过面向对象的数据访问的力量,你可能会喜欢它。
但是,首先,让我们确保我们共享相同的词汇。关系和对象数据模型使用相似的概念,但他们每个人都有他们自己的术语:
关系 | 面向对象的 |
---|---|
表 | 类 |
行,记录 | 对象 |
场,列 | 财产 |
检索列值
symfoob娱乐下载ny构建模型时,它会创建一个基本对象类中定义的每个表schema.yml
。每个类都有默认的构造函数,访问器,对于基于列定义:新
,getXXX ()
,setXXX ()
方法帮助创建对象,给访问对象属性,如清单以8:7所示。
清单以8:7 -生成对象类的方法
美元的文章=新文章();美元的文章- >setTitle(“我的第一篇文章”);美元的文章- >setContent(“这是我的第一篇文章。\ n希望你能喜欢它!”);美元的标题=美元的文章- >getTitle();美元的内容=美元的文章- >getContent();
请注意
生成的对象类文章
,这是phpName
给了blog_article
表。如果phpName
没有模式中定义的,类被称为什么BlogArticle
。器和写值器使用camelCase列名的变体,所以getTitle ()
方法检索的值标题
列。
设置几个字段,你可以使用fromArray ()
方法,还为每个对象生成类,如清单8所示。
清单8 -fromArray ()
方法是一个多个Setter
美元的文章- >fromArray(数组(“标题”= >“我的第一篇文章”,“内容”= >“这是我的第一篇文章。\ n希望你能喜欢它!”,));
请注意
的fromArray ()
方法的第二个参数keyType
。您可以指定数组的键类型,此外通过一个类类型的常量BasePeer: TYPE_PHPNAME
,BasePeer: TYPE_STUDLYPHPNAME
,BasePeer: TYPE_COLNAME
,BasePeer: TYPE_FIELDNAME
,BasePeer: TYPE_NUM
。默认的密钥类型列的PhpName(如。“AuthorId”)。
检索相关记录
的blog_article_id
列blog_comment
隐式定义外键的表blog_article
表。每个评论与一篇文章,一篇文章可以有很多评论。生成的类包含五种方法翻译这种关系在一个面向对象的方法,如下:
$ - > getArticle评论()
:相关文章
对象$ - > getArticleId评论()
:相关的ID文章
对象评论- > setArticle美元(美元)
:定义相关的文章
对象评论- > setArticleId美元($ id)
:定义相关的文章
对象从一个ID$ - > getComments条()
:相关评论
对象
的getArticleId ()
和setArticleId ()
方法显示,您可以考虑blog_article_id
列作为常规列和设置的关系,但它们并不是很有趣。面向对象的方法的好处是更明显的三个方法。清单8展示了如何使用生成的setter。
清单8 - 9 -外键被翻译成一个特殊的Setter
美元的评论=新评论();美元的评论- >setAuthor(“史蒂夫。”);美元的评论- >setContent(“哎呀,老兄,你石:最好的文章!”);/ /附加评论前一美元的这篇文章对象美元的评论- >setArticle(美元的文章);/ /替代语法/ /只有当对象已经保存在数据库中美元的评论- >setArticleId(美元的文章- >getId());
清单8 - 10显示了如何使用生成的getter。它还演示了如何链模型对象上的方法调用。
清单8 - 10 -外键转换成特殊的getter
/ /许多关系回声美元的评论- >getArticle()- >getTitle();= >我的第一篇文章回声美元的评论- >getArticle()- >getContent();= >这是我的第一篇文章。希望你喜欢它!/ /一对多关系美元的评论=美元的文章- >getComments();
的getArticle ()
方法返回一个对象的类文章
,它的好处getTitle ()
访问器。这是比自己做的加入,这可能需要几行代码(从$ - > getArticleId评论()
调用)。
的美元的评论
变量在清单8 - 10包含类的一个对象数组评论
。你可以显示第一个评论[0]美元
或遍历集合foreach(言论评论美元)
。
请注意
定义对象模型与一个单一的名称按照惯例,现在你可以理解为什么。中定义的外键blog_comment
创建一个表原因getComments ()
通过添加一个方法,命名年代
到评论
对象名称。如果你给模型对象一个复数的名字,一代会导致一种命名方法getCommentss ()
,这没有意义。
保存和删除数据
通过调用新
构造函数,创建一个新对象,但不是一个实际的记录blog_article
表。修改数据库对象没有影响。为了保存数据到数据库,您需要调用save ()
对象的方法。
美元的文章- >保存();
ORM是足够聪明来检测物体之间的关系,所以保存美元的文章
对象还节省了相关美元的评论
对象。它也知道如果保存的对象有一个现有的数据库中对应,所以调用save ()
有时是在SQL的翻译吗插入
,有时由一个更新
。主键自动设定的save ()
方法,所以在保存,您可以检索新主键$文章- > getId ()
。
提示
你可以检查一个对象是否新通过调用isNew ()
。如果你想知道一个对象被修改和值得挽救,调用它isModified ()
方法。
如果你读评论你的文章,你可能会改变你的想法的兴趣在互联网上发布。如果你不欣赏的讽刺文章评论,您可以轻松地删除的评论delete ()
方法,如清单8所示。
清单8——从数据库删除记录delete ()
方法在相关对象
foreach(美元的文章- >getComments()作为美元的评论){美元的评论- >删除();}
提示
即使调用delete ()
方法,一个对象保持可用,直到结束的请求。来确定数据库中删除一个对象,调用isDeleted ()
方法。
检索记录的主键
如果你知道某一记录的主键,使用retrieveByPk ()
类方法对等类的相关对象。
美元的文章= ArticlePeer::retrieveByPk(7);
的schema.yml
文件定义了id
的主键字段blog_article
表,所以这条语句会返回id
7所示。当你使用主键,你知道只返回一条记录;的美元的文章
变量包含类的一个对象文章
。
在某些情况下,一个主键可能包含多个列。在这些情况下,retrieveByPK ()
方法接受多个参数,一个为每个主键列。
您也可以选择多个对象基于他们的主键,通过调用生成的retrieveByPKs ()
方法,它将一个主键数组作为参数。
检索记录与标准
当你想要检索多个记录,您需要调用doSelect ()
对等类的方法对应于您想要检索的对象。例如,检索的对象类文章
,叫ArticlePeer: doSelect ()
。
的第一个参数doSelect ()
方法是类的一个对象标准
没有定义,这是一个简单的查询定义类SQL的数据库抽象。
一个空标准
返回所有类的对象。例如,清单8 - 12中所示的代码检索所有的文章。
清单8 - 12 -通过标准检索记录doSelect ()
——空标准
$ c=新标准();美元的文章= ArticlePeer::doSelect($ c);/ /将导致以下SQL查询选择blog_article。ID, blog_article。标题、blog_article。内容,blog_article。从blog_article CREATED_AT;
侧边栏
保湿
调用::doSelect ()
实际上是更强大的比一个简单的SQL查询。首先,你选择SQL优化DBMS。其次,传递到任何值标准
逃过被集成到SQL代码之前,防止SQL注入风险。第三,方法返回一个对象数组,而不是一个结果集,ORM自动创建和填充对象基于数据库结果集,这个过程称为补水。
对于更复杂的对象选择,你需要一个等效的,秩序,组织,和其他SQL语句。的标准
所有这些条件对象方法和参数。例如,要获取所有评论写的史蒂夫,日期,下令建造一个标准
见清单8日至13日。
清单8日至13日,由标准检索记录doSelect ()
——标准与条件
$ c=新标准();$ c- >添加(CommentPeer::作者,“史蒂夫。”);$ c- >addAscendingOrderByColumn(CommentPeer::CREATED_AT);美元的评论= CommentPeer::doSelect($ c);/ /将导致以下SQL查询选择blog_comment。ARTICLE_ID,blog_comment.AUTHOR,blog_comment。内容,blog_comment。CREATED_ATFROM blog_comment WHERE blog_comment.author =“史蒂夫。”ORDER BY blog_comment。CREATED_AT ASC;
类常量作为参数传递add ()
方法指的是属性名。他们命名的大写版本的列名。例如,解决内容
列的blog_article
表,可以使用ArticlePeer:内容
类常量。
请注意
为什么要使用CommentPeer:作者
而不是blog_comment.AUTHOR
,它将输出在SQL查询的方式呢?假设您需要改变作者字段的名称贡献者
在数据库中。如果你使用blog_comment.AUTHOR
,你将不得不改变它在每一个调用模型。另一方面,通过使用CommentPeer:作者
,你只需要改变的列名schema.yml
文件,保持phpName
作为作者
和重建模型。
表8 - 1的SQL语法进行了对比分析标准
对象的语法。
表8 - 1 - SQL语法和标准对象
SQL | 标准 |
---|---|
在列=值 |
- >添加(列值); |
列< >值在哪里 |
- >添加(列、价值标准::NOT_EQUAL); |
其他比较运算符 | |
>、< |
标准::GREATER_THAN,标准::LESS_THAN |
> =,< = |
标准::GREATER_EQUAL,标准::LESS_EQUAL |
是空的,没有空 |
标准::ISNULL,标准::ISNOTNULL |
喜欢,我喜欢 |
标准:标准::我喜欢 |
的,不是 |
标准:标准:::NOT_IN |
其他SQL关键字 | |
命令列ASC |
- > addAscendingOrderByColumn(列); |
命令列DESC |
- > addDescendingOrderByColumn(列); |
限制限制 |
- > setLimit(限制) |
抵消抵消 |
- > setOffset(抵消) |
从表1,表名的地方。col1 = table2.col2 |
- > addJoin (col1, col2) |
从表1左加入表在表1。col1 = table2.col2 |
- > addJoin (col1、col2标准::LEFT_JOIN) |
从表1右加入表在表1。col1 = table2.col2 |
- > addJoin (col1、col2标准::RIGHT_JOIN) |
提示
发现和了解哪些方法是最好的方法是看在生成类基地
文件lib /模型/ om /
文件夹后一代。方法名是非常明确的,但是如果你需要更多的评论,设置propel.builder.addComments
参数真正的
在配置/ propel.ini
文件和重建模型。
清单8 - 14显示的另一个例子标准
与多个条件。获取所有史蒂夫的言论文章包含单词“享受”,下令日期。
清单8 - 14 -检索记录通过标准的另一个例子doSelect ()
——标准与条件
$ c=新标准();$ c- >添加(CommentPeer::作者,“史蒂夫。”);$ c- >addJoin(CommentPeer::ARTICLE_ID,ArticlePeer::ID);$ c- >添加(ArticlePeer::内容,“%享受%”标准::就像);$ c- >addAscendingOrderByColumn(CommentPeer::CREATED_AT);美元的评论= CommentPeer::doSelect($ c);/ /将导致以下SQL查询选择blog_comment。ID, blog_comment。ARTICLE_ID,blog_comment.AUTHOR,blog_comment。内容,blog_comment。CREATED_ATFROM blog_comment, blog_article WHERE blog_comment.AUTHOR =“史蒂夫。”和blog_article。内容如“%享受%”和blog_comment。ARTICLE_ID=blog_article。ORDER BY blog_comment ID。CREATED_AT ASC
正如SQL是一种简单的语言,它允许您构建非常复杂的查询,任何级别的标准对象可以处理条件的复杂性。但是因为许多开发人员认为首先在SQL之前将一个条件转化为面向对象的逻辑,标准
对象可能很难理解。了解它的最好办法是学习例子和示例应用程序。symfob娱乐下载ony项目网站,例如,到处都是标准
建筑的例子,在很多方面会启发你。
除了doSelect ()
方法,每一个同行类都有doCount ()
方法,它简单的计数记录的数量满足标准作为参数传递和返回数为整数。因为没有对象返回,补水过程不会发生在这种情况下,和doCount ()
方法是比doSelect ()
。
对等类也提供了doDelete ()
,doInsert ()
,doUpdate ()
方法,所有期待标准
作为参数。这些方法允许您的问题删除
,插入
,更新
查询到您的数据库。检查生成的对等类模型中对这些激励方法的更多细节。
最后,如果你想返回第一个对象,替换doSelect ()
与一个doSelectOne ()
调用。这可能是当你知道标准
将只返回一个结果,优势是,这个方法返回一个对象,而不是一个对象数组。
提示
当一个doSelect ()
查询返回大量结果,您可能希望只显示在你的反应的一个子集。ob娱乐下载Symfony提供了一个寻呼机类调用sfPropelPager
自动分页的结果。
使用原始SQL查询
有时候,你不想检索对象,但只想得到合成结果计算的数据库。例如,最新创建日期的所有文章,它没有意义的检索上的所有文章和循环数组。你喜欢问数据库只返回结果,因为它会跳过对象补水过程。
另一方面,你也不想直接调用数据库管理的PHP命令,因为你将失去数据库抽象的好处。这意味着你需要绕过ORM(推动)而不是数据库抽象(PDO)。
查询数据库和PHP数据对象要求您执行以下操作:
- 得到一个数据库连接。
- 建立一个查询字符串。
- 创建一个声明。
- 迭代的结果集上执行语句的结果。
如果这看起来像胡言乱语,你,代码在清单地位可能会更加明确。
清单和PDO地位——自定义的SQL查询
美元的连接=推动:getConnection();美元的查询=“选择马克斯(?)马克斯来自哪里?”;美元的声明=美元的连接- >准备(美元的查询);美元的声明- >bindValue(1,ArticlePeer::CREATED_AT);美元的声明- >bindValue(2,ArticlePeer::TABLE_NAME);美元的声明- >执行();$ resultset=美元的声明- >获取(PDO::FETCH_OBJ);美元最大=$ resultset- >马克斯;
就像推动选择,PDO查询是棘手当你第一次开始使用它们。再一次,从现有的应用程序例子和教程将向您展示正确的方式。
谨慎
如果你想绕过这一过程,直接访问数据库,你可能失去推动提供的安全性和抽象。做驱动的方法是更长的时间,但是它迫使你用良好的实践,保证性能,应用程序的可移植性和安全。特别是查询包含参数来自不受信任的源(如互联网用户)。推动所有必要的逃避和保护您的数据库。让你直接访问数据库sql注入攻击的风险。
使用特殊的日期列
通常,当一个表中的一列created_at
,它是用于存储时间戳日期的记录被创建。这同样适用于updated_at列,更新每次更新记录本身,当前时间的价值。
好消息是,symf欧宝平台是合法的吗ony会认出这些列的名称和ob娱乐下载处理他们的更新给你。你不需要手动设置created_at
和updated_at
列;他们将自动更新,分裂到8 - 16个。见清单这同样适用于列命名created_on
和updated_on
。
分裂到8 - 16个,清单created_at
和updated_at
列是自动处理的
美元的评论=新评论();美元的评论- >setAuthor(“史蒂夫。”);美元的评论- >保存();/ /显示创建日期回声美元的评论- >getCreatedAt();= >(日期数据库插入操作]
另外,日期列的getter接受日期格式作为参数:
回声美元的评论- >getCreatedAt(“Y-m-d”);
侧边栏
重构数据层
开发一个symfony项目时,通常先ob娱乐下载写域逻辑代码的行为。但数据库查询和操纵模型不应存储在控制器层。所有的逻辑相关的数据应该搬到模型层。每当你需要做相同的请求在不止一个地方在你的行动,考虑转移相关的代码模型。它有助于保持短的行动和可读性。
例如,假设一个博客来检索所需的代码十大最受欢迎的文章对于一个给定的标记(作为请求参数传递)。这段代码不应该在一个动作,但是在模型中。事实上,如果您需要在模板中显示这个列表,动作就应该是这个样子:
公共函数executeShowPopularArticlesForTag(美元的请求){美元的标记= TagPeer::retrieveByName(美元的请求- >getParameter(“标签”));这个美元- >forward404Unless(美元的标记);这个美元- >文章=美元的标记- >getPopularArticles(10);}
操作创建一个类的对象标签
从请求参数。然后查询数据库所需的所有代码位于一个getPopularArticles ()
这个类的方法。它使操作更具可读性,并且模型可以很容易地重用代码在另一个行动。
代码移动到一个更合适的位置是重构的技术之一。如果你经常这么做,你的代码易于维护,由其他开发人员理解。一个好的经验法则何时做重构数据层是一个动作的代码应该很少包含超过十行PHP代码。
数据库连接
数据模型是独立于数据库的使用,但是你肯定会使用一个数据库。symfony所需的最小信息发送请求到项目数据库的名称、凭证,数据库的类ob娱乐下载型。这些连接设置可以通过配置数据源名称(DSN)配置:数据库
任务:
美元php ob娱乐下载symfony的配置:数据库“mysql:主机= localhost; dbname =博客”根mYsEcret
连接设置依赖环境。您可以定义不同的设置刺激
,dev
,测试
环境中,或任何其他环境在你的应用程序使用env
选择:
美元php ob娱乐下载symfony的配置:数据库——env = dev“mysql:主机= localhost; dbname = blog_dev“根mYsEcret
这个配置也可以覆盖每个应用程序。例如,您可以使用这种方法有不同的前端和后端应用程序的安全策略,并定义多个数据库具有不同权限的用户在数据库中处理:
美元php ob娱乐下载symfony的配置:数据库——应用=前端“mysql:主机= localhost; dbname =博客”根mYsEcret
为每一个环境中,您可以定义许多连接。每个连接是指具有相同名称的模式被贴上。使用默认连接的名字推动
它指的是推动
模式在清单8 - 3。的的名字
选项允许您创建另一个连接:
美元php ob娱乐下载symfony的配置:数据库——name =主要“mysql:主机= localhost; dbname =榜样”根mYsEcret
您还可以手动输入这些连接设置databases.yml
文件位于配置/
目录中。清单8显示了一个示例的一个文件和清单仅显示了相同的示例扩展符号。
清单8 -速记数据库连接设置
:推动:类:sfPropelDatabase参数:dsn: mysql: / /登录:passwd@localhost /博客
8 - 18 - Sample数据库连接设置,清单myproject / config / databases.yml
刺激:推动:param: hostspec: mydataserver用户名:myusername密码:xxxxxxxxxx:推动:类:sfPropelDatabase参数:phptype: mysql数据库供应商hostspec: localhost数据库:博客用户名:登录密码:passwd端口:80编码:Use utf8 #表创建持久的默认字符集:真正的#使用持久连接
允许的值phptype
参数的PDO数据库系统支持:
mysql
该软件
pgsql
sqlite
甲骨文
hostspec
,数据库
,用户名
,密码
是数据库连接设置。
覆盖配置每个应用程序,您需要编辑一个特定于应用程序的文件,例如应用程序/前端/ config / databases.yml
。
如果你使用SQLite数据库,hostspec
参数必须设置为数据库文件的路径。例如,如果你保持你的博客数据库数据/ blog.db
,databases.yml
文件将类似清单8-19。
清单8-19 - SQLite数据库连接设置使用一个文件路径作为主机
:推动:类:sfPropelDatabase参数:phptype: sqlite数据库:% SF_DATA_DIR % / blog.db
扩展模型
生成的模型方法是伟大的但往往不够。只要你实现自己的业务逻辑,需要扩展它,通过添加新的方法或覆盖现有的。
添加新方法
您可以添加新的空模型类中生成的方法lib /模型/
目录中。使用这个美元
当前对象的调用方法,和使用自我::
调用当前类的静态方法。记住,定制类继承的方法基地
类位于lib /模型/ om /
目录中。
例如,对于文章
对象生成基于清单8 - 3,您可以添加一个魔法__toString ()
这呼应一个对象的类方法文章
显示其标题,如清单8-20所示。
清单8-20 -自定义模型,lib /模型/ Article.php
类文章扩展BaseArticle{公共函数__toString(){返回这个美元- >getTitle();/ /从BaseArticle getTitle()是遗传的}}
你也可以扩展对等类——例如,添加一个方法来检索所有文章命令创建日期,如清单8至21所示。
清单8至21 -自定义模型,lib /模型/ ArticlePeer.php
类ArticlePeer扩展BaseArticlePeer{公共静态函数getAllOrderedByDate(){$ c=新标准();$ c- >addAscendingOrderByColumn(自我::CREATED_AT);返回自我::doSelect($ c);}}
新方法可用相同的方式生成的,如清单8-22所示。
清单8-22——使用自定义模型方法是使用生成的方法
foreach(ArticlePeer::getAllOrderedByDate()作为美元的文章){回声美元的文章;/ /调用魔法__toString()方法}
覆盖现有的方法
如果一些生成的方法基地
类不符合您的需求,您仍然可以覆盖在定制类。只是确保你使用相同的方法签名(即相同数量的参数)。
例如,$ - > getComments条()
方法返回的数组评论
对象,排名不分先后。如果你想要结果下令创建日期,最新评论第一,然后覆盖getComments ()
方法,如清单8-23所示。请注意,原件getComments ()
方法(中lib /模型/ om / BaseArticle.php
)预计值和标准连接值作为参数,所以你的函数必须做同样的事情。
清单8-23 -覆盖现有的模型方法,lib /模型/ Article.php
公共函数getComments(美元标准=零,反对美元=零){如果(is_null(美元标准)){美元标准=新标准();}其他的{/ /对象是通过引用传递在PHP5,所以为了避免修改原始,你必须复制它美元标准=克隆美元标准;}美元标准- >addDescendingOrderByColumn(CommentPeer::CREATED_AT);返回父::getComments(美元标准,反对美元);}
自定义方法最终调用母公司的一个基类,这是好的做法。然而,您可以完全绕过它并返回结果。
使用模型的行为
一些模型的修改是通用的,可以被重用。例如,方法使模型对象排序和一个乐观锁来防止冲突并发对象保存是通用的扩展,可以添加到许多类。
ob娱乐下载Symfony包这些扩展行为。提供额外的行为是外部类方法模型类。模型类已经包含挂钩,symfony知道如何扩展它们。ob娱乐下载
使行为在你的模型类,您必须修改一个设置配置/ propel.ini
文件:
propel.builder。一个ddBehaviors = true // Default value is false
没有默认行为绑定在symfony中,但他们可以通过安装插件。ob娱乐下载一行为一次安装插件,您可以指定一个类的行为一行。例如,如果你安装sfPropelParanoidBehaviorPlugin
在您的应用程序中,您可以扩展一个文章
类与这种行为通过添加以下结束的时候Article.class.php
:
sfPropelBehavior::添加(“文章”,数组(“偏执”= >数组(“列”= >“deleted_at”)));
后重建模型,删除文章
肉眼不可见的对象仍将在数据库中查询使用ORM,除非你暂时禁用行为sfPropelParanoidBehavior:禁用()
。
或者,您也可以直接在声明的行为schema.yml
下,通过列出他们_behaviors
(见下面的清单8-34)的关键。
检查上的symfony的插件列表ob娱乐下载存储库寻找行为。每个都有自己的文档和安装指南。欧宝官网下载app
扩展模式的语法
一个schema.yml
文件可以是简单的,如清单8 - 3所示。但是关系模型往往是复杂的。这就是为什么模式有一个广泛的语法能够处理几乎每一个案例。
属性
连接和表可以有特定的属性,如清单- 24所示。设置下一个_attributes
关键。
清单日到24日-属性和表的连接
推动:_attributes: {noXsd:假的,defaultIdMethod:没有,包:lib.model} blog_article: _attributes: {phpName:文章}
你可能希望你的模式验证之前的代码生成。要做到这一点,停用noXSD
连接属性。也支持的连接defaultIdMethod
属性。如果没有提供,那么将使用数据库的本机方法生成id——例如,自动增量
MySQL或序列
PostgreSQL。其他可能的值没有一个
。
的包
属性是像一个名称空间;它决定了存储生成的类路径。它默认为lib /模型/
,但是你可以改变它在子包来组织您的模型。例如,如果你不想把核心业务类和类定义一个数据库存储数据引擎在同一目录中,然后定义两个模式lib.model.business
和lib.model.stats
包。
你已经看到了phpName
表属性,用于设置生成的类的名称映射表。
表包含本地化内容(即,几个版本的内容,在相关的表中,国际化)也需要两个额外的属性(有关详细信息,请参阅第13章),见清单8-25。
清单为i18n 8-25——属性表
推动:blog_article: _attributes: {isI18N:真的,i18nTable: db_group_i18n}
侧边栏
处理多个模式
每个应用程序可以有多个模式。ob娱乐下载Symfony将考虑每个文件结束schema.yml
或schema.xml
在配置/
文件夹中。如果您的应用程序有很多表,或者有些表不共享相同的连接,你会发现这种方法非常有用。
考虑这两个模式:
/ /配置/业务模式。yml推动:blog_article: _attributes: {phpName:文章}id:标题:varchar (50) / / config / stats-schema。yml推动:stats_hit: _attributes: {phpName:打击}id:资源:varchar (100) created_at:
这两个模式共享相同的连接(推动
),文章
和打击
类将在同样的生成lib /模型/
目录中。一切都发生如果你只写了一个模式。
你也可以有不同的模式使用不同的连接(例如,推动
和propel_bis
中定义databases.yml
在子目录)并组织生成的类:
/ /配置/业务模式。yml推动:blog_article: _attributes: {phpName:文章中,包:lib.model。商业}id:标题:varchar (50) / / config / stats-schema。yml propel_bis: stats_hit: _attributes: {phpName:冲击,包:lib.model。stat} id:资源:varchar (100) created_at:
许多应用程序使用多个模式。特别是一些插件有自己的模式和方案,以避免干扰自己的类(有关详细信息,请参阅第17章)。
列的细节
基本语法给你两个选择:让symfony演绎列特征从它的名字(给一个空值)或定义的类型与一ob娱乐下载个关键字类型。清单8-26演示了这些选择。
清单8-26——基本的列属性
推动:blog_article: id: ~ #让symfony标题ob娱乐下载:varchar(50) #指定自己的类型
但是你可以定义更多的列。如果你这样做,你将需要定义列设置一个关联数组,见清单8-27。
清单8-27 -复杂的列属性
推动:blog_article: id:{类型:整数,要求:真的,primaryKey:真的,自动增量:真正}名称:{类型:varchar(50),默认值:foobar,指数:真正}group_id:{类型:整数,foreignTable: db_group foreignReference: id、onDelete:级联}
列参数如下:
类型
:列类型。的选择是布尔
,非常小的整数
,短整型
,整数
,长整型数字
,双
,浮动
,真正的
,小数
,字符
,varchar(大小)
,用longvarchar
,日期
,时间
,时间戳
,bu_date
,bu_timestamp
,团
,clob
。要求
:布尔。将其设置为真正的
如果你想需要的列。大小
:的大小或长度字段类型,支持它规模
:小数点后的数字为decimal数据类型(大小也必须指定)默认的
:默认值。primaryKey
:布尔。将其设置为真正的
主键。自动增量
:布尔。将其设置为真正的
列的类型整数
这需要一个自动递增的值。序列
:序列名称使用序列数据库自动增量
列(例如,PostgreSQL和Oracle)。指数
:布尔。将其设置为真正的
如果你想要一个简单的指数或独特的
如果你想要创建唯一索引的列。foreignTable
:表名,用于创建另一个表的外键。foreignReference
:相关专栏的名称如果一个外键是通过定义的foreignTable
。onDelete
:决定了行动时触发一个相关的表中记录被删除。当设置为setnull
设置外键列零
。当设置为级联
记录被删除。如果数据库引擎不支持设置行为,ORM模拟它。这是有关只列轴承foreignTable
和一个foreignReference
。isCulture
:布尔。将其设置为真正的
文化本地化内容表中的列(参见第13章)。
外键
作为替代foreignTable
和foreignReference
列属性,您可以添加外键_foreignKeys:
关键在一个表中。清单8-28中的模式将创建一个外键上user_id
匹配的列,id
列blog_user
表。
清单8-28 -外键替代语法
推动:blog_article: id: ~标题:varchar (50) user_id:{类型:整数}_foreignKeys: - foreignTable: blog_user onDelete:级联引用:{当地:user_id,外国:id}
另一种语法是有用的多重参考外键和外键名称,如清单8-29所示。
清单8-29 -外键替代语法应用于多个外键引用
_foreignKeys: my_foreign_key: foreignTable: db_user onDelete:级联引用:{当地:user_id,外国:id} -{当地:post_id,外国:id}
索引
作为替代指数
在列属性,您可以添加索引_indexes:
关键在一个表中。如果你想定义独特的索引,您必须使用的_uniques:
头。列需要大小,因为它们是文本列,索引指定的大小一样的长度列使用括号。清单8-30显示的替代语法索引。
清单8-30 -索引和独特的索引替代语法
推动:blog_article: id: ~标题:varchar (50) created_at: _indexes: my_index:[标题(10)、user_id] _uniques: my_other_index: [created_at]
替代语法只适用于索引建立在多个列。
空的列
当会议一列没有值,symfony会做一些自己的魔法和添加一个值。ob娱乐下载参见清单8-31的细节添加到空的列。
清单8-31 -列细节推断的列名称
/ /空名为id被认为是主键列id:{类型:整数,要求:真的,primaryKey:真的,自动增量:真正}/ /空叫XXX_id被认为是外键列foobar_id:{类型:整数,foreignTable: db_foobar foreignReference: id} / /空的列名叫created_at,更新,created_on和updated_on / /被认为是日期和自动取时间戳类型created_at:{类型:时间戳}updated_at:{类型:时间戳}
外键,symfony会寻找一个拥有相ob娱乐下载同的表phpName
列名的开始,如果找到一个,就把这表名称foreignTable
。
I18n表
ob娱乐下载Symfony支持相关表中内容国际化。这意味着当你有内容国际化,它存储在两个不同的表中:一个不变的列和另一个国际化的列。
在一个schema.yml
文件,所有隐含表当你的名字foobar_i18n
。例如,清单所示的模式8-32与列和表属性将自动完成国际化内容机制工作。在内部,symfony会ob娱乐下载理解它,就好像它是类似于清单8-33写的。第十三章将告诉你更多关于i18n。
清单8-32 -隐含i18n机制
推动:db_group: id: ~ created_at: ~ db_group_i18n:名称:varchar (50)
清单8-33 -明确i18n机制
推动:db_group: _attributes: {isI18N:真的,i18nTable: db_group_i18n} id: ~ created_at: ~ db_group_i18n: id:{类型:整数,要求:真的,primaryKey:真的,foreignTable: db_group, foreignReference: id、onDelete:级联}文化:{isCulture:真的,类型:varchar(7),要求:真的,primaryKey:真正}名称:varchar (50)
行为
行为模型修改器提供的插件,添加新功能推动类。第十七章解释了行为。您可以定义行为的模式,通过清单为每个表,连同他们的参数,下_behaviors
关键。通过扩展清单8-34给出一个示例BlogArticle
类的偏执
的行为。
清单8-34 -行为宣言
推动:blog_article:标题:varchar (50) _behaviors:偏执:{专栏:deleted_at}
超越的模式。yml:模式。xml
事实上,schema.yml
格式是symfony的内部。ob娱乐下载所谓的推动——命令时,实际上symfony将这个文件转换为ob娱乐下载generated-schema.xml
文件,该文件类型的文件的预期推动实际对模型执行任务。
的schema.xml
文件包含相同的信息作为其YAML等价的。例如,清单8 - 3转化为XML文件清单8-35所示。
清单8-35——示例schema.xml
,对应于清单8 - 3
< ? xml版本=“1.0”编码=“utf - 8”? ><数据库的名字=“推动”defaultIdMethod=“本地”noXsd=“真正的”包=“lib.model”><表的名字=“blog_article”phpName=“文章”><列的名字=“id”类型=“整数”要求=“真正的”primaryKey=“真正的”自动增量=“真正的”/ ><列的名字=“标题”类型=“varchar”大小=“255”/ ><列的名字=“内容”类型=“用longvarchar”/ ><列的名字=“created_at”类型=“时间戳”/ >< /表><表的名字=“blog_comment”phpName=“评论”><列的名字=“id”类型=“整数”要求=“真正的”primaryKey=“真正的”自动增量=“真正的”/ ><列的名字=“article_id”类型=“整数”/ ><外键foreignTable=“blog_article”><参考当地的=“article_id”外国=“id”/ >< /外键><列的名字=“作者”类型=“varchar”大小=“255”/ ><列的名字=“内容”类型=“用longvarchar”/ ><列的名字=“created_at”类型=“时间戳”/ >< /表>< /数据库>
的描述schema.xml
格式可以在文档和项目推动的“入门”部分欧宝官网下载app网站。
YAML格式旨在保持模式简单的读写,但换来的是,最复杂的模式不能被描述schema.yml
文件。另一方面,XML格式允许完整的模式描述,无论其复杂性,数据库,包括特定于供应商的设置,表继承,等等。
ob娱乐下载Symfony实际上理解模式编写的XML格式。所以如果你的模式是YAML的语法太复杂,如果你有一个现有的XML模式,或如果你已经熟悉推动XML语法,你不必切换到symfony YAML语法。ob娱乐下载把你的schema.xml
在项目的配置/
目录,建立模型,那就这样吧。
侧边栏
推动在symfonyob娱乐下载
所有的细节在本章并不特定于symfony,而是推动。ob娱乐下载推动是首选对象/关系symfony的抽象层,但你可以选择另一种。ob娱乐下载然而,symfonob娱乐下载y更无缝地与推动工作,原因如下:
所有的类和对象数据模型标准
类是半自动的类。一旦你使用它们,symfony将包括正确的文件,和ob娱乐下载你不需要手动添加文件包含语句。在syob娱乐下载mfony中,推动不需要启动也没有初始化。当一个对象使用推动,图书馆提升者本身。一些symob娱乐下载fony助手使用推动对象作为参数来实现高级任务(比如分页或过滤)。推动对象允许快速成型和一代的后端应用程序(第14章提供了更多细节)。模式是更快的写的schema.yml
文件。
,推动独立于数据库的使用,所以是symfony。ob娱乐下载
不要创建模型的两倍
使用一个ORM的权衡是你必须定义数据结构两次:一次数据库,一旦对象模型。幸运的是,symfony提ob娱乐下载供了命令行工具来生成一个基于另一个,这样你就可以避免重复工作。
构建一个基于现有模式的SQL数据库结构
如果你开始通过编写的应用程序schema.yml
文件,symob娱乐下载fony可以生成一个SQL查询,直接从YAML数据模型创建的表。使用查询,去根项目目录和类型:
php syob娱乐下载mfony推动美元:构建sql
一个lib.model.schema.sql
文件将被创建myproject /数据/ sql /
。注意,生成的SQL代码将针对中定义的数据库系统进行了优化phptype
参数的propel.ini
文件。
您可以使用schema.sql
文件直接构建表。例如,在MySQL、类型:
mysqladmin - u root - p创建博客mysql美元- u root - p <数据/ sql / lib.model.schema.sql博客
生成的SQL也有助于重建数据库在另一个环境,或者改变到另一个数据库管理系统。如果连接设置中定义propel.ini
,你甚至可以使用php ob娱乐下载symfony推动:插入sql
自动命令来做到这一点。
提示
命令行中还提供了一个任务来填充数据库与基于文本文件的数据。有关更多信息,请参见第16章的推动:数据加载
任务和YAML夹具文件。
从现有数据库生成YAML数据模型
ob娱乐下载Symfony可以使用推动生成schema.yml
从现有的数据库文件,由于内省(数据库的能力来确定结构的表在他们操作)。这是特别有用,当你做逆向工程,或如果你喜欢工作在数据库对象模型。
为了做到这一点,您需要确保该项目databases.yml
文件指向正确的数据库,包含所有连接设置,然后调用推动:建立模式
命令:
php syob娱乐下载mfony推动美元:建立模式
一个全新的schema.yml
文件由数据库结构中生成配置/
目录中。你可以基于该模式的构建模型。
模式生成命令非常强大,可以将很多database-dependent信息添加到您的模式。作为YAML格式不处理这种类型的供应商信息,您需要生成一个XML模式来利用它。你可以简单地添加一个xml
参数建立模式
任务:
php syob娱乐下载mfony推动美元:建立模式——xml
而不是生成一个schema.yml
文件,这将创建一个schema.xml
文件与推动完全兼容,包含所有供应商的信息。但请注意,生成XML模式往往是相当冗长,难以阅读。
侧边栏
的propel.ini
配置
这个文件包含其他设置用于配置驱动发电机,使生成的模型类兼容symfony。ob娱乐下载大多数设置内部和不感兴趣的用户,除了几个:
/ /基类自动装载在symfony / /设置为true使用inclob娱乐下载ude_once语句而不是/ / propel.builder(小对性能产生负面影响)。添加Includes = false // Generated classes are not commented by default // Set this to true to add comments to Base classes // (Small negative impact on performance) propel.builder.addComments = false // Behaviors are not handled by default // Set this to true to be able to handle them propel.builder.AddBehaviors = false
在你做一个修改propel.ini
设置,别忘了重建模型的更改生效。
总结
ob娱乐下载Symfony使用推动作为ORM和PHP数据对象的数据库抽象层。这意味着你必须首先描述数据库的关系模式在YAML生成对象模型类。然后,在运行时,使用对象和同行类的方法来检索一个记录或一组记录的信息。你可以覆盖和扩展模型很容易通过添加自定义类的方法。连接设置中定义databases.yml
文件,该文件可以支持多个连接。和命令行包含特殊任务,以避免重复的结构定义。
模型层是最复杂的symfony框架。ob娱乐下载这种复杂性的一个原因是,数据操作是一个复杂的问题。网站的相关安全问题是至关重要的,不应该被忽略。另一个原因是,symfony更适合中等企业中大ob娱乐下载规模应用程序上下文。在这样的应用程序中,提供的自动化symfony模型真正代表获得时间,价值投资在学习它的内部。ob娱乐下载
所以不要犹豫地花一些时间测试模型对象和方法充分地理解它们。应用程序的可靠性和可伸缩性将是一个巨大的回报。
这项工作是GFDL许可执照。