数据库和教义ORM

编辑该页面

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

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

数据库和教义ORM

截屏视频

你喜欢视频教程?检查教义视频系列

欧宝娱乐app下载地址Symfony没有提供一个组件使用的数据库,但它提供与第三方库称为紧密集成学说

请注意

本文是关于使用ORM原则。如果你喜欢用原始的数据库查询,看到“如何使用原则DBAL吗”文章。

你也可以保存数据MongoDB使用原则ODM图书馆。看到“DoctrineMongoDBBundle _”文档。欧宝体育电话

安装原则

首先,通过ORM包安装原则支持,以及MakerBundle,这将有助于生成一些代码:

1 2
美元作曲家需要symfony / or欧宝娱乐app下载地址m-pack美元作曲家需要symfony / ma欧宝娱乐app下载地址ker-bundle - dev

配置数据库

数据库连接信息存储为一个环境变量DATABASE_URL。发展,你会发现和定制这里面.env:

1 2 3 4 5 6 7
# .env(或覆盖在.env DATABASE_URL。当地以避免提交您的更改)#定制这一行!DATABASE_URL = " mysql: / / db_user: db_password@127.0.0.1:3306 / db_name”#使用sqlite: # DATABASE_URL =“sqlite: / / / % kernel.project_dir % / var / app.db”

谨慎

如果用户名、密码,主机或数据库名称包含任何字符被认为是一个URI(如特殊!,@,美元,#,/),您必须对它们进行编码。看到RFC 3986保留字符或使用的完整列表urlencode函数进行编码。在这种情况下,你需要删除解决:前缀的配置/包/ doctrine.yaml为了避免错误:url: ' % env(解决:DATABASE_URL) % '

现在你的连接参数设置,教义可以创建db_name数据库:

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

有更多的选择配置/包/ doctrine.yaml您可以配置,包括你server_version(如5.7如果你使用MySQL 5.7),这可能会影响到原则的功能。

提示

还有许多其他学说的命令。运行php bin /控制台列表教义看到一个完整的列表。

创建一个实体类

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

您可以使用:实体命令你需要创建这个类和任何字段。命令将会问你一些问题,回答像做如下:

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
美元php bin /控制台:实体类名的实体来创建或更新:>产品新属性名称(按<返回>停止添加字段):>名称字段类型(输入?查看所有类型)[string]:[255] >字符串字段长度:> 255这个字段可以为空数据库(可以为空)(yes / no)[不]:>没有新的属性名(按<返回>停止添加字段):>价格领域类型(输入?查看所有类型)[string]: >整数这一领域能空吗数据库(可以为空)(yes / no)[不]:>没有新的属性名(按<返回>停止添加字段):>(按回车键完成)

1.3

的互动行为:实体命令是在MakerBundle 1.3中引入的。

哇!你现在有一个新的src /实体/ Product.php文件:

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 34
/ / src /实体/ Product.php名称空间应用程序\实体;使用学说\ORM\映射作为ORM;/ * * *@ORM实体(repositoryClass = \ App \ Repository \ ProductRepository) * /产品{/ * * *@ORM\ Id *@ORM\ GeneratedValue *@ORM\列(类型=“整数”)* /私人美元id;/ * * *@ORM\列(类型=“字符串”,长度= 255)* /私人美元的名字;/ * * *@ORM\列(类型=“整数”)* /私人美元价格;公共函数getId(){返回美元- >id;}/ /……getter和setter方法}

请注意

困惑为什么价格是整数?不要担心,这只是一个例子。但是,存储价格为整数(例如100 = 1美元)可以避免舍入的问题。

谨慎

有一个767字节的索引键限制前缀当使用InnoDB表在MySQL 5.6和更早的版本。255个字符长度和字符串列utf8mb4编码超过极限。这意味着任何类型的列字符串独特= true必须设置它的最大长度190年。否则,你将会看到这个错误:“PDOException SQLSTATE[42000]:语法错误或访问违例:1071指定的密钥太长;马克斯关键长度是767字节”

这类被称为一个“实体”。很快,你就可以保存和查询产品对象产品表在数据库中。每个属性的产品实体可以被映射到表的一列。这通常是用注释:@ORM \…你在上面看到的评论每个属性:

:实体命令是一个工具,使生活变得更加容易。但这是你的代码:添加/删除字段,添加/删除或更新配置方法。

学说支持各种各样的字段类型,每个都有自己的选择。看到一个完整的列表,请查看教义的映射类型文档欧宝体育电话。如果你想使用XML而不是注释,添加类型:xmldir:“% kernel.project_dir % / config /学说”在你的实体映射配置/包/ doctrine.yaml文件。

谨慎

小心不要使用SQL关键字保留作为表名或列名(如。集团用户)。看到学说的保留SQL关键字的文档欧宝体育电话如何摆脱这些细节。或者,改变表名@ORM \表(name = "集团")在类或配置的列名name = " group_name "选择。

迁移:创建数据库表/模式

产品类是配置完整,准备保存到产品表。如果你只是这个类定义,数据库实际上并不拥有产品表。添加它,您可以利用DoctrineMigrationsBundle已经安装了:

1
美元php bin /控制台:迁移

如果一切工作,您应当会看到类似这样的:

成功!

下:审查新移民“src /迁移/ Version20180207231217。php”:运行迁移与php bin /控制台原则:迁移:迁移

如果你打开这个文件,它包含了SQL数据库需要更新!运行SQL,执行你的迁移:

1
美元php bin /控制台学说:迁移:迁移

这个命令执行所有迁移的文件还没有针对数据库运行。你应该上运行这个命令生产部署保持最新的生产数据库。

迁移和添加更多的字段

但是,如果您需要添加一个新的字段属性产品,就像一个描述吗?您可以编辑类来添加新属性。但是,您还可以使用:实体再次:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
美元php bin /控制台:实体类名称的实体来创建或更新>产品新属性名称(按<返回>停止添加字段):>描述字段类型(输入?查看所有类型)[string]: >文本这个字段可以为空数据库(可以为空)(yes / no)[不]:>没有新的属性名(按<返回>停止添加字段):>(按回车键完成)

这增加了新的描述财产和getDescription ()setDescription ()方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
/ / src /实体/ Product.php/ /……类产品{/ /……+ / * *+ * @ORM \列(type = "文本")+ * /+私人美元描述;/ / getDescription () & setDescription},还添加了()

新的属性映射,但它并不存在产品表。没问题!生成一个新的迁移:

1
美元php bin /控制台:迁移

这一次,生成的文件中的SQL会看起来像这样:

1
改变产品添加描述量变

迁移系统聪明的。比较你的所有实体的当前状态数据库并生成所需的SQL同步!像以前一样,执行你的迁移:

1
美元php bin /控制台学说:迁移:迁移

这样只会执行一个新移民文件,因为DoctrineMigrationsBundle知道第一个迁移已经执行。在幕后,它管理migration_versions表来跟踪。

每次你改变你的模式,运行这两个命令来生成迁移,然后执行它。一定要提交移民文件,当您部署执行它们。

提示

如果你喜欢手动添加新的属性,:实体命令可以生成getter和setter方法:

1
美元php bin /控制台:实体——再生

如果你做一些修改,并想再生所有getter / setter方法,还通过——覆盖

持久化对象到数据库

保存的时候了产品对象到数据库!让我们创建一个新的控制器实验:

1
美元php bin /控制台:控制器ProductController

控制器内部,您可以创建一个新的产品对象,设置数据,并保存它!

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
/ / src /控制器/ ProductController.php名称空间应用程序\控制器;/ /……使用应用程序\实体\产品;ProductController扩展AbstractController{/ * * *@Route(“/产品”,name = "产品")* /公共函数指数(){/ /可以通过$ this - >获取EntityManager getDoctrine ()/ /或者你可以将一个参数添加到您的行动:指数(EntityManagerInterface entityManager美元)美元entityManager=美元- >getDoctrine ()- >getManager ();美元产品=产品();美元产品- >setName (“键盘”);美元产品- >setPrice (1999年);美元产品- >setDescription (的人体工学和时尚!);/ /告诉学说你想(最终)保存产品(没有查询)美元entityManager- >persist (美元产品);/ /实际执行查询(即插入查询)美元entityManager- >冲洗();返回响应(“保存新产品id”美元产品- >getId ());}}

试一下!

http://localhost: 8000 /产品

恭喜你!你刚刚创建的第一行产品表。为了证明这一点,你可以直接查询数据库:

1 2 3 4
美元php bin /控制台学说:查询:sql“从产品选择*”#在Windows系统不使用Powershell,运行这个命令:# php bin /控制台学说:查询:sql SELECT *从产品”

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

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

请注意

如果冲洗()调用失败,学说\ ORM \ ORMException异常。看到事务和并发性

不管你是创建或更新对象,工作流总是相同的:原则是足够聪明知道这应该插入或更新你的实体。

从数据库中获取对象

获取一个对象的数据库更容易。假设你希望能够去/产品/ 1看到你的新产品:

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 /控制器/ ProductController.php/ /……/ * * *@Route(" /产品/ {id} " name = " product_show ") * /公共函数显示(美元id){美元产品=美元- >getDoctrine ()- >getRepository(产品::类)- >找到(美元id);如果(!美元产品){美元- >createNotFoundException (“没有发现产品id”美元id);}返回响应(“看看这个伟大的产品:”美元产品- >getName ());/ /或呈现模板/ /模板中,打印东西{{product.name}}/ /返回$ this - >渲染(产品/ show.html。嫩枝”,(“产品”= >产品美元));}

试一下!

http://localhost: 8000 /产品/ 1

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

一旦你有一个存储库对象,你有许多辅助方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
美元存储库=美元- >getDoctrine ()- >getRepository(产品::类);/ /寻找单一产品的主键(通常是“id”)美元产品=美元存储库- >找到(美元id);/ /寻找一个产品的名字美元产品=美元存储库- >findOneBy ([“名字”= >“键盘”]);/ /或者找到的名字和价格美元产品=美元存储库- >findOneBy ([“名字”= >“键盘”,“价格”= >1999年]);/ /寻找匹配的多个产品对象名称、订购价格美元产品=美元存储库- >findBy ([“名字”= >“键盘”]、[“价格”= >“ASC”]);/ /寻找* *产品所有对象美元产品=美元存储库- >findAll ();

你也可以加入自定义方法更复杂的查询!更晚些时候数据库和教义ORM部分。

提示

呈现一个HTML页面时,web调试工具栏底部的页面将显示查询的数量和执行时间:

如果数据库查询的数量过高,图标会变黄,表明一些可能不是正确的。点击图标打开Symfony分析器,看看具体执行的查询。欧宝娱乐app下载地址如果您没有看到web调试工具栏,尝试运行作曲家要求- dev symfony / pr欧宝娱乐app下载地址ofiler-pack安装它。

自动抓取对象(ParamConverter)

在许多情况下,您可以使用SensioFrameworkExtraBundle自动帮你查询!首先,安装包,以防你没有:

1
美元作曲家需要sensio赞助/ framework-extra-bundle

现在,简化你的控制器:

1 2 3 4 5 6 7 8 9 10 11 12 13
/ / src /控制器/ ProductController.php使用应用程序\实体\产品;/ /……/ * * *@Route(" /产品/ {id} " name = " product_show ") * /公共函数显示(产品美元产品){/ /使用的产品!/ /……}

就是这样!包使用{id}从路线查询产品id列。如果没有发现,生成一个404页的。

有很多选项可以使用。阅读更多关于ParamConverter

更新一个对象

一旦你获取一个对象从教条,你与它相同的与任何PHP交互模型:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/ * * *@Route(" /产品/编辑/ {id} ") * /公共函数更新(美元id){美元entityManager=美元- >getDoctrine ()- >getManager ();美元产品=美元entityManager- >getRepository(产品::类)- >找到(美元id);如果(!美元产品){美元- >createNotFoundException (“没有发现产品id”美元id);}美元产品- >setName (“新产品的名字!”);美元entityManager- >冲洗();返回美元- >redirectToRoute (“product_show”,(“id”= >美元产品- >getId ()));}

使用原则编辑现有产品包括三个步骤:

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

可以调用(entityManager - >保存美元产品),但它没有必要:学说已经“看”你的对象的变化。

删除一个对象

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

1 2
美元entityManager- >remove (美元产品);美元entityManager- >冲洗();

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

查询对象:存储库

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

1 2 3 4
/ /从一个控制器美元存储库=美元- >getDoctrine ()- >getRepository(产品::类);美元产品=美元存储库- >找到(美元id);

但是如果你需要一个更复杂的查询呢?当你生成实体:实体,命令生成一个ProductRepository类:

1 2 3 4 5 6 7 8 9 10 11 12 13 14
/ / src /仓库/ ProductRepository.php名称空间应用程序\存储库;使用应用程序\实体\产品;使用学说\\DoctrineBundle\存储库\ServiceEntityRepository;使用欧宝娱乐app下载地址\\学说\RegistryInterface;ProductRepository扩展ServiceEntityRepository{公共函数__construct(RegistryInterface美元注册表){::__construct (美元注册表、产品::类);}}

当你获取存储库(即。- > getRepository(产品::类)),这是实际上的一个实例对象!这是由于repositoryClass在你的配置生成产品实体类。

假设您想查询所有产品对象大于一定的价格。添加一个新方法,这样您的存储库:

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
/ / src /仓库/ ProductRepository.php/ /……ProductRepository扩展ServiceEntityRepository{公共函数__construct(RegistryInterface美元注册表){::__construct (美元注册表、产品::类);}/ * * *@param美元价格*@return产品[]* /公共函数findAllGreaterThanPrice(美元价格):数组{/ /自动知道选择产品/ /“p”是您将使用的别名查询美元qb=美元- >createQueryBuilder (“p”)- >引入(“p。价格>:价格的)- >setParameter (“价格”,美元价格)- >orderBy (“p.price”,“ASC”)- >getQuery ();返回美元qb- >execute ();/ /得到只有一个结果:/ /产品=美元qb - > setMaxResults (1) - > getOneOrNullResult ();}}

它使用原则的查询构建器:一个非常强大的和友好的方式来编写自定义查询。现在,您可以在存储库中调用这个方法:

1 2 3 4 5 6 7 8
/ /从一个控制器美元minPrice=1000年;美元产品=美元- >getDoctrine ()- >getRepository(产品::类)- >findAllGreaterThanPrice (美元minPrice);/ /……

如果你在一个服务容器,您可以type-hintProductRepository类和注入感觉正常。

更多细节,请参阅查询构建器欧宝体育电话文档从教义。

与DQL或SQL查询

除了查询生成器,您还可以查询教义的查询语言:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/ / src /仓库/ ProductRepository.php/ /……公共函数findAllGreaterThanPrice(美元价格):数组{美元entityManager=美元- >getEntityManager ();美元查询=美元entityManager- >createQuery (“从App \实体\产品选择p p, p。价格>:价格按p。ASC的价格)- >setParameter (“价格”,美元价格);/ /返回一个产品对象数组返回美元查询- >execute ();}

或直接与SQL如果你需要:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ / src /仓库/ ProductRepository.php/ /……公共函数findAllGreaterThanPrice(美元价格):数组{美元康涅狄格州=美元- >getEntityManager ()- >getConnection ();美元sql=“从产品选择* p, p。价格>:价格按p。ASC的价格;美元支撑=美元康涅狄格州- >准备(美元sql);美元支撑- >执行([“价格”= >美元价格]);/ /返回一个数组的数组(即原始数据集)返回美元支撑- >fetchAll ();}

使用SQL,您将回到原始数据,而不是对象(除非你使用NativeQuery功能)。

关系和联系

学说提供了所有你需要的功能来管理数据库(也称为协会)的关系,包括ManyToOne OneToMany, OneToOne和多关系。

信息,请参阅如何使用主义协会/关系

虚拟数据设备

学说提供了一个库,允许您以编程方式测试数据加载到您的项目(即。“固定数据”)。安装:

1
美元作曲家需要原则/ doctrine-fixtures-bundle - dev

然后,使用:设备命令来生成一个空夹具类:

1 2 3 4
美元php bin /控制台:夹具装置创建的类名(例如AppFixtures): > ProductFixture

自定义新的类加载产品对象为原则:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/ / src / DataFixtures / ProductFixture.php名称空间应用程序\DataFixtures;使用学说\\FixturesBundle\夹具;使用学说\常见的\持久性\ObjectManager;ProductFixture扩展夹具{公共函数负载(ObjectManager美元经理){美元产品=产品();美元产品- >setName (“无价的工具!”);美元产品- >setPrice (14.50);美元产品- >setDescription (‘好吧,我猜这* *有价格的);美元经理- >persist (美元产品);/ /添加更多的产品美元经理- >冲洗();}}

空的数据库并重新加载所有设备类:

1
美元php bin /控制台学说:夹具:负载

信息,请参阅“DoctrineFixturesBundle _”文档。欧宝体育电话

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