书籍Symfony 5:快速轨道欧宝娱乐app下载地址

欧宝娱乐app下载地址Symfony 5:快速轨道是学习现代Symfony发展,从零到生产的最好书籍。欧宝娱乐app下载地址+300页展示Symfony与Docker,欧宝娱乐app下载地址 api,队列和异步任务,Webpack, spa等。

数据库和ORM原则

数据库和ORM原则

截图

你更喜欢视频教程吗?看看教义扫描系列

欧宝娱乐app下载地址symfony提供了在应用程序中使用数据库所需的所有工具学说,最好的PHP库与数据库一起使用。这些工具支持MySQL和PostgreSQL等关系数据库以及MongoDB等NoSQL数据库。

数据库是一个广泛的主题,因此文档分为三篇文章:欧宝体育电话

  • 本文解释了推荐的使用方法关系数据库在Sy欧宝娱乐app下载地址mfony应用程序;
  • 这其他文章如果你需要低级访问对关系数据库执行原始SQL查询(类似于PHP的PDO.);
  • DoctrineMongoDBBundle文档如果你正在使用MongoDB数据库

安装原则

首先,通过orm欧宝娱乐app下载地址Symfony包,以及MakerBundle,它将帮助生成一些代码:

1 2
作曲家需要symfony / or欧宝娱乐app下载地址m-pack编写器需要——dev symfony/make欧宝娱乐app下载地址r-bundle

配置数据库

数据库连接信息存储为调用的环境变量database_url..对于开发,您可以在内部找到并自定义.env.

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#.env(或override database_url in .env.local以避免提交更改)#自定义此行!database_url =“mysql:// db_user:[电子邮件受保护]:3306 / db_name?serverversion = 5.7“#使用mariadb:database_url =”mysql:// db_user:[电子邮件受保护]sql: # DATABASE_URL="sqlite:///%kernel.project_dir%/var/app.db" #使用postgresql: # DATABASE_URL="postgresql://db_user:[电子邮件受保护]:5432 / db_name?serverversion = 11&charset = utf8“#使用Oracle:#database_url =”oci8:// db_user:[电子邮件受保护]: 1521 / db_name”

警告

如果用户名,密码,主机或数据库名称包含在URI中被视为特殊的任何字符(例如+/),你必须对它们进行编码。看RFC 3986获取保留字符的完整列表或使用urlencode用于编码它们的功能。在这种情况下,您需要删除解决:前缀配置/包/ doctrine.yaml为了避免错误:url:' % env(解决:DATABASE_URL) %

现在您的连接参数已经设置好了,Doctrine可以创建db_name.数据库为您:

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

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

提示

还有许多其他的教条命令。运行php垃圾箱/控制台列表学说查看完整列表。

创建实体类

假设您正在构建一个应用程序,需要显示产品。甚至没有考虑学说或数据库,你已经知道你需要一个产品对象来表示这些产品。

你可以使用制作:实体命令创建此类以及所需的任何字段。该命令将问您一些问题 - 回答它们如下所示:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21 21 22 23 22 22 22 22 22 28 22
$ PHP BIN / CONSOLE:ENTITITE类的实体名称要创建或更新:>产品新属性名称按<返回>停止添加字段: > name字段类型进入 ?查看所有类型(细绳: > string字段长度(255.: >255.此字段是否可以在数据库中为空可以为空是/否(没有:>没有新的财产名称按<返回>停止添加字段:>价格领域类型进入 ?查看所有类型(细绳: > integer该字段在数据库中是否为空可以为空是/否(没有:>没有新的财产名称按<返回>停止添加字段: >再次按回车键完成

1.3新版功能:互动行为制作:实体命令是在MakerBundle 1.3中引入的。

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

/ / src /实体/ Product.php名称空间应用程序\实体使用app \ repository \ productRepository使用主义\ \ ORM映射作为orm./ * ** @ORM \实体(repositoryClass = ProductRepository::类)* /班级产品/ * ** @orm \ id()* @ORM \ GeneratedValue ()* @ORM \列(type =“整数”)* /私人$ ID/ * ** @ORM \列(类型=“字符串”,长度= 255)* /私人$名称/ * ** @ORM \列(type =“整数”)* /私人$!公共函数getId()int返回这个美元->id/ /……Getter和setter方法

笔记

为什么价格是整数?别担心,这只是个例子。但是,将价格存储为整数(例如100 = $1 USD)可以避免四舍五入问题。

笔记

如果您使用的是SQLite数据库,您将看到以下错误:PDOException: SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL column with default value NULL.添加A.nullable = true可以选择的描述属性来解决问题。

警告

有一个索引密钥前缀限制为767个字节在MySQL 5.6和更早的版本中使用InnoDB表时。长度为255个字符的字符串列UTF8MB4.编码超过了这个限制。这意味着任何类型的列细绳独特= true必须设置其最大值长度190.否则,您将看到此错误:" [PDOException] SQLSTATE[42000]: Syntax error or access违例:1071 Specified key was too long;最大密钥长度为767字节"

这个类被称为“实体”。很快,您就能够将Product对象保存并查询到产品表。中的每个属性产品实体可以映射到该表中的列。这通常是用注释完成的:@orm \ ...你在每个属性上面看到的注释:

_images / mapping_single_entity.png

制作:实体命令是一种让生活更轻松的工具。但这就是你的代码:添加/删除字段,添加/删除方法或更新配置。

学说支持各种各样的领域类型,每种类型都有自己的选项。要查看完整的列表,请检查原则的映射类型文档欧宝体育电话.如果要使用XML而不是注释,请添加类型:xmldir:'%kernel.project_dir%/ config / doctrine'到你的实体映射配置/包/ doctrine.yaml文件。

警告

注意不要使用保留的SQL关键字作为表名或列名。团体用户).看到学说的保留的SQL关键字文档欧宝体育电话关于如何转义这些的详细信息。或者将表名更改为@orm \ table(name =“组”)在课堂上方或配置列名name =“group_name”选项。

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

产品类已完全配置,可以保存到产品表格如果你只是定义了这个类,你的数据库实际上没有产品表尚未。要添加它,您可以利用DoctrineMigratiesBundle.,它已经安装:

1
PHP BIN / CONSOLE使:迁移

如果一切正常,你应该看到如下内容:

成功!

下一页:查看新迁移“迁移/ reverse20180207231217.php”然后:使用php bin / console doctrine运行迁移:迁移:迁移

如果打开此文件,它包含更新数据库所需的SQL!要运行该SQL,请执行迁移:

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

此命令执行尚未对数据库运行的所有迁移文件。部署以使生产数据库保持最新时,您应该在生产上运行此命令。

迁移&添加更多字段

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
$ php bin / console使:实体的实体类名为创建或更新>产品新属性名称按<返回>停止添加字段:>描述字段类型进入 ?查看所有类型(细绳: > text该字段在数据库中是否可以为空可以为空是/否(没有:>没有新的财产名称按<返回>停止添加字段: >再次按回车键完成

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

12 3 4 5 6 7 8 9 10 11 12 13 14
// src/ Product.php //…class Product{//…+ / * *+ * @ORM \列(type = "文本")+ * /+私人$描述;// getDescription()和setDescription()也被添加}

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

1
PHP BIN / CONSOLE使:迁移

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

1
改变表格产品添加描述量变

迁移系统是聪明的.它将所有实体与数据库的当前状态进行了比较,并生成同步它们所需的SQL!就像之前一样,执行迁移:

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

这只会执行一个新的迁移文件,因为DoctrineMigrationsBundle知道第一次迁移在前面已经执行了。在后台,它管理一个migration_versions表来跟踪这个。

每次对模式进行更改时,运行这两个命令来生成迁移,然后执行它。请确保提交迁移文件并在部署时执行它们。

提示

如果您愿意手动添加新属性,请制作:实体命令可以为您生成Getter和Setter方法:

1
PHP bin/console make:entity——regenerate

如果您做了一些更改并想重新生成所有Getter /setter方法,也传递——覆盖

将对象持久化到数据库

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

1
php bin/console make:controller ProductController . php

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

/ / src /控制器/ ProductController.php名称空间App \控制器/ /……使用应用\ \实体产品使用Doctrine \ orm \ entityManagerInterface使用欧宝娱乐app下载地址symfony \ component \ httpfoundation \ response班级ProductController扩展AbstractController./ * ** @Route(“/产品名称=“create_product”)* /公共函数CreateProduct.()响应//您可以通过$ this-> getdoctrine()获取EntityManager//或者你可以添加一个参数到动作:$ EntityManager.这个美元->GetDoctrine.()->GetManager.();美元的产品产品();美元的产品->setname.“键盘”);美元的产品->setPrice1999年);美元的产品->setDescription'符合人体工程学和时尚!');//告诉Doctrine你想(最终)保存产品(还没有查询)$ EntityManager.->坚持美元的产品);//实际上执行查询(即插入查询)$ EntityManager.->冲洗();返回响应'以id保存新产品'美元的产品->getId());

试试看!

恭喜你!控件中创建了第一行产品表格要证明它,您可以直接查询数据库:

1 2 3 4
php bin /控制台学说:查询:sql'SELECT * FROM product'#在没有使用Powershell的Windows系统上,运行这个命令:# php bin/console doctrine:query:sql "SELECT * FROM product"

让我们更详细地看看前面的例子:

  • 第18行$ this-> getdoctrine() - > getManager()方法得到了学说的实体管理器客体,是《学说》中最重要的客体。它负责将对象保存到数据库,并从数据库中获取对象。
  • 行20在本节中,实例化并使用美元的产品像任何其他普通PHP对象一样的对象。
  • 第26行坚持(产品)呼叫告诉学说“管理”美元的产品目的。这有点不是对数据库进行查询。
  • 第29行当。。。的时候冲洗()方法被调用时,Doctrine会检查它管理的所有对象,看它们是否需要被持久化到数据库中。在本例中美元的产品数据库中不存在对象的数据,因此实体管理器执行一个插入查询中创建新行产品表格

笔记

如果冲洗()调用失败,Doctrine \ orm \ ormexception异常。看事务和并发性

无论您是创建还是更新对象,工作流程都始终相同:Doctrine智能足以知道它是否应该插入或更新您的实体。

验证对象

symf欧宝娱乐app下载地址ony验证器重用学说元数据来执行一些基本验证任务:

/ / src /控制器/ ProductController.php名称空间App \控制器使用应用\ \实体产品使用欧宝娱乐app下载地址symfony \ component \ httpfoundation \ response使用欧宝娱乐app下载地址Symfony \验证器\ \组件验证器\ ValidatorInterface/ /……班级ProductController扩展AbstractController./ * ** @Route(“/产品名称=“create_product”)* /公共函数CreateProduct.validatorInterface.$验证器响应美元的产品产品();//这将触发一个错误:列在数据库中不是空的美元的产品->setname.);//这将触发类型不匹配错误:预期整数美元的产品->setPrice'1999');/ /……美元的错误$验证器->证实美元的产品);如果数数美元的错误>0返回响应((细绳美元的错误400);/ /……

虽然产品实体没有明确定义任何东西验证配置, 欧宝娱乐app下载地址Symfony会对Doctrine映射配置进行内省,以推断出一些验证规则。例如,假定名称财产不能在数据库中,aNotNull约束将自动添加到属性(如果它不包含该约束)。

下表总结了Doctrine元数据和Symfony自动添加的相应验证约束之间的映射:欧宝娱乐app下载地址

义属性 验证约束 笔记
nullable = false. NotNull 需要安装PropertyInfo组件
类型 类型 需要安装PropertyInfo组件
独特= true UniqueEntity
长度 长度

因为表格组成部分以及API的平台内部使用验证器组件,所有表单和Web API也将自动从这些自动验证约束中受益。

此自动验证是提高您的生产力的一个很好的功能,但它不会完全取代验证配置。你仍然需要添加一些验证约束确保用户提供的数据是正确的。

从数据库中获取对象

从数据库中取回对象甚至更容易。假设你想去/产品/ 1看你的新产品:

/ / src /控制器/ ProductController.php名称空间App \控制器使用应用\ \实体产品使用欧宝娱乐app下载地址symfony \ component \ httpfoundation \ response/ /……班级ProductController扩展AbstractController./ * ** @Route(“/产品/ {id}”,name = " product_show ")* /公共函数表演int$ ID响应美元的产品这个美元->GetDoctrine.()->getRepository.产品::班级->找到$ ID);如果美元的产品这个美元->createNotFoundException“没有找到id的产品”$ ID);返回响应“看看这个伟大的产品:”美元的产品->getName());//或渲染模板//在模板中,用{{product.name}}打印物品//返回$ this-> render('product / show.html.twig',['product'=> $ product]);

另一种可能性是使用ProductRepository.使用Symf欧宝娱乐app下载地址ony的自动装配并通过依赖注入容器注入:

/ / src /控制器/ ProductController.php名称空间App \控制器使用应用\ \实体产品使用app \ repository \ productRepository使用欧宝娱乐app下载地址symfony \ component \ httpfoundation \ response/ /……班级ProductController扩展AbstractController./ * ** @Route(“/产品/ {id}”,name = " product_show ")* /公共函数表演int$ IDProductRepository.productRepository美元响应美元的产品productRepository美元->找到$ ID);/ /……

试试看!

当您查询特定类型的对象时,您总是使用所谓的“存储库”。您可以将存储库看作是一个PHP类,它的唯一工作就是帮助您获取某个类的实体。

有一个存储库对象后,您有很多帮助方法:

$存储库这个美元->GetDoctrine.()->getRepository.产品::班级);//通过主键(通常是"id")查找单个Product美元的产品$存储库->找到$ ID);//按名称查找单个产品美元的产品$存储库->FindOeby.([“名字”=>“键盘”]);//或通过名称和价格查找美元的产品$存储库->FindOeby.([“名字”=>“键盘”'价格'=>1999年]);//查看符合名称的多个产品对象,按价格订购美元的产品$存储库->findBy(“名字”=>“键盘”],('价格'=>'asc');//查找所有的产品对象美元的产品$存储库->findAll();

你也可以添加风俗用于更复杂查询的方法!更多的是在后来的查询对象:存储库部分。

提示

渲染HTML页面时,页面底部的Web Debug工具栏将显示执行它们所花费的查询数:

_images / doctrine_web_debug_toolbar.png.

如果数据库查询的数量过高,图标将变为黄色,表示可能不正确。单击图标以打开Symfony Profiler,并查看执行的欧宝娱乐app下载地址确切查询。如果没有看到web调试工具栏,请安装分析器欧宝娱乐app下载地址Symfony包执行以下命令:作曲家需要——开发欧宝娱乐app下载地址Symfony / Profiler-Pack

自动获取对象(ParamConverter)

在许多情况下,您可以使用sensioframeworkextrabundle.自动为您做查询!首先,安装包,如果你没有它:

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

现在,简化你的控制器:

/ / src /控制器/ ProductController.php名称空间App \控制器使用应用\ \实体产品使用app \ repository \ productRepository使用欧宝娱乐app下载地址symfony \ component \ httpfoundation \ response/ /……班级ProductController扩展AbstractController./ * ** @Route(“/产品/ {id}”,name = " product_show ")* /公共函数表演产品美元的产品响应//使用产品!/ /……

就是这样!捆绑使用{id}从路由查询到产品id柱子。如果未找到,则会生成404页。

你可以使用更多的选项。阅读更多关于ParamConverter

更新对象

一旦您从Doctrine获取了一个对象,您就与任何PHP模型相同:

/ / src /控制器/ ProductController.php名称空间App \控制器使用应用\ \实体产品使用app \ repository \ productRepository使用欧宝娱乐app下载地址symfony \ component \ httpfoundation \ response/ /……班级ProductController扩展AbstractController./ * ** @route(“/ product /编辑/ {id}”)* /公共函数更新int$ ID响应$ EntityManager.这个美元->GetDoctrine.()->GetManager.();美元的产品$ EntityManager.->getRepository.产品::班级->找到$ ID);如果美元的产品这个美元->createNotFoundException“没有找到id的产品”$ ID);美元的产品->setname.“新产品的名字!”);$ EntityManager.->冲洗();返回这个美元->redirectToRoute“product_show”(“id”=>美元的产品->getId()]);

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

  1. 从学说中获取客体;
  2. 修改对象;
  3. 调用冲洗()在实体管理器上。

可以称呼entityManager - >保存(产品),但这并不是必须的:教条已经在“观察”你的对象的变化。

删除对象

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

$ EntityManager.->删除美元的产品);$ EntityManager.->冲洗();

如你所料remove ()方法通知教义您希望从数据库中删除给定对象。的删除直到冲洗()方法被调用。

查询对象:存储库

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

//从控制器内部$存储库这个美元->GetDoctrine.()->getRepository.产品::班级);美元的产品$存储库->找到$ ID);

但是如果您需要一个更复杂的查询呢?当您使用制作:实体,命令生成A.ProductRepository.班级:

// src /存储库/ productRepository.php名称空间App \库使用应用\ \实体产品使用学说\包\ DoctrineBundle \ Repository \ ServiceEntityRepository使用主义\ \ ManagerRegistry持久性班级ProductRepository.扩展serviceentityRepository.公共函数__constructManagerRegistry.$注册表父母::__construct$注册表产品::班级);

当您获取您的存储库(即。- > getRepository(产品::类)),这是实际上一个例子目的!这是因为repositoryclass.在您的顶部生成的配置产品实体课程。

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

// src /存储库/ productRepository.php/ /……班级ProductRepository.扩展serviceentityRepository.公共函数__constructManagerRegistry.$注册表父母::__construct$注册表产品::班级);/ * ** @return产品[]* /公共函数findallgreaterthanprice.int$!数组$ EntityManager.这个美元->getEntityManager();美元的查询$ EntityManager.->Createquery.'选择P.从App \实体\产品p哪里p.price>:价格按P.Price ASC订购'->setParameter'价格'$!);//返回一个Product对象数组返回美元的查询->getResult();

这些字符串传递给createquery()可能看起来像SQL,但它是教义的查询语言.这允许您使用一般已知的查询语言输入查询,但引用PHP对象(即在陈述)。

现在,你可以在存储库中调用这个方法:

//从控制器内部minPrice美元1000美元的产品这个美元->GetDoctrine.()->getRepository.产品::班级->findallgreaterthanprice.minPrice美元);/ /……

将服务/配置注入到服务中如何将存储库注入任何服务。

查询查询构建器

教义也提供了查询构建器,面向对象写的询问方式。当查询是动态构建的查询时建议使用此(即,基于PHP条件):

// src /存储库/ productRepository.php/ /……班级ProductRepository.扩展serviceentityRepository.公共函数findallgreaterthanprice.int$!BOOL.includeUnavailableProducts美元错误的数组//自动知道选择产品//“p”是您在其余查询中使用的别名qb美元这个美元->CreatequeryBuilder.“p”->在哪里“p.price >:价格->setParameter'价格'$!->orderby.“p.price”'asc');如果includeUnavailableProducts美元qb美元->引入'p.available = true');美元的查询qb美元->getQuery.();返回美元的查询->执行();//只得到一个结果:// $product = $query->setMaxResults(1)->getOneOrNullResult();

用SQL查询

此外,如果你需要,你可以直接用SQL查询:

// src /存储库/ productRepository.php/ /……班级ProductRepository.扩展serviceentityRepository.公共函数findallgreaterthanprice.int$!数组康涅狄格州美元这个美元->getEntityManager()->getConnection();$ SQL.SELECT * FROM product p哪里p.price>:价格按P.Price ASC订购支撑美元康涅狄格州美元->准备$ SQL.);支撑美元->执行(['价格'=>$!]);//返回数组的数组(即一个原始数据集)返回支撑美元->fetchAllAssociative();

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

配置

看到原则配置参考

关系和联系

Doctrine提供了您需要管理数据库关系(也称为关联)的所有功能,包括ManyToOne, onetoomany, OneToOne和manymany关系。

信息,请参阅如何与教义协会/关系合作

数据库测试

阅读关于测试与数据库交互的代码

教义扩展(时间戳,可翻译等)

教义社区已经创建了欧宝下载链接一些扩展来实现诸如“创建实体时自动设置创建物属性的值”.阅读更多关于可用原则扩展并使用StofDoctrineExtensionsBundle将它们集成在您的申请中。

这项工作包括代码样本,是在a下获得的许可创作共用BY-SA 3.0许可证。