数据库和原则

编辑该页面

警告:你浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 3.0,不再维护。

这个页面的更新版本Symf欧宝娱乐app下载地址ony 6.2(当前的稳定版本)。

< /div>

数据库和原则

最常见的和具有挑战性的任务对于任何应用程序包括持久化和阅读信息和从数据库。尽管Symfony框架不整欧宝娱乐app下载地址合处理数据库的任何组件,它提供与第三方库称为紧密集成学说。原则的唯一目标是给你强大的工具使数据库交互简单、灵活。

在这一章,你将学习如何开始利用教义在Symfony项目给你丰富的数据库交互。欧宝娱乐app下载地址

请注意

原则是完全脱离Symfony和使用它是可选的。欧宝娱乐app下载地址这一章都是关于教义ORM,旨在让您将对象映射到关系数据库(如<新兴市场>MySQL,<新兴市场>PostgreSQL或<新兴市场>Microsoft SQL)。如果你喜欢用原始的数据库查询,这是很容易的,并解释了在“如何使用原则DBAL吗”文章。

你也可以保存数据MongoDB使用原则ODM图书馆。有关更多信息,阅读“DoctrineMongoDBBundle _”文档。欧宝体育电话

< /div>

一个简单的例子:一个产品

理解教义是如何工作的最简单的方法就是看它的实际应用。在本节中,您将配置数据库,创建一个产品对象持久化到数据库并获取它。

配置数据库

在你真正开始之前,您需要配置您的数据库连接信息。按照惯例,这些信息通常是在一个配置应用程序/配置/ parameters.yml文件:

1 2 3 4 5 6 7 8
# app / config / parameters.yml参数:database_host:本地主机database_name:test_projectdatabase_user:database_password:密码#……

请注意

通过定义配置parameters.yml只是一个惯例。该文件中定义的参数引用的主要配置文件设置原则时:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8
# app / config / config.yml原则:dbal:司机:pdo_mysql主持人:“% database_host %”dbname:“% database_name %”用户:“% database_user %”密码:“% database_password %”

通过将数据库信息到一个单独的文件中,您可以很容易地保持在每个服务器上文件的不同版本。您还可以方便地存储数据库配置(或任何敏感信息)以外的项目,比如在Apache配置。有关更多信息,请参见服务容器外部参数如何设置

< /div>

现在学说可以连接到数据库,下面的命令可以自动生成一个空test_project数据库:

1
美元php bin /控制台学说:数据库:创建

即使是经验丰富的开发人员常犯的一个错误当开始一个Symfony项目是忘记设置默认数据库字符集和校对,结束了拉丁类型针欧宝娱乐app下载地址对性,它是大多数数据库的默认。他们甚至会记得第一次,但是忘记都是运行在开发过程中比较常见的命令:

1 2
美元php bin /控制台学说:数据库:下降,迫使美元php bin /控制台学说:数据库:创建

设置UTF8违约MySQL一样简单的几行添加到您的配置文件(通常是my.cnf):

1 2 3 4
(mysqld)5.5.3 #版本引入了“utf8mb4”,这是推荐的collation-server= utf8mb4_general_ci#替换utf8_general_cicharacter-set-server= utf8mb4#替换utf8

您还可以更改默认设置为原则,这样生成的SQL使用正确的字符集。

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7
# app / config / config.yml原则:dbal:字符集:utf8mb4default_table_options:字符集:utf8mb4整理:utf8mb4_unicode_ci

我们建议对MySQLuse utf8字符集,因为它不支持4字节unicode字符,和字符串包含将被截断。这是固定的新utf8mb4字符集

< /div>

请注意

如果你想使用SQLite作为您的数据库,您需要设置应该存储在数据库文件的路径:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# app / config / config.yml原则:dbal:司机:pdo_sqlite路径:' % kernel.root_dir % / sqlite.db '字符集:use UTF8

创建一个实体类

假设您要构建一个应用程序,需要显示的产品。没想学说或数据库中,你已经知道你需要一个产品对象来表示这些产品。创建这个类里面实体你的AppBundle目录:

1 2 3 4 5 6 7 8 9
/ / src / AppBundle /实体/ Product.php名称空间AppBundle\实体;产品{私人美元的名字;私人美元价格;私人美元描述;}

类——通常被称为一个“实体”的意思<新兴市场>一个基本类,保存数据——很简单,帮助满足需要的产品在您的应用程序的业务需求。这个类不能被持久化到数据库——这只是一个简单的PHP类。

提示

一旦你学习原则背后的概念,你可以有教义为您创建简单的实体类。这将问你互动问题帮助你建立任何实体:

1
美元php bin /控制台学说:生成:实体

添加映射信息

教义允许您工作与数据库更加有趣的方式不仅仅是获取行标量数据到一个数组中。相反,教义允许您获取整个<新兴市场>对象从数据库中,将整个对象持久化到数据库中。的学说能够做到这一点,你必须<新兴市场>地图具体的PHP类,你的数据库表和列在这些表必须映射到特定属性对应的PHP类。

你会提供这种映射信息的形式“元数据”的规则的集合告诉学说如何产品类及其属性<新兴市场>映射到一个特定的数据库表中。此元数据可以指定在许多不同的格式,包括YAML、XML或直接在产品类通过DocBlock注释:

  • 注释
  • YAML
  • XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31 32 33
/ / src / AppBundle /实体/ Product.php名称空间AppBundle\实体;使用学说\ORM\映射作为ORM;/ * * *@ORM* \实体@ORM\表(name = "产品")* /产品{/ * * *@ORM\列(type =“整数”)*@ORM\ Id *@ORM\ GeneratedValue(策略=“汽车”)* /私人美元id;/ * * *@ORM\列(类型=“字符串”,长度= 100)* /私人美元的名字;/ * * *@ORM\列(type =“小数”,规模= 2)* /私人美元价格;/ * * *@ORM\列(type = " text ") * /私人美元描述;}

请注意

一捆只能接受一个元数据定义格式。例如,它是不可能的混合YAML的元数据定义与注释PHP实体类定义。

< /div>

提示

表名是可选的,如果省略,将自动确定基于实体类的名称。

< /div>

教义允许您选择各种不同的字段类型,每个都有自己的选择。有关可用的字段类型的信息,请参阅数据库和原则部分。

另请参阅

你也可以看看学说基本的映射文档欧宝体育电话对所有细节映射信息。如果你使用注释,需要预先考虑所有注释ORM \(如。ORM \列(…)所示),这不是教条的文档。欧宝体育电话你还需要包括使用原则\ ORM \ ORM映射;声明,<新兴市场>进口ORM注释前缀。

< /div>

谨慎

小心如果你的实体类的名称(或属性)也保留SQL关键字集团用户。例如,如果您的实体的类名集团默认情况下,对应的表名集团。这将导致一个SQL错误在某些数据库引擎。看到学说的保留SQL关键字的文档欧宝体育电话有关如何正确逃脱这些名字。另外,如果你自由选择数据库模式,简单地映射到不同的表名或列名。看到学说的创建数据库的类属性映射欧宝体育电话文档。

< /div>

请注意

当使用另一个库或程序(例如Doxygen),使用注释,你应该把@IgnoreAnnotation注释的类来表示注释Symfony应该忽略。欧宝娱乐app下载地址

例如,为了防止@fn注释从抛出异常,添加以下:

1 2 3 4 5
/ * * *@IgnoreAnnotation(fn) * /产品/ /……

生成getter和setter方法

尽管学说现在知道如何坚持产品对象到数据库,类本身还没有真正有用的。自产品只是一个普通的PHP类私人属性,您需要创建公共(例如getter和setter方法。getName (),setName(名称))为了访问其属性在应用程序的其余部分的代码。幸运的是,下面的命令可以自动生成这些样板的方法:

1
美元php bin /控制台学说:生成:实体AppBundle /实体产品

这个命令确保所有的生成getter和setter方法产品类。这是一个安全的命令,您可以运行它一遍又一遍:它只生成getter和setter方法,不存在(即它不会取代你现有的方法)。

谨慎

记住,教义的实体发生器产生简单的getter / setter。您应该检查生成的方法和添加任何逻辑,如果有必要,以满足应用程序的需要。

< /div>

原则:生成实体命令,您可以:

  • 在实体类生成getter和setter方法;
  • 生成库类代表实体配置了@ORM \实体(repositoryClass = "…")注释;
  • 生成适当的构造函数为1:n和n: m关系。

原则:生成实体命令保存一个备份原来的Product.php命名Product.php ~。在某些情况下,这个文件的存在会导致一个“不能重新定义类”错误。它可以安全地删除。您还可以使用——没有备份的防止生成这些备份文件的选项。

注意,你不<新兴市场>需要使用此命令。您还可以手工编写必要的getter和setter。这个选项的存在只是为了节省你的时间,因为创建这些方法在开发过程中往往是一个常见的任务。

< /div>

你也可以生成所有已知的实体(即任何教条的PHP类映射信息)的包或整个命名空间:

1 2 3 4 5
# AppBundle生成所有实体php bin /控制台学说:美元AppBundle生成:实体#生成包的所有实体Acme名称空间美元php bin /控制台学说:生成:Acme的实体

创建数据库表/模式

你现在有一个可用的产品类映射信息,以便教义确切地知道如何坚持。当然,你还没有相应的产品表在数据库中。幸运的是,教义可以自动创建所需的所有数据库表为每一个已知的实体在您的应用程序。要做到这一点,运行:

1
php bin /控制台学说:美元模式:更新——力量

提示

实际上,这个命令是非常强大的。比较你的数据库<新兴市场>应该看起来像(基于实体的映射信息)与它<新兴市场>实际上看起来,并执行所需的SQL语句<新兴市场>更新数据库模式在它应该在的地方。换句话说,如果你添加一个新的属性映射元数据产品和运行这个任务时,它将执行“ALTER TABLE语句需要添加新列的现有产品表。

一个更好的方法是通过利用这个功能迁移,它允许您生成这些SQL语句和存储他们移民类,可以生产服务器上运行系统,以更新和安全可靠地跟踪更改数据库模式。

你是否利用迁移,原则:模式:更新命令应该只在开发期间使用。它不应该在生产环境中使用。

< /div>

数据库现在有一个全功能产品表和列匹配你指定的元数据。

< /div>

持久化对象到数据库

现在您已经绘制了产品实体对应的产品表,就可以持续下去产品对象到数据库。在一个控制器,这是非常容易的。添加以下方法DefaultController包:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日24
/ / src / AppBundle /控制器/ DefaultController.php/ /……使用AppBundle\实体\产品;使用欧宝娱乐app下载地址\组件\HttpFoundation\响应;/ /……公共函数createAction(){美元产品=产品();美元产品- >setName (“键盘”);美元产品- >setPrice (19.99);美元产品- >setDescription (的人体工学和时尚!);美元新兴市场=美元- >getDoctrine ()- >getManager ();/ /告诉学说你想(最终)保存产品(没有查询)美元新兴市场- >persist (美元产品);/ /实际执行查询(即插入查询)美元新兴市场- >冲洗();返回响应(“保存新产品id”美元产品- >getId ());}

请注意

如果你按照这个例子中,您需要创建一个指向这个动作路线工作。

< /div>

提示

本文展示了处理原则从控制器使用getDoctrine ()控制器的方法。这是一个快捷的方法学说服务。你可以在任何地方使用原则通过注入服务的其他服务。看到服务容器在创建自己的服务。

< /div>

更详细地看一看前面的示例:

  • 第10 - 13行在本节中,您实例化和工作美元的产品像其他普通PHP对象。
  • 第15行这条线获取学说<新兴市场>实体管理器对象,负责持久化对象的过程中,和抓取对象从数据库中。
  • 第17行坚持(产品)打电话告诉学说“管理”美元的产品对象。这并导致一个查询的数据库。
  • 第18行冲洗()方法被调用,原则通过的所有对象的管理,看看他们是否需要被持久化到数据库中。在这个例子中,美元的产品对象的数据在数据库中不存在,所以实体管理器执行一个插入查询,创建一个新行产品表。

请注意

事实上,由于教义意识到你所有的管理实体,当你调用冲洗()方法,它计算一个整体变更集和执行查询以正确的顺序。它利用缓存准备语句稍微提高性能。例如,如果您坚持共有100产品然后随后调用对象冲洗(),100年学说将执行插入使用一个事先准备好的声明中对象的查询。

< /div>

是否创建或更新对象,工作流总是相同的。在下一节中,您将看到如何学说是一个足够聪明来自动问题更新数据库中查询如果实体已经存在。

提示

学说提供了一个库,允许您以编程方式测试数据加载到您的项目(即。“固定数据”)。信息,请参阅“DoctrineFixturesBundle _”文档。欧宝体育电话

< /div>

从数据库中获取对象

获取一个对象的数据库更容易。例如,假设您已经配置了一个显示一个特定的路线产品基于其id值:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
公共函数showAction(美元productId){美元产品=美元- >getDoctrine ()- >getRepository (“AppBundle:产品”)- >找到(美元productId);如果(!美元产品){美元- >createNotFoundException (“没有发现产品id”美元productId);}/ /……做点什么,比如通过美元产品对象到一个模板}

提示

可以达到相当于这个没有编写任何代码通过使用@ParamConverter快捷方式。看到FrameworkExtraBundle文欧宝体育电话档为更多的细节。

< /div>

查询一个特定类型的对象时,你总是用所谓的“仓库”。你可以认为一个存储库是一个PHP类唯一的工作就是帮助你获取某个类的实体。您可以访问存储库对象为一个实体类通过:

1 2
美元存储库=美元- >getDoctrine ()- >getRepository (“AppBundle:产品”);

请注意

AppBundle:产品字符串是一个快捷方式可以使用任何学说,而不是实体的完整类名(即。AppBundle \ \实体产品)。只要你的实体下的生活实体你的包名称空间,这将工作。

< /div>

一旦你有了一个存储库对象,您可以访问各种各样的有用的方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
美元存储库=美元- >getDoctrine ()- >getRepository (“AppBundle:产品”);/ /查询单个产品的、由其主键(通常是“id”)美元产品=美元存储库- >找到(美元productId);/ /动态方法名来找到一个单一产品基于列值美元产品=美元存储库- >findOneById (美元productId);美元产品=美元存储库- >findOneByName (“键盘”);/ /动态方法名称查找一组产品基于列值美元产品=美元存储库- >findByPrice (19.99);/ /找到* *所有产品美元产品=美元存储库- >findAll ();

请注意

当然,你也可以问题复杂的查询,你会了解更多的数据库和原则部分。

< /div>

你也可以利用有用的findByfindOneBy方法方便地获取对象根据多个条件:

1 2 3 4 5 6 7 8 9 10 11 12
美元存储库=美元- >getDoctrine ()- >getRepository (“AppBundle:产品”);/ /查询单个产品匹配给定的名称和价格美元产品=美元存储库- >findOneBy (数组(“名字”= >“键盘”,“价格”= >19.99));/ /查询多个产品匹配给定的名称、订购价格美元产品=美元存储库- >findBy (数组(“名字”= >“键盘”),数组(“价格”= >“ASC”));

提示

当你渲染任何页面中,您可以看到有多少查询在网络调试工具栏的右下角。

如果你单击图标,分析器会打开,显示你的查询。

图标会变黄,如果有50多个查询页面。这可能表明,东西是不正确的。

< /div>

更新一个对象

一旦你获取一个对象从教义,更新很容易。假设您有一个路线,产品id映射到一个更新控制器中的动作:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
公共函数updateAction(美元productId){美元新兴市场=美元- >getDoctrine ()- >getManager ();美元产品=美元新兴市场- >getRepository (“AppBundle:产品”)- >找到(美元productId);如果(!美元产品){美元- >createNotFoundException (“没有发现产品id”美元productId);}美元产品- >setName (“新产品的名字!”);美元新兴市场- >冲洗();返回美元- >redirectToRoute (“主页”);}

更新对象包括三个步骤:

  1. 获取对象从教义;
  2. 修改对象;
  3. 调用冲洗()在实体管理器

注意,调用(em - >坚持美元产品)是没有必要的。回想一下,这个方法简单告诉原则管理或“观察”美元的产品对象。在这种情况下,因为你把美元的产品对象从教义,它已经成功。

< /div>

删除一个对象

删除一个对象非常相似,但需要调用remove ()实体管理器的方法:

1 2
美元新兴市场- >remove (美元产品);美元新兴市场- >冲洗();

如您所料,remove ()方法通知学说,你想从数据库中删除给定对象。实际的删除查询,但是,并不是实际执行,直到冲洗()方法被调用。

查询对象

您已经看到如何存储库对象允许您运行基本查询没有任何工作:

1 2 3 4
美元存储库=美元- >getDoctrine ()- >getRepository (“AppBundle:产品”);美元产品=美元存储库- >找到(美元productId);美元产品=美元存储库- >findOneByName (“键盘”);

当然,教义也允许您编写更复杂的查询使用查询语言(DQL)原则。DQL类似于SQL除外,你应该想象你查询一个或多个对象的一个实体类(如。产品)而不是桌子上(如查询行。产品)。

在教义查询时,你有两种选择:写纯DQL查询或使用原则的查询生成器。

查询与DQL对象

想象一下你想查询的产品成本比19.99,从最小订购最昂贵的。您可以使用DQL,教义的原生sql语言,构造一个查询的方法对于这个场景:

1 2 3 4 5 6 7 8 9
美元新兴市场=美元- >getDoctrine ()- >getManager ();美元查询=美元新兴市场- >createQuery (“从AppBundle选择p:产品p, p。价格>:价格按p。ASC的价格)- >setParameter (“价格”,19.99);美元产品=美元查询- >getResult ();

如果您熟悉SQL,那么DQL应该感到很自然。最大的区别是,你需要考虑选择PHP对象,而不是数据库中的行。出于这个原因,你选择<新兴市场>从AppBundle:产品实体(一个可选的快捷方式AppBundle \ \实体产品这类),然后别名p

提示

注意的setParameter ()方法。在处理原则时,它总是一个好主意任何外部值设置为“占位符”(:价格在上面的示例中),因为它可以防止SQL注入攻击。

< /div>

getResult ()方法返回一个数组的结果。只有一个结果,您可以使用getOneOrNullResult ():

1
美元产品=美元查询- >setMaxResults (1)- >getOneOrNullResult ();

DQL语法是非常强大的,允许您轻松地加入实体之间的话题关系稍后将介绍)、组等。有关更多信息,看到官方的吗教义的查询语言欧宝体育电话文档。

< /div>

查询对象使用原则的查询生成器

而不是写一个DQL字符串,您可以使用一个称为有用的对象QueryBuilder为你构建字符串。这是有用,当实际的查询取决于动态条件下,随着代码很快就变得难以阅读与DQL你开始连接字符串:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
美元存储库=美元- >getDoctrine ()- >getRepository (“AppBundle:产品”);/ /从AppBundle createQueryBuilder自动选择:产品/ /,别名“p”美元查询=美元存储库- >createQueryBuilder (“p”)- >(在哪里“p。price > :price'< /span>)- >setParameter (“价格”,“19.99”)- >orderBy (“p.price”,“ASC”)- >getQuery ();美元产品=美元查询- >getResult ();/ /得到只有一个结果:/ /产品=美元查询- > setMaxResults (1) - > getOneOrNullResult ();

QueryBuilder对象包含每个方法需要建立你的查询。通过调用getQuery ()方法,查询构建器返回正常查询对象,该对象可以用来获取查询的结果。

教义的查询构建器的更多信息,参考原则查询构建器欧宝体育电话文档。

< /div>

组织自定义查询到库类

前面所有的查询是直接写在你的控制器。但对于组织原则提供了特殊的库类允许您保持所有的查询逻辑放在一个中心位置。

看到如何创建自定义库类的信息。

< /div>

配置

教义是高度可配置的,虽然你可能不会需要担心的大多数选项。找到更多关于配置原则,看到的理论部分配置引用

教义字段类型引用

教义有很多可用的字段类型。这些PHP数据类型映射到一个特定的列类型无论你使用数据库。对于每个字段类型,进一步可以配置,设置长度,可以为空的行为,的名字和其他选项。看到所有可用的列表类型和更多信息,参见学说映射类型的文档欧宝体育电话

< /div>

关系和联系

学说提供了你需要的所有功能管理器数据库(也称为协会)的关系。信息,请参阅如何使用主义协会/关系

< /div>
这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。