数据库和教义ORM
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 4.1,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.2(当前的稳定版本)。
数据库和教义ORM
截屏视频
你喜欢视频教程?检查教义视频系列。
ob娱乐下载Symfony没有提供一个组件使用的数据库,但它做提供与第三方库称为紧密集成学说。
请注意
本文是关于使用ORM原则。如果你喜欢用原始的数据库查询,看到“如何使用原则DBAL吗”文章。
你也可以保存数据MongoDB使用原则ODM图书馆。看到“DoctrineMongoDBBundle _”文档。欧宝官网下载app
安装原则
首先,通过ORM包安装原则支持,以及MakerBundle,这将有助于生成一些代码:
1 2
美元作曲家需要symfony / orob娱乐下载m-pack美元作曲家需要symfony / maob娱乐下载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 \…
你在上面看到的评论每个属性:
的:实体
命令是一个工具,使生活变得更加容易。但这是你的代码:添加/删除字段,添加/删除或更新配置方法。
学说支持各种各样的字段类型,每个都有自己的选择。看到一个完整的列表,请查看教义的映射类型文档欧宝官网下载app。如果你想使用XML而不是注释,添加类型:xml
和dir:“% kernel.project_dir % / config /学说”
在你的实体映射配置/包/ doctrine.yaml
文件。
谨慎
小心不要使用SQL关键字保留作为表名或列名(如。集团
或用户
)。看到学说的保留SQL关键字的文档欧宝官网下载app如何摆脱这些细节。或者,改变表名@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 ());}}
试一下!
恭喜你!你刚刚创建的第一行产品
表。为了证明这一点,你可以直接查询数据库:
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。嫩枝”,(“产品”= >产品美元));}
试一下!
查询一个特定类型的对象时,你总是用所谓的“仓库”。你可以认为一个存储库是一个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分析器,看看具体执行的查询。ob娱乐下载如果您没有看到web调试工具栏,尝试运行作曲家要求- dev symfony / prob娱乐下载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 ()));}
使用原则编辑现有产品包括三个步骤:
- 获取对象从教义;
- 修改对象;
- 调用
冲洗()
实体管理器。
你可以调用(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;使用ob娱乐下载\桥\学说\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
类和注入感觉正常。
更多细节,请参阅查询构建器欧宝官网下载app文档从教义。
与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功能)。
虚拟数据设备
学说提供了一个库,允许您以编程方式测试数据加载到您的项目(即。“固定数据”)。安装:
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 _”文档。欧宝官网下载app