数据库和理论
编辑本页警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 2.4,现已不再维护。
读本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。
数据库和理论
对于任何应用程序来说,最常见和最具挑战性的任务之一是持久化和从数据库中读取信息。幸运的是,Symfony集ob娱乐下载成了学说,这个库的唯一目标就是为您提供强大的工具来简化此过程。在本章中,您将学习Doctrine背后的基本哲学,并了解使用数据库是多么容易。
请注意
Doctrine完全与Symfony分离,使用它是可选的。ob娱乐下载本章是关于ORM原则的,它的目的是让您将对象映射到关系数据库(例如MySQL,PostgreSQL或Microsoft SQL).如果您更喜欢使用原始数据库查询,这很容易,并在“如何使用Doctrine的DBAL层“食谱条目。
还可以将数据持久化到MongoDB使用Doctrine ODM库。要了解更多信息,请阅读“DoctrineMongoDBBundle”文档。欧宝官网下载app
一个简单的例子:一个产品
要理解教条主义是如何运作的,最简单的方法就是看它的实际行动。在本节中,您将配置数据库,创建一个产品
对象,将其持久化到数据库并将其取出。
配置数据库
在真正开始之前,您需要配置数据库连接信息。根据约定,此信息通常配置在应用程序/配置/ parameters.yml
文件:
1 2 3 4 5 6 7 8 9
# app / config / parameters.yml参数:database_driver:pdo_mysqldatabase_host:本地主机database_name:test_projectdatabase_user:根database_password:密码#……
请注意
通过定义配置parameters.yml
只是一种惯例。该文件中定义的参数在设置Doctrine时由主配置文件引用:
- YAML
- XML
- PHP
1 2 3 4 5 6 7 8
# app / config / config.yml原则:dbal:司机:“% database_driver %”主持人:“% database_host %”dbname:“% database_name %”用户:“% database_user %”密码:“% database_password %”
通过将数据库信息分离到一个单独的文件中,您可以轻松地在每个服务器上保存文件的不同版本。您还可以轻松地将数据库配置(或任何敏感信息)存储在项目之外,例如在Apache配置中。有关更多信息,请参见如何设置服务容器的外部参数.
现在Doctrine已经知道了你的数据库,你可以让它为你创建数据库:
1
$ PHP应用程序/控制台原则:数据库:创建
请注意
如果你想使用SQLite作为你的数据库,你需要设置你的数据库文件应该存储的路径:
- YAML
- XML
- PHP
1 2 3 4 5 6
# app / config / config.yml原则:dbal:司机:pdo_sqlite路径:“% kernel.root_dir % / sqlite.db”字符集:use UTF8
创建实体类
假设您正在构建一个需要显示产品的应用程序。甚至不考虑Doctrine或数据库,您已经知道您需要一个产品
对象来表示这些产品。类中创建这个类实体
贵公司目录AcmeStoreBundle
:
1 2 3 4 5 6 7 8 9 10 11
/ / src / Acme / / Product.php StoreBundle /实体名称空间Acme\StoreBundle\实体;类产品{受保护的$的名字;受保护的$价格;受保护的$描述;}
类——常称为“实体”,意思是保存数据的基本类-简单且有助于满足应用程序中所需产品的业务需求。这个类还不能持久化到数据库中——它只是一个简单的PHP类。
提示
一旦你学习了Doctrine背后的概念,你就可以让Doctrine为你创建简单的实体类。它会问你一些互动问题来帮助你构建任何实体:
1
$ PHP应用程序/控制台原则:生成:实体
添加映射信息
Doctrine允许您以一种更有趣的方式使用数据库,而不仅仅是将基于列的表中的行获取到数组中。相反,Doctrine允许您完整地持久化对象并从数据库中获取整个对象。这是通过将一个PHP类映射到一个数据库表,并将该PHP类的属性映射到表中的列来实现的:
为了让Doctrine能够做到这一点,您只需要创建“元数据”,或者配置,告诉Doctrine确切地如何产品
类及其属性应该是映射到数据库。该元数据可以以多种不同的格式指定,包括YAML、XML或直接在产品
通过注释创建类:
- 注释
- YAML
- XML
12 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 / Acme / / Product.php StoreBundle /实体名称空间Acme\StoreBundle\实体;使用学说\ORM\映射作为ORM;/ * * *@ORM* \实体@ORM\表(name = "产品")* /类产品{/ * * *@ORM\列(type =“整数”)*@ORM\ Id *@ORM\ GeneratedValue(策略=“汽车”)* /受保护的$id;/ * * *@ORM\Column(type="string", length=100) */受保护的$的名字;/ * * *@ORM\Column(type="decimal", scale=2) */受保护的$价格;/ * * *@ORM\列(type = " text ") * /受保护的$描述;}
请注意
一个bundle只能接受一种元数据定义格式。例如,不可能将YAML元数据定义与带注释的PHP实体类定义混合使用。
提示
表名是可选的,如果省略,将根据实体类的名称自动确定。
Doctrine允许您从各种不同的字段类型中进行选择,每种类型都有自己的选项。有关可用字段类型的信息,请参见数据库和理论部分。
另请参阅
你也可以看看Doctrine的基础制图文档欧宝官网下载app查看映射信息的所有详细信息。如果使用注释,则需要在所有注释前加上ORM \
(如。ORM \列(. .)
),并没有在Doctrine的文档中显示。欧宝官网下载app您还需要包括使用Doctrine\ORM\Mapping作为ORM;
声明,进口的ORM
注释前缀。
谨慎
注意不要将类名和属性映射到受保护的SQL关键字(例如集团
或用户
).例如,如果您的实体类名是集团
,那么,默认情况下,您的表名将为集团
,这将在某些引擎中导致SQL错误。看到学说的保留SQL关键字文档欧宝官网下载app如何正确地转义这些名称。或者,如果您可以自由选择数据库模式,只需映射到不同的表名或列名。看到学说的持久化类而且属性映射欧宝官网下载app文档。
请注意
当使用另一个库或程序(例如。Doxygen)使用注释,您应该放置@IgnoreAnnotation
注释,以指示Symfony应该忽略哪些注释。ob娱乐下载
例如,防止@fn
注释抛出异常时,添加以下内容:
1 2 3 4 5
/ * * *@IgnoreAnnotation(fn) * /类产品/ /……
生成getter和setter
尽管教条主义现在知道如何坚持产品
对象,类本身还没有真正有用。自产品
是一个普通的PHP类,你需要创建getter和setter方法(例如。getName ()
,setName ()
)来访问它的属性(因为属性是受保护的
).幸运的是,Doctrine可以通过运行:
1
$ php应用程序/控制台原则:生成:实体Acme/StoreBundle/实体/产品
属性的所有getter和setter都生成了产品
类。这是一个安全的命令-你可以一遍又一遍地运行它:它只生成不存在的getter和setter(即它不会取代你现有的方法)。
谨慎
请记住,Doctrine的实体生成器生成简单的getter /setter。您应该检查生成的实体,并根据自己的需要调整getter/setter逻辑。
你也可以生成一个bundle或整个命名空间的所有已知实体(即带有Doctrine映射信息的任何PHP类):
1 2
$ php应用程序/控制台原则:generate:entities AcmeStoreBundle $ php应用程序/控制台原则
请注意
教条并不关心你的财产是否是受保护的
或私人
,或者属性是否有getter或setter函数。这里生成getter和setter只是因为需要它们与PHP对象进行交互。
创建数据库表/模式
你现在有一个可用的产品
类使用映射信息,以便Doctrine确切地知道如何持久化它。当然,你还没有相应的产品
表。幸运的是,Doctrine可以自动为应用程序中的每个已知实体创建所需的所有数据库表。要做到这一点,运行:
1
$ PHP应用程序/控制台原则:schema:update——force
提示
实际上,这个命令非常强大。它比较你的数据库应该看起来像(基于实体的映射信息)实际上查看,并生成所需的SQL语句更新将数据库移到它应该在的位置。换句话说,如果将元数据映射到的新属性添加到产品
并再次运行此任务,它将生成将新列添加到现有列所需的“alter table”语句产品
表格
利用此功能的更好方法是通过DoctrineMigrationsBundle,它允许您生成这些SQL语句并将它们存储在可以在生产服务器上系统地运行的迁移类中,以便安全可靠地跟踪和迁移数据库模式。
您的数据库现在具有完整的功能产品
表,其中的列与所指定的元数据匹配。
持久化对象到数据库
现在你有了一个映射产品
实体和对应的产品
表,您就可以将数据持久化到数据库中。从控制器内部来看,这非常简单。属性中添加以下方法DefaultController
关于捆绑:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/ / src / Acme / StoreBundle /控制器/ DefaultController.php/ /……使用Acme\StoreBundle\实体\产品;使用ob娱乐下载\组件\HttpFoundation\响应;公共函数createAction(){$产品=新产品();$产品->setName ('A Foo Bar');$产品->setPrice (“19.99”);$产品->setDescription (“Lorem ipsum dolor”);$新兴市场=$这->getDoctrine ()->getManager ();$新兴市场->persist ($产品);$新兴市场->冲洗();返回新响应(“创建的产品id”.$产品->getId ());}
请注意
如果您遵循这个示例,您将需要创建一个指向此操作的路由,以查看它是否工作。
提示
方法在控制器中使用DoctrinegetDoctrine ()控制器的方法。此方法是获取学说
服务。您可以在其他任何地方通过在服务中注入该服务来使用Doctrine。看到服务容器有关创建自己的服务的更多信息。
更详细地看看前面的例子:
- 行9 - 12方法的实例化和使用
美元的产品
对象,就像任何其他普通PHP对象一样。 - 第14行这一行是Doctrine的实体管理器对象,该对象负责处理持久化和从数据库获取对象的过程。
- 第15行的
persist ()
方法告诉Doctrine“管理”美元的产品
对象。这实际上不会导致对数据库的查询。 - 线16当
冲洗()
方法时,Doctrine会查看它所管理的所有对象,以确定它们是否需要持久化到数据库中。在本例中,美元的产品
对象尚未持久化,因此实体管理器将执行插入
查询中创建一行产品
表格
请注意
实际上,由于Doctrine知道您的所有托管实体,当您调用冲洗()
方法,它计算总体更改集并执行最有效的查询/查询。例如,如果您总共持久化了100产品
对象,然后调用冲洗()
教条会造就一个单预处理语句,并为每个插入重用它。这个模式叫做工作单元使用它是因为它快速有效。
当创建或更新对象时,工作流总是相同的。在下一节中,您将看到Doctrine是如何智能地自动发出一个更新
查询该记录是否已经存在于数据库中。
提示
Doctrine提供了一个库,允许您以编程的方式将测试数据加载到您的项目中(例如。“固定数据”)。有关信息,请参见DoctrineFixturesBundle。
从数据库中获取对象
从数据库中取回对象更加简单。例如,假设您配置了一条路由来显示特定的路由产品
基于它id
值:
12 3 4 5 6 7 8 9 10 11 12 13 14
公共函数showAction($id){$产品=$这->getDoctrine ()->getRepository (“AcmeStoreBundle:产品”)->找到($id);如果(!$产品) {扔$这->createNotFoundException (“没有为id找到产品”.$id);}/ /……做一些事情,比如将$product对象传递到模板中}
提示
方法可以实现与此等效的功能,而无需编写任何代码@ParamConverter
快捷方式。有关更多细节,请参阅frameworkextrabunda欧宝官网下载appnce文档。
当你查询一个特定类型的对象时,你总是使用所谓的“存储库”。您可以将存储库视为一个PHP类,它的唯一任务是帮助您获取某个类的实体。你可以通过以下方式访问实体类的存储库对象:
1 2
$存储库=$这->getDoctrine ()->getRepository (“AcmeStoreBundle:产品”);
请注意
的AcmeStoreBundle:产品
string是你可以在Doctrine中的任何地方使用的快捷方式,而不是实体的完整类名(即。Acme \ \ StoreBundle \实体产品
).只要你的实体还在实体
命名空间,这将工作。
一旦你有了你的存储库,你就可以访问各种有用的方法:
12 3 4 5 6 7 8 9 10 11 12
//通过主键查询(通常是"id")$产品=$存储库->找到($id);//基于列值查找的动态方法名$产品=$存储库->findOneById ($id);$产品=$存储库->findOneByName (“foo”);//查找所有产品$产品=$存储库->findAll ();//根据任意列值查找一组产品$产品=$存储库->findByPrice (19.99);
请注意
当然,您还可以发出复杂的查询,您将在数据库和理论部分。
你也可以利用有用的findBy
而且findOneBy
基于多个条件轻松获取对象的方法:
1 2 3 4 5 6 7 8 9 10
//查询一个名称和价格匹配的产品$产品=$存储库->findOneBy (数组(“名字”= >“foo”,“价格”= >19.99));//查询所有与名称匹配的产品,按价格排序$产品=$存储库->findBy (数组(“名字”= >“foo”),数组(“价格”= >“ASC”));
提示
当您呈现任何页面时,您可以在web调试工具栏的右下角看到进行了多少查询。
如果单击图标,分析器将打开,显示所执行的确切查询。
更新对象
一旦你从Doctrine中获取了一个对象,更新它就很容易了。假设你有一个将产品id映射到控制器中的更新操作的路由:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
公共函数updateAction($id){$新兴市场=$这->getDoctrine ()->getManager ();$产品=$新兴市场->getRepository (“AcmeStoreBundle:产品”)->找到($id);如果(!$产品) {扔$这->createNotFoundException (“没有为id找到产品”.$id);}$产品->setName (“新产品名称!”);$新兴市场->冲洗();返回$这->重定向($这->generateUrl (“主页”));}
更新对象只涉及三个步骤:
- 从Doctrine中获取对象;
- 修改对象;
- 调用
冲洗()
在实体管理器上
请注意(em - >坚持美元产品)
是没有必要的。回想一下,这个方法只是告诉Doctrine管理或“监视”对象美元的产品
对象。在本例中,由于您获取了美元的产品
来自Doctrine的对象,它已经被管理好了。
删除对象
对象的删除非常类似,但需要调用remove ()
实体管理器方法:
1 2
$新兴市场->remove ($产品);$新兴市场->冲洗();
如你所料,remove ()
方法通知Doctrine您希望从数据库中删除给定对象。实际的删除
查询,但是直到冲洗()
方法。
查询对象
你已经看到了repository对象是如何让你不做任何工作就可以运行基本查询的:
1 2 3
$存储库->找到($id);$存储库->findOneByName (“Foo”);
当然,Doctrine还允许您使用Doctrine Query Language (DQL)编写更复杂的查询。DQL类似于SQL,除了您应该想象您正在查询一个实体类的一个或多个对象(例如。产品
),而不是查询表中的行(例如。产品
).
在Doctrine中查询时,您有两个选择:编写纯Doctrine查询或使用Doctrine的Query Builder。
使用Doctrine的查询生成器查询对象
假设您想查询产品,但只返回成本高于19.99
从最便宜的到最贵的。你可以使用Doctrine的QueryBuilder
:
1 2 3 4 5 6 7 8 9 10
$存储库=$这->getDoctrine ()->getRepository (“AcmeStoreBundle:产品”);$查询=$存储库->createQueryBuilder (“p”)->(在哪里'p.price >:价格')->setParameter (“价格”,“19.99”)->orderBy (“p.price”,“ASC”)->getQuery ();$产品=$查询->getResult ();
的QueryBuilder
对象包含构建查询所需的每个方法。通过调用getQuery ()
方法时,查询构建器将返回一个法线查询
对象,该对象可用于获取查询的结果。
提示
请注意setParameter ()
方法。在使用Doctrine时,将任何外部值设置为“占位符”总是一个好主意(:价格
例如上面的例子),因为它可以防止SQL注入攻击。
的getResult ()
方法返回结果数组。为了只得到一个结果,您可以使用getSingleResult ()
(抛出异常,没有结果)或getOneOrNullResult ()
:
1
$产品=$查询->getOneOrNullResult ();
有关Doctrine的查询生成器的更多信息,请参阅Doctrine的查询构建器欧宝官网下载app文档。
使用DQL查询对象
而不是使用QueryBuilder
,您也可以直接使用DQL编写查询:
1 2 3 4 5 6 7 8 9
$新兴市场=$这->getDoctrine ()->getManager ();$查询=$新兴市场->createQuery (“SELECT p FROM AcmeStoreBundle:Product p WHERE p.price >:price ORDER BY p.price ASC”)->setParameter (“价格”,“19.99”);$产品=$查询->getResult ();
如果您熟悉SQL,那么DQL应该感觉非常自然。最大的区别是您需要考虑“对象”,而不是数据库中的行。因此,您选择从的AcmeStoreBundle:产品
对象然后用别名表示p
(如您所见,这与您在前一节中所做的相同)。
DQL语法非常强大,允许您轻松地在实体之间连接(本文的主题是关系稍后将讨论)、组等。欲了解更多信息,请参阅官方教义Doctrine查询语言欧宝官网下载app文档。
自定义存储库类
在前面的小节中,您开始从控制器内部构造和使用更复杂的查询。为了隔离、测试和重用这些查询,为您的实体创建一个自定义存储库类并在其中添加带有查询逻辑的方法是一个很好的实践。
为此,将存储库类的名称添加到映射定义中:
- 注释
- YAML
- XML
12 3 4 5 6 7 8 9 10 11 12
/ / src / Acme / / Product.php StoreBundle /实体名称空间Acme\StoreBundle\实体;使用学说\ORM\映射作为ORM;/ * * *@ORMAcme \ StoreBundle \ \实体(repositoryClass = "实体\ ProductRepository ") * /类产品{/ /……}
Doctrine可以通过运行前面用来生成缺少的getter和setter方法的相同命令为您生成存储库类:
1
$ php应用/控制台原则:生成:实体Acme
接下来,添加一个新方法-findAllOrderedByName ()
-到新生成的存储库类。该方法将查询所有的产品
实体,按字母顺序排列。
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/ / src / Acme / / ProductRepository.php StoreBundle /实体名称空间Acme\StoreBundle\实体;使用学说\ORM\EntityRepository;类ProductRepository扩展EntityRepository{公共函数findAllOrderedByName(){返回$这->getEntityManager ()->createQuery (SELECT p FROM AcmeStoreBundle:Product p ORDER BY p.name ASC)->getResult ();}}
提示
实体管理器可以通过$ this - > getEntityManager ()
从存储库内部。
你可以像使用存储库的默认查找器方法一样使用这个新方法:
1 2 3
$新兴市场=$这->getDoctrine ()->getManager ();$产品=$新兴市场->getRepository (“AcmeStoreBundle:产品”)->findAllOrderedByName ();
请注意
在使用自定义存储库类时,仍然可以访问默认查找器方法,例如find ()
而且findAll ()
.
实体关系/协会
假设应用程序中的产品完全属于一个“类别”。在这种情况下,你需要一个类别
对象和关联对象的方法产品
对象的类别
对象。首先创建类别
实体。因为您知道您最终需要通过Doctrine来持久化类,所以您可以让Doctrine为您创建类。
1
$ PHP应用程序/控制台原则:生成:实体——实体=“AcmeStoreBundle:类别”——字段=“名字:字符串(255)”
此任务生成类别
实体为你,用一个id
场,的名字
字段和相关的getter和setter函数。
关系映射元数据
联系类别
而且产品
实体,首先创建一个产品
的属性类别
类:
- 注释
- YAML
- XML
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/ / src / Acme / / Category.php StoreBundle /实体/ /……使用学说\常见的\集合\ArrayCollection;类类别{/ /……/ * * *@ORM\OneToMany(targetEntity="Product", mappedBy="category") */受保护的$产品;公共函数__construct(){$这->产品=新ArrayCollection ();}}
首先,由于类别
对象会涉及到很多产品
对象,产品
添加数组属性来保存它们产品
对象。同样,这样做并不是因为Doctrine需要它,而是因为它在每个应用程序中都有意义类别
保存…的数组产品
对象。
请注意
的代码__construct ()
方法很重要,因为教义要求美元的产品
属性为ArrayCollection
对象。这个物体的样子和作用几乎是一样的完全类似于数组,但有一些额外的灵活性。如果这让你不舒服,别担心。想象一下这是一个数组
你的身材会很好。
提示
上面使用的装饰器中的targetEntity值可以引用具有有效名称空间的任何实体,而不仅仅是同一名称空间中定义的实体。要关联到不同类或包中定义的实体,请输入完整的名称空间作为targetEntity。
接下来,由于产品
类只能与一个相关类别
对象时,您需要添加一个美元的类别
属性产品
类:
- 注释
- YAML
- XML
12 3 4 5 6 7 8 9 10 11 12 13
/ / src / Acme / / Product.php StoreBundle /实体/ /……类产品{/ /……/ * * *@ORM\ManyToOne(targetEntity="Category", inversedBy="products") *@ORM\JoinColumn(name="category_id", referencedColumnName="id") */受保护的$类别;}
最后,现在您已经向两个类别
而且产品
类,告诉Doctrine为你生成缺少的getter和setter方法:
1
$ php应用/控制台原则:生成:实体Acme
暂时忽略Doctrine元数据。你现在有两个类类别
而且产品
自然的一对多关系。的类别
类的数组产品
对象和产品
物体可以容纳一个类别
对象。换句话说,您已经以一种对您的需求有意义的方式构建了类。数据需要持久化到数据库始终是次要的。
现在,看看上面的元数据美元的类别
的属性产品
类。这里的信息告诉Doctrine相关的类是类别
它应该存储id
的类别记录上category_id添加
的场产品
表格换句话说,是相关的类别
对象将存储在美元的类别
属性,但在幕后,Doctrine将通过将类别的id值存储在category_id添加
的列产品
表格
上面的元数据美元的产品
的属性类别
对象不那么重要,只是告诉主义看Product.category
属性来确定如何映射关系。
在继续之前,请务必告诉Doctrine添加新的类别
表,product.category_id
列和新外键:
1
$ PHP应用程序/控制台原则:schema:update——force
请注意
这个任务应该只在开发期间使用。有关系统地更新生产数据库的更健壮的方法,请阅读Doctrine迁移。
保存相关实体
现在您可以看到这个新代码的实际运行!假设你在一个控制器中:
12 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
/ /……使用Acme\StoreBundle\实体\类别;使用Acme\StoreBundle\实体\产品;使用ob娱乐下载\组件\HttpFoundation\响应;类DefaultController扩展控制器{公共函数createProductAction(){$类别=新类别();$类别->setName (主要产品的);$产品=新产品();$产品->setName (“Foo”);$产品->setPrice (19.99);//将该产品与类别联系起来$产品->setCategory ($类别);$新兴市场=$这->getDoctrine ()->getManager ();$新兴市场->persist ($类别);$新兴市场->persist ($产品);$新兴市场->冲洗();返回新响应('创建的产品id: '.$产品->getId()。和类别id: '.$类别->getId ());}}
现在,一行被添加到两个类别
而且产品
表。的product.category_id
新产品的列设置为id
属于新类别。教条为你管理这种关系的持久性。
获取相关对象
当您需要获取关联对象时,您的工作流看起来就像以前一样。首先,获取美元的产品
对象,然后访问其相关类别
:
1 2 3 4 5 6 7 8 9 10
公共函数showAction($id){$产品=$这->getDoctrine ()->getRepository (“AcmeStoreBundle:产品”)->找到($id);$categoryName=$产品->getCategory ()->getName ();/ /……}
在本例中,首先查询a产品
对象基于产品的id
.的查询只是该产品的数据和补水美元的产品
对象使用该数据。等会儿,等你打电话的时候产品- > getCategory()——> getName ()
,教义默默地进行第二次查询,以找到类别
这和这个有关产品
.它准备美元的类别
对象并将它返回给你。
重要的是,您可以很容易地访问产品的相关类别,但直到您请求类别时,类别数据才会实际检索到(即它是“惰性加载”)。
您也可以向其他方向查询:
1 2 3 4 5 6 7 8 9 10
公共函数showProductAction($id){$类别=$这->getDoctrine ()->getRepository (“AcmeStoreBundle:类别”)->找到($id);$产品=$类别->getProducts ();/ /……}
在本例中,发生了相同的情况:首先查询单个类别
对象,然后Doctrine执行第二个查询以检索相关的产品
对象,但只有一次/如果你要求他们(即当你调用- > getProducts ()
).的美元的产品
Variable是all的数组产品
与给定对象相关的对象类别
对象通过category_id添加
价值。
加入相关记录
在上面的例子中,进行了两个查询——一个是原始对象(例如a类别
)和一个用于相关对象(例如产品
对象)。
提示
请记住,您可以通过web调试工具栏查看请求期间进行的所有查询。
当然,如果您事先知道需要访问这两个对象,则可以通过在原始查询中发出连接来避免第二个查询。属性中添加以下方法ProductRepository
类:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/ / src / Acme / / ProductRepository.php StoreBundle /实体公共函数findOneByIdJoinedToCategory($id){$查询=$这->getEntityManager ()->createQuery ('SELECT p, c FROM AcmeStoreBundle:Product p JOIN p.category c WHERE p.id =:id')->setParameter (“id”,$id);试一试{返回$查询->getSingleResult ();}抓(\ \ ORM \ NoResultException教义$e) {返回零;}}
现在,你可以在控制器中使用这个方法来查询产品
对象及其相关对象类别
只有一个问题:
1 2 3 4 5 6 7 8 9 10
公共函数showAction($id){$产品=$这->getDoctrine ()->getRepository (“AcmeStoreBundle:产品”)->findOneByIdJoinedToCategory ($id);$类别=$产品->getCategory ();/ /……}
更多有关关联的资料
本节介绍了一种常见的实体关系类型,即一对多关系。有关如何使用其他类型关系(例如,一对一,多对多)的更高级细节和示例,请参阅Doctrine关联映射文档欧宝官网下载app.
请注意
如果使用注释,则需要在所有注释前加上ORM \
(如。ORM \ OneToMany
),并没有反映在Doctrine的文档中。欧宝官网下载app您还需要包括使用Doctrine\ORM\Mapping作为ORM;
声明,进口的ORM
注释前缀。
生命周期回调
有时,您需要在插入、更新或删除实体之前或之后执行某个操作。这些类型的操作被称为“生命周期”回调,因为它们是你需要在实体生命周期的不同阶段执行的回调方法(例如,实体被插入、更新、删除等)。
如果要对元数据使用注释,首先要启用生命周期回调。如果您使用YAML或XML进行映射,则不需要这样做。
1 2 3 4 5 6 7 8
/ * * *@ORM() * \实体@ORM\ HasLifecycleCallbacks () * /类产品{/ /……}
现在,您可以告诉Doctrine在任何可用的生命周期事件上执行一个方法。例如,假设你想要设置一个createdAt
Date列到当前日期,仅当实体第一次被持久化(即插入)时:
- 注释
- YAML
- XML
1 2 3 4 5 6 7 8 9
/ / src / Acme / / Product.php StoreBundle /实体/ * * *@ORM\ PrePersist * /公共函数setCreatedAtValue(){$这->createdAt =新\ DateTime ();}
请注意
上面的示例假设您已经创建并映射了一个createdAt
属性(此处未显示)。
现在,在首次持久化实体之前,Doctrine将自动调用此方法和createdAt
字段将被设置为当前日期。
还有一些其他的生命周期事件可以被您钩入。有关其他生命周期事件和生命周期回调的更多信息,请参阅Doctrine生命周期事件文档欧宝官网下载app.
理论领域类型
Doctrine提供了大量可用的字段类型。它们中的每一个都将PHP数据类型映射到您所使用的数据库中的特定列类型。对于每个字段类型,列
可以进一步配置,设置长度
,可以为空
的行为,的名字
还有其他选择。要查看所有可用类型的列表和更多信息,请参阅Doctrine的映射类型文档欧宝官网下载app.
总结
使用Doctrine,您可以专注于对象以及它们在应用程序中的用处,然后再考虑数据库持久性。这是因为Doctrine允许您使用任何PHP对象来保存数据,并依赖于映射元数据信息将对象的数据映射到特定的数据库表。
尽管Doctrine围绕着一个简单的概念,但它非常强大,允许您创建复杂的查询和订阅事件,允许您在对象经历其持久性生命周期时采取不同的操作。