利用原则表继承
雨果·哈蒙
在symfoob娱乐下载ny 1.3 Doctrine已经正式成为默认的ORM库,而Propel的开发在过去几个月已经放缓了。由于symfony社区成员的努力,Propel项目仍然得到支持并继续得到改进。欧宝体育平台怎么样ob娱乐下载
Doctrine 1.2项目成为新的默认symfony ORM库,因为它比Propel更容易使用ob娱乐下载,也因为它捆绑了许多很棒的特性,包括行为、简单的DQL查询、迁移和表继承。
本章描述了什么是表继承,以及它现在是如何在symfony 1.3中完全集成的。ob娱乐下载通过一个真实的例子,本章将说明如何利用Doctrine表继承使代码更加灵活和更好地组织起来。
教义表继承
虽然许多开发人员并不真正了解和使用表继承,但表继承可能是Doctrine最有趣的特性之一。表继承允许开发人员创建相互继承的数据库表,其方式与面向对象编程语言中的类继承相同。表继承提供了在单个超级表中的两个或多个表之间共享数据的简单方法。查看下面的图表以更好地理解表继承原理。
Doctrine根据应用程序的需求(性能、原子性、简单性……)提供了三种不同的策略来管理表继承:简单的,列聚合而且混凝土表继承。所有这些策略都在理论的书,一些进一步的解释将有助于更好地理解每个选项以及它们在哪些情况下有用。
简单的表继承策略
简单表继承策略是最简单的,因为它将所有列(包括子表列)存储在超级父表中。如果模型模式看起来像下面的YAML代码,Doctrine将生成一个表人
,其中包括教授
而且学生
表的列。
Person: columns: first_name: type: string(50) notnull: true last_name: type: string(50) notnull: true教授:继承:type: simple extends: Person columns: specialty: type: string(50) notnull: true学生:继承:type: simple extends: Person columns:毕业:type: string(20) notnull: true晋升:type: integer(4) notnull: true
使用简单的继承策略,额外的列专业
,毕业
而且促销活动
的顶层自动注册人
模型,即使Doctrine为两者生成一个模型类学生
而且教授
表。
作为超级父表,这种策略有一个重要的缺点人
不提供任何列来标识每个记录的类型。换句话说,没有办法只检索教授
或学生
对象。下面的Doctrine语句返回Doctrine_Collection
在所有表记录中(学生
而且教授
记录)。
美元的教授= Doctrine_Core::可以获得的(“教授”)->findAll();
简单的表继承策略在实际示例中并不是很有用,因为通常需要选择特定类型的对象。因此,本章不再进一步使用它。
列聚合表继承策略
列聚合表继承策略与简单继承策略相似,不同之处在于它包含类型
列来标识不同的记录类型。因此,当一个记录被持久化到数据库时,一个类型值被添加到它,以存储它所属的类。
Person: columns: first_name: type: string(50) nottnull: true last_name: type: string(50) nottnull: true教授:inheritance: type: column_aggregation extends: Person keyField: type keyValue: 1 columns: specialty: type: string(50) nottnull: true学生:inheritance: type: column_aggregation extends: Person keyField: type keyValue: 2 columns: graduate: type: string(20) nottnull: true promotion: type: integer(4) nottnull: true
在上面的YAML模式中,继承类型已更改为column_aggregation
并且添加了两个新属性。第一个属性,keyField
,指定将创建用于存储每个记录的类型信息的列。的keyField
字符串列有名字吗类型
,如果没有,则为默认列名keyField
都是确定的。属性的每个记录的类型值教授
或学生
类。
列聚合策略是表继承的好方法,因为它只创建一个表(人
)包含所有已定义的字段加上类型
字段。因此,不需要创建多个表并使用SQL查询将它们连接起来。下面是一些如何查询表以及将返回哪种类型结果的示例:
//返回教授对象的Doctrine_Collection美元的教授= Doctrine_Core::可以获得的(“教授”)->findAll();//返回Student对象的Doctrine_Collection美元的学生= Doctrine_Core::可以获得的(“学生”)->findAll();//返回一个教授对象美元教授= Doctrine_Core::可以获得的(“教授”)->findOneBySpeciality(“物理”);//返回一个Student对象美元的学生= Doctrine_Core::可以获得的(“学生”)->找到(42);//返回一个Student对象美元的学生= Doctrine_Core::可以获得的(“人”)->findOneByIdAndType(数组(42,2));
从子类执行数据检索时(教授
,学生
), Doctrine将自动附加SQL . SQL在哪里
子句上的查询类型
列的相应值。
但是,在某些情况下使用列聚合策略存在一些缺点。首先,列聚合防止每个子表的字段被设置为要求
.取决于有多少个字段人
表中可能包含多个空值的记录。
第二个缺点与子表和字段的数量有关。如果模式声明了许多子表,而子表又声明了许多字段,那么最终的超级表将由非常多的列组成。因此,该表可能更难维护。
具体表继承策略
具体的表继承策略是列聚合策略的优点、性能和可维护性之间的一个很好的折衷。实际上,这种策略为每个包含所有列的子类创建了独立的表:包括共享列和模型的独立列。
Person: columns: first_name: type: string(50) notnull: true last_name: type: string(50) notnull: true教授:继承:type: concrete extends: Person columns: specialty: type: string(50) notnull: true学生:继承:type: concrete extends: Person columns:毕业:type: string(20) notnull: true晋升:type: integer(4) notnull: true
对于前面的模式,生成的教授
表将包含以下一组字段:id
,first_name
,last_name
而且专业
.
与以前的策略相比,这种方法有几个优点。首先,所有表都是隔离的,并且彼此独立。此外,没有更多的空白字段和额外的类型
列不包括在内。结果是,每张桌子都更轻,并且与其他桌子隔离开来。
请注意
共享字段在子表中重复的事实对于性能和可伸缩性是一个好处,因为Doctrine不需要在超级表上进行自动SQL连接来检索属于子表记录的共享数据。
具体表继承策略的唯一两个缺点是共享字段复制(尽管复制通常是性能的关键)和生成的超级表总是空的事实。的确,学说产生了人
表,但它不会被任何查询填充或引用。不会对该表执行任何查询,因为所有内容都存储在子表中。
我们只是花时间介绍了Doctrine表继承的三种策略,但我们还没有在symfony的真实示例中尝试它们。ob娱乐下载本章的下一部分将解释如何利用symfony 1.3中的Doctrine表继承,特别是在模型和表单框架中。ob娱乐下载
ob娱乐下载Symfony表继承的集成
在symfonob娱乐下载y 1.3之前,框架不完全支持Doctrine表继承,因为表单和过滤器类不能正确地从基类继承。因此,需要使用表继承的开发人员被迫调整表单和过滤器,并被迫重写许多方法来检索继承行为。
由于社区的反馈,sy欧宝体育平台怎么样mfony核心团队已经改进了表ob娱乐下载单和过滤器,以便在symfony 1.3中轻松且全面地支持Doctrine表继承。
本章的剩余部分将解释如何使用Doctrine的表继承,以及如何在包括模型、表单、过滤器和管理生成器在内的几种情况下利用它。真实的案例研究示例将帮助我们更好地理解继承如何与symfony一起工作,以便您可以轻松地使用它来满足自己的需求。ob娱乐下载
介绍真实世界案例研究
在本章中,将介绍几个真实世界的案例研究,以揭示Doctrine表继承方法在以下几个层次上的许多优点模型
,形式
,过滤器
和管理发电机
.
第一个示例来自Sensio为一家著名的法国公司开发的应用程序。它展示了Doctrine表继承是如何管理十几个相同的引用数据集以共享方法和属性并避免代码重复的良好解决方案。
第二个示例通过创建一个简单的模型来管理数字文件,展示了如何利用表单的具体表继承策略。
最后,第三个示例将演示如何利用Admin Generator的表继承,以及如何使其更加灵活。
模型层的表继承
与面向对象编程的概念类似,表继承鼓励数据共享。因此,它允许在处理生成的模型时共享属性和方法。原则表继承是共享和覆盖可在继承对象上调用的操作的好方法。让我们用一个真实的例子来解释这个概念。
这个问题
许多web应用程序需要“参考”数据才能运行。引用通常是由一个包含至少两个字段的简单表表示的一小组数据。id
而且标签
).然而,在某些情况下,引用包含额外的数据,如is_active
或is_default
国旗。这就是最近在Sensio的一个客户应用程序的情况。
客户希望管理大量数据,这些数据驱动了应用程序的主要表单和视图。所有这些参考表都是围绕着相同的基本模型建立的:id
,标签
,位置
而且is_default
.的位置
字段帮助排名记录多亏ajax拖放功能。的is_default
field表示一个标志,表示当一个记录提供一个HTML选择下拉框时,它是否应该默认设置为“选定”。
解决方案
管理两个以上相等的表是使用表继承解决的最佳问题之一。在上面的问题中,选择具体的表继承来满足需求,并在单个类中共享每个对象的方法。让我们看一下下面的简化模式,它说明了这个问题。
sfReferential: columns: id: type: integer(2) notnull: true label: type: string(45) notnull: true position: type: integer(2) notnull: true is_default: type: boolean notnull: true default: false sfReferentialContractType:继承:type: concrete extends: sfReferentialProductType:继承:type: concrete extends: sfReferential
具体表继承在这里工作得很好,因为它提供了单独和隔离的表,并且因为位置
字段必须对共享相同类型的记录进行管理。
建立模型,看看会发生什么。Doctrine和symfob娱乐下载ony生成了3个SQL表和6个模型类lib /模型/教义
目录:
sfReferential
:管理sf_referential
记录,sfReferentialTable
:管理sf_referential
表格sfReferentialContractType
:管理sf_referential_contract_type
记录。sfReferentialContractTypeTable
:管理sf_referential_contract_type
表格sfReferentialProductType
:管理sf_referential_product_type
记录。sfReferentialProductTypeTable
:管理sf_referential_product_type
表格
类的两个基类都可以查看所生成的继承sfReferentialContractType
而且sfReferentialProductType
模型类继承自sfReferential
类。因此,所有受保护的和公共的方法(包括属性)都放在sfReferential
类将在两个子类之间共享,并且可以在必要时重写。
这正是预期的目标。的sfReferential
类现在可以包含管理所有引用数据的方法,例如:
/ / lib /模型/理论/ sfReferential.class.php类sfReferential扩展BasesfReferential{公共函数促进(){//在列表中向上移动记录}公共函数降级(){//向下移动列表中的记录}公共函数moveToFirstPosition(){//移动记录到第一个位置}公共函数moveToLastPosition(){//将记录移动到最后一个位置}公共函数moveToPosition(美元的地位){//将记录移动到给定位置}公共函数makeDefault(forceSave美元=真正的,康涅狄格州美元=零){这个美元->setIsDefault(真正的);如果(forceSave美元){这个美元->保存(康涅狄格州美元);}}}
由于Doctrine具体表继承,所有代码都在同一个地方共享。代码变得更容易调试、维护、改进和单元测试。
这是处理表继承时的第一个真正优势。此外,由于这种方法,模型对象可以用于集中操作代码,如下所示。的sfBaseReferentialActions
是由管理引用模型的每个操作类继承的特殊操作类。
/ / lib /动作/ sfBaseReferentialActions.class.php类sfBaseReferentialActions扩展sfActions{/** * Ajax操作,保存用户在列表视图中使用拖放操作后的新位置。* *此操作的链接得益于~sfDoctrineRoute~,它*简化了单个引用对象的检索。* * @param sfWebRequest $request */公共函数executeMoveToPosition(sfWebRequest美元的请求){这个美元->forward404Unless(美元的请求->isXmlHttpRequest());参照美元=这个美元->getRoute()->getObject();参照美元->moveToPosition(美元的请求->getParameter(“位置”,1));返回sfView::没有一个;}}
如果模式不使用表继承,会发生什么?需要在每个引用子类中复制代码。这种方法不是DRY(不要重复自己),特别是对于一个有十几个参考表的应用程序。
表单层的表继承
让我们继续学习Doctrine表继承的优点。上一节演示了该特性对于在几个继承模型之间共享方法和属性非常有用。现在让我们看看它在处理symfony生成的表单时的行为。ob娱乐下载
案例模型
下面的YAML模式描述了一个管理数字文档的模型。对象中存储通用信息文件
表和子表中的具体数据类似视频
而且PDF
.
文件:columns: filename: type: string(50) notnull: true mime_type: type: string(50) notnull: true description: type: clob notnull: true size: type: integer(8) notnull: true default: 0视频:继承:type: concrete extends:文件列:format: type: string(30) notnull: true duration: type: integer(8) notnull: true default: 0 encoding: type: string(50) PDF: tableName: PDF继承:type: concrete extends:文件列:pages: type: integer(8) notnull: true default: 0 paper_size: type: type:String (30) orientation: type: enum default: portrait values: [portrait, landscape] is_encrypted: type: Boolean default: false notull: true
这两个PDF
而且视频
表共享相同的数据文件
表,其中包含有关数字文件的全局信息。的视频
模型封装与视频对象相关的数据,例如格式
(4/ 3,16 /9…)或持续时间
,而PDF
模型包含的个数页面
或者文件的取向
.让我们构建这个模型并生成相应的表单。
$ PHP ob娱乐下载symfony原则:build -all
下一节将介绍如何利用表单类中的表继承setupInheritance ()
方法。
发现setupinheritage()方法
不出所料,Doctrine在中生成了六个形式类lib /形式/学说
而且lib /形式/理论/基地
目录:
BaseFileForm
BaseVideoForm
BasePDFForm
FileForm
VideoForm
PDFForm
让我们打开三个基地
形成类来发现一些新的东西设置()
方法。一个新的setupInheritance ()
方法已为symfony 1.3添加。ob娱乐下载该方法默认为空。
要注意的最重要的一点是,表单继承保留为BaseVideoForm
而且BasePDFForm
两者都扩展了FileForm
而且BaseFileForm
类。因此,每个都继承自文件
类,并且可以共享相同的基方法。
属性的setupInheritance ()
方法,并配置FileForm
类,以便可以更有效地在任一子表单中使用它。
/ / lib /形式/理论/ FileForm.class.php类FileForm扩展BaseFileForm{受保护的函数setupInheritance(){父::setupInheritance();这个美元->useFields(数组(“文件名”,“描述”));这个美元->widgetSchema[“文件名”]=新sfWidgetFormInputFile();这个美元->validatorSchema[“文件名”]=新sfValidatorFile(数组(“路径”= > sfConfig::得到(“sf_upload_dir”)));}}
的setupInheritance ()
方法调用该方法VideoForm
而且PDFForm
子类,删除除文件名
而且描述
.的文件名
字段的小部件已转换为文件小部件,其对应的验证器已更改为sfValidatorFile
验证器。这样,用户将能够上传文件并将其保存到服务器。
设置当前文件的Mime类型和大小
所有表单现在都已经准备好并进行了定制。然而,在能够使用它们之前,还有一件事情需要配置。随着mime_type
而且大小
字段已从FileForm
对象时,它们必须以编程方式设置。最好的地方是在一个新的generateFilenameFilename ()
方法中的文件
类。
/ / lib /模型/理论/ File.class.php类文件扩展BaseFile{/** *生成当前文件对象的文件名。* * @param sfValidatedFile $file * @返回字符串*/公共函数generateFilenameFilename(sfValidatedFile美元的文件){这个美元->setMimeType(美元的文件->方法());这个美元->setSize(美元的文件->getSize());返回美元的文件->generateFilename();}}
这个新方法旨在为存储在文件系统上的文件生成一个自定义文件名。虽然generateFilenameFilename ()
方法返回默认自动生成的文件名,则它还设置mime_type
而且大小
房产的飞速发展多亏了sfValidatedFile
对象作为其第一个参数传递。
由于sob娱乐下载ymfony 1.3完全支持Doctrine表继承,表单现在能够保存对象及其继承的值。本地继承支持允许使用很少的定制代码块来生成功能强大的表单。
由于类继承,可以广泛而容易地改进上面的示例。例如,两者VideoForm
而且PDFForm
类可以重写文件名
验证器到更特定的自定义验证器,例如sfValidatorVideo
或sfValidatorPDF
.
过滤器层的表继承
因为过滤器也是表单,所以它们也继承了父表单过滤器的方法和属性。因此,VideoFormFilter
而且PDFFormFilter
对象扩展FileFormFilter
类,并且可以通过使用setupInheritance ()
方法。
以同样的方式,两者都有VideoFormFilter
而且PDFFormFilter
可以共享相同的自定义方法FileFormFilter
类。
管理生成器层的表继承
现在是时候了解如何利用Doctrine表继承以及Admin Generator的一个新特性:动作基类定义。Admin Generator是symfony自1.0版本以来改进最多的特性之一。ob娱乐下载
在2008年11月,symfony推ob娱乐下载出了新的Admin Generator系统,该系统与版本1.2捆绑在一起。这个工具有很多开箱即用的功能,比如基本的CRUD操作,列表过滤和分页,批量删除等等…Admin Generator是一个功能强大的工具,可以为任何开发人员简化和加速后端生成和定制。
实例介绍
本章最后一部分的目的是说明如何利用Doctrine表继承和Admin Generator的结合。为了实现这一点,将构造一个简单的后端区域来管理两个表,这两个表都包含可以排序/优先级的数据。
由于sob娱乐下载ymfony的咒语是不要每次都重新发明轮子,Doctrine模型将使用csDoctrineActAsSortablePlugin来提供所有需要的API来对对象进行排序。的csDoctrineActAsSortablePlugin
插件是由symfony生态系统中最活跃的公司之一CentreSource开发和维护的。ob娱乐下载
数据模型非常简单。有三个模型类,sfItem
,sfTodoItem
而且sfShoppingItem
,帮助管理待办事项清单和购物清单。两个列表中的每个项目都是可排序的,以允许在列表中对项目进行优先级排序。
sfItem: actAs: [Timestampable] columns: name: type: string(50) nottnull: true sfTodoItem: actAs: [Sortable] inheritance: type: concrete extends: sfItem columns: priority: type: string(20) nottnull: true default: minor assigned_to: type: string(30) nottnull: true default: me sfShoppingItem: actAs: [Sortable] inheritance: type: concrete extends: sfItem columns: quantity: type: integer(3) nottnull: true default: 1
上面的模式描述了划分为三个模型类的数据模型。两个幼儿班(sfTodoItem
,sfShoppingItem
)都使用可分类的
而且Timestampable
行为。的可分类的
属性提供的csDoctrineActAsSortablePlugin
插件并添加一个整数位置
列到每个表。这两个类都扩展了sfItem
基类。此类包含id
而且的名字
列。
让我们添加一些数据fixture,这样我们就可以在后端中使用一些测试数据。数据fixture通常位于数据/ fixtures.yml
symfony项目文件。ob娱乐下载
sfTodoItem: sfTodoItem_1:名称:“写一个新的symfony书”优先ob娱乐下载级:“中”assigned_to:“Fabien Potencier”sfTodoItem_2:名称:“发布主义2.0”优先级:“minor”assigned_to:“Jonathan Wage”sfTodoItem_3:名称:“发布symfony 1.4”优先级:“major”assigned_to:“Kris Wallsmith”sfTodoItem_4:名称:“Document Lime 2核心API”优先级:“medium”assigned_to:“Bernard Schussek”sfShoppingItem: sfShoppingItem_1:名称:“苹果MacBook Pro 15.4英寸”数量:3 sfShoppingItem_2:名称:“外部硬盘驱动器320gb”数量:5 sfShoppingItem_3:名称:“USB键盘”数量:2 sfShoppingItem_4:名称:“激光打印机”数量:1
一旦csDoctrineActAsSortablePlugin
插件已经安装并且数据模型已经准备就绪,新的插件需要在ProjectConfiguration
类位于配置/ ProjectConfiguration.class.php
:
类ProjectConfiguration扩展sfProjectConfiguration{公共函数设置(){这个美元->enablePlugins(数组(“sfDoctrinePlugin”,“csDoctrineActAsSortablePlugin”));}}
接下来,可以生成数据库、模型、表单和过滤器,并将fixture加载到数据库中以提供新创建的表。这可以立即完成,多亏了原则:建立
任务:
$ PHP ob娱乐下载symfony原则:build -all -no-confirmation
必须清除ob娱乐下载symfony缓存才能完成该过程,并且插件的资产必须链接到网络
目录:
清除$ PHob娱乐下载P symfony插件:publish-assets
下面一节将解释如何使用Admin Generator工具构建后端模块,以及如何从新的操作基类特性中受益。
设置后端
本节描述设置新后端应用程序所需的步骤,其中包含两个生成的模块,用于管理购物和待办事项列表。因此,要做的第一件事是生成后端
应用程序来容纳即将到来的模块:
symfonob娱乐下载y生成:应用程序后端
尽管Admin Generator是一个很棒的工具,但在symfony 1.3之前,开发人员被迫在生成的模块之间复制ob娱乐下载公共代码。然而,现在原则:generate-admin
任务引入了一个新的——actions-base-class
选项,允许开发人员定义模块的基本操作类。
由于这两个模块非常相似,它们肯定需要共享一些通用的操作代码。类中的超操作类中可以定位此代码lib /行动
目录如下所示的代码:
/ / lib /动作/ sfSortableModuleActions.class.php类sfSortableModuleActions扩展sfActions{}
一旦新的sfSortableModuleActions
类被创建并且缓存已经被清除,两个模块可以在后端应用程序中生成:
$ php ob娱乐下载symfony原则:生成-admin——module=shopping——actions-base-class=sfSortableModuleActions后端sfShoppingItem
$ php ob娱乐下载symfony原则:generate-admin——module=todo——actions-base-class=sfSortableModuleActions后端sfTodoItem
Admin Generator在两个单独的目录中生成模块。第一个目录当然是,应用程序/后端模块
.生成的大部分模块文件位于缓存/后端/ dev /模块
目录中。每次缓存清除或模块配置更改时,都会重新生成位于此位置的文件。
请注意
浏览缓存的文件是了解symfony和Admin Generator在底层如何协同工作的好方法。ob娱乐下载因此,新的sfSortableModuleActions
子类可以在缓存/后端/ dev /模块/ autoShopping /行动/ actions.class.php
而且缓存/后端/ dev /模块/ autoTodo /行动/ actions.class.php
.默认情况下,symfonob娱乐下载y将生成这些要直接继承的类sfActions
.
这两个后端模块已经可以使用和定制了。然而,探索自动生成模块的配置并不是本章的目标。有关于此主题的重要文档,欧宝官网下载app包括ob娱乐下载symfony参考书.
改变物品的位置
上一节描述了如何设置两个功能齐全的后端模块,它们都继承自同一个动作类。下一个目标是创建一个共享操作,允许开发人员对列表中的对象进行排序。这很容易,因为安装的插件提供了一个完整的API来处理对象的调用。
第一步是创建两条能够在列表中向上或向下移动记录的新路由。当管理生成器使用sfDoctrineRouteCollection
方法,可以轻松地声明新路由并将其附加到集合配置/ generator.yml
在两个模块中:
#应用/后端/模块/购物/ config /发电机。yml generator: class: sfDoctrineGenerator param: model_class: sfShoppingItem主题:admin non_verbose_templates: true with_show: false singular: ~ plural: ~ route_prefix: sf_shopping_item with_doctrine_route: true actions_base_class: sfSortableModuleActions config: actions: ~ fields: ~ list: max_per_page: 100 sort: [position, asc] display: [position, name, quantity] object_actions: moveUp: {label: "move up", action: "moveUp"} moveDown: {label: "move down", action: "moveDown"} _edit:~ _delete: ~ filter: ~ form: ~ edit: ~ new: ~ .
的更改需要重复待办事项
模块:
#应用/后端/模块/备忘录/ config /发电机。yml generator: class: sfDoctrineGenerator param: model_class: sfTodoItem主题:admin non_verbose_templates: true with_show: false singular: ~ plural: ~ route_prefix: sf_todo_item with_doctrine_route: true actions_base_class: sfSortableModuleActions config: actions: ~ fields: ~ list: max_per_page: 100 sort: [position, asc] display: [position, name, priority, assigned_to] object_actions: moveUp: {label: "move up", action: "moveUp"} moveDown: {label: "move down", action: "moveDown"} _edit:~ _delete: ~ filter: ~ form: ~ edit: ~ new: ~ .
这两个YAML文件描述了两者的配置购物
而且待办事项
模块。每一个都是定制的,以满足最终用户的需求。首先,列表视图在位置
列。提升
排序。接下来,每页的最大条目数已增加到100,以避免分页。
最后,显示的列数已减少到位置
,的名字
,优先级
,assigned_to
而且数量
列。此外,每个模块都有两个新动作:moveUp
而且moveDown
.最终的渲染应该像下面的截图:
这两个新动作已经声明了,但是现在什么都不做。每个都必须在共享动作类中创建,sfSortableModuleActions
如下所述。的csDoctrineActAsSortablePlugin
Plugin为每个模型类提供了两个额外有用的方法:促进()
而且降级()
.每一个都是用来建立moveUp
而且moveDown
行动。
/ / lib /动作/ sfSortableModuleActions.class.php类sfSortableModuleActions扩展sfActions{/** *在列表中向上移动一个项。* * @param sfWebRequest $request */公共函数executeMoveUp(sfWebRequest美元的请求){这个美元->项=这个美元->getRoute()->getObject();这个美元->项->促进();这个美元->重定向(这个美元->getModuleName());}/** *在列表中向下移动一个项目。* * @param sfWebRequest $request */公共函数executeMoveDown(sfWebRequest美元的请求){这个美元->项=这个美元->getRoute()->getObject();这个美元->项->降级();这个美元->重定向(这个美元->getModuleName());}}
多亏了这两个共享的操作,待办事项列表和购物列表都是可排序的。此外,它们易于维护和使用功能测试进行测试。您可以通过覆盖对象的动作模板来删除第一个模块,从而改进这两个模块的观感向上移动
林克和最后一个向下移动
链接。
特殊礼物:改善用户体验
在结束之前,让我们完善这两个列表以改善用户体验。每个人都同意,通过单击链接来向上(或向下)移动一个记录对最终用户来说并不是真正直观的。更好的方法肯定是包含JavaScript ajax行为。在这种情况下,所有HTML表行都是可拖放的表格拖放
jQuery插件。每当用户移动HTML表中的一行时,就会执行ajax调用。
首先抓取并安装jQuery框架web / js
目录,然后对表格拖放
插件,其源代码托管在谷歌代码存储库。
为了工作,每个模块的列表视图必须包含一个JavaScript片段,并且两个表都需要一个id
属性。由于所有管理生成器模板和部分都可以重写,因此_list.php
文件(默认位于缓存中)应该复制到两个模块。
但是等等,复制_list.php
在模板/
每个模块的目录不是真正的DRY。只要复制缓存/后端/ dev /模块/ autoShopping /模板/ _list.php
文件到应用程序/后端/模板/
目录并重命名_table.php
.将其当前内容替换为以下代码:
< div类=“sf_admin_list”><?php如果(!美元寻呼机->getNbResults()):? >< p > < ?php回声__(“没有结果”,数组(),“sf_admin”)? > < / p ><?php其他的:? ><表格单元格间距=“0”id =“sf_item_table”> <头>“sf_admin_list_batch_actions”输入id = > <“sf_admin_list_batch_checkbox”类型=“复选框”onclick =“checkAll();“/ > < / th ><?phpinclude_partial(sf_request美元->getParameter(“模块”).' / list_th_tabular ',数组(“排序”= >美元的排序))? >< th id =“sf_admin_list_th_actions”><?php回声__(“行动”,数组(),“sf_admin”)? > <?phpforeach(美元寻呼机->getResults()作为我美元= >美元的项目):? ><?php奇怪的美元=在你(++我美元,2)?“奇怪”:“甚至”? >< tr类=“sf_admin_row < ?php回声奇怪的美元? >"><?phpinclude_partial(sf_request美元->getParameter(“模块”).' / list_td_batch_actions ',数组(“sf_”.sf_request美元->getParameter(“模块”).“_item”= >美元的项目,“助手”= >美元的助手))? ><?phpinclude_partial(sf_request美元->getParameter(“模块”).' / list_td_tabular ',数组(“sf_”.sf_request美元->getParameter(“模块”).“_item”= >美元的项目))? ><?phpinclude_partial(sf_request美元->getParameter(“模块”).' / list_td_actions ',数组(“sf_”.sf_request美元->getParameter(“模块”).“_item”= >美元的项目,“助手”= >美元的助手))? >< / tr ><?phpendforeach;? >tbody > < / > < /表<?phpendif;? > <脚本类型=“text / javascript”>/ * < ![CDATA[ */函数checkAll(){varboxes = document.getElementsByTagName(“输入”);为(var指数=0;索引< boxes.length;指数+ +){盒子=盒子[指数];如果(盒子。类型==“复选框”& &盒子。类Name ==“sf_admin_batch_checkbox”)盒子。checked = document.getElementById(“sf_admin_list_batch_checkbox”)支票}返回真正的;}/*]]> */> < /脚本 “< ?php回声$colspan ?>"><?php如果(美元寻呼机->haveToPaginate()):? ><?phpinclude_partial(sf_request美元->getParameter(“模块”)./分页的,数组(“寻呼机”= >美元寻呼机))? ><?phpendif;? ><?php回声format_number_choice('[0] no result|[1] 1 result|(1,+Inf] %1% results',数组(“% 1%”= >美元寻呼机->getNbResults()),美元寻呼机->getNbResults(),“sf_admin”)? ><?php如果(美元寻呼机->haveToPaginate()):? ><?php回声__(”(页面% % % % / % % nb_pages % %)”,数组(% % % %页的= >美元寻呼机->getPage(),“% % nb_pages % %”= >美元寻呼机->getLastPage()),“sf_admin”)? ><?phpendif;? > 最后,创建一个
_list.php
文件在每个模块的模板
目录,并在每个目录中放置以下代码:/ /应用程序/后端/模块/购物/模板/ _list.php<?phpinclude_partial(“全球/表”,数组(“寻呼机”= >美元寻呼机,“助手”= >美元的助手,“排序”= >美元的排序,“colspan”= >5))? >// apps/backend/modules/shopping/templates/_list.php 美元寻呼机,“助手”= >美元的助手, 'sort' => $sort, 'colspan' => 8 )) ?>要更改一行的位置,两个模块都需要实现一个处理即将到来的ajax请求的新操作。如前所述,新的共享
executeMove ()
动作将放在sfSortableModuleActions
动作类:/ / lib /动作/ sfSortableModuleActions.class.php类sfSortableModuleActions扩展sfActions{/** *执行Ajax请求,将项目移动到新位置。* * @param sfWebRequest $request */公共函数executeMove(sfWebRequest美元的请求){这个美元->forward404Unless(美元的请求->isXmlHttpRequest());这个美元->forward404Unless(美元的项目= Doctrine_Core::可以获得的(这个美元->配置->getModel())->找到(美元的请求->getParameter(“id”)));美元的项目->moveToPosition((int)美元的请求->getParameter(“排名”,1));返回sfView::没有一个;}}的
executeMove ()
行动需要一个getModel ()
方法。实现这个新方法todoGeneratorConfiguration
而且shoppingGeneratorConfiguration
类如下所示:/ /应用程序/后端/模块/购物/ lib / shoppingGeneratorConfiguration.class.php类shoppingGeneratorConfiguration扩展BaseShoppingGeneratorConfiguration{公共函数getModel(){返回“sfShoppingItem”;}}// apps/backend/modules/todo/lib/todoGeneratorConfiguration.class.php类todoGeneratorConfiguration扩展BaseTodoGeneratorConfiguration{公共函数getModel(){返回'sfTodoItem';}}还有最后一个手术要做。目前,tables行是不可拖拽的,当移动的行被释放时,不会执行ajax调用。为了实现这一点,两个模块都需要一个特定的路由来访问它们对应的模块
移动
行动。因此,应用程序/后端/ config / routing.yml
文件需要新建如下两条路由,如下图所示:<?phpforeach(数组(“购物”,“待办事项”)作为美元的模块):? ><?php回声美元的模块? > _move:类: sfRequestRoute url: /<?php回声美元的模块? >/move参数:“< ?php回声美元的模块? >"动作:移动需求:sf_method:[得到]<?phpendforeach? >为了避免代码重复,这两条路由在
foreach
语句,并基于模块名在视图中轻松检索它。最后,应用程序/后端/模板/ _table.php
必须实现JavaScript片段,以初始化拖放行为和相应的ajax请求:<脚本类型=“text / javascript”charset =“utf - 8”>美元()时(函数(){$(“# sf_item_table”).tableDnD({onDrop:函数(表,行){varrows = table.tBodies[0].rows;//获取移动项的idvarmovedId = $(行);(“td输入:复选框”).val();//计算新行位置varpos=1;为(var我=0;我< rows.length;我+ +){var单元格=行[我]childnodes;//执行新位置的ajax请求如果(movedId == $(细胞[1]);(输入:复选框的).val()){. ajax美元({url:“< ?php回声url_for('@'. $sf_request->getParameter('module').'_move') ?>?id="+ movedId +"等级= "+pos类型:“获得”});打破;}pos+ +;}},});});> < /脚本HTML表现在功能齐全。行是可拖放的,由于ajax调用,行的新位置会自动保存。通过少量的代码块,后端的可用性得到了极大的提高,从而为最终用户提供了更好的体验。Admin Generator非常灵活,可以进行扩展和定制,并且可以完美地与Doctrine的表继承一起工作。
请随意通过删除两个过时的模块来改进这两个模块
moveUp
而且moveDown
操作,并添加符合您需求的任何其他自定义。最终的想法
本章描述了Doctrine表继承是一个强大的特性,它可以帮助开发人员更快地编写代码并改进代码组织。这个Doctrine功能在symfony的几个级别上完全集成。ob娱乐下载鼓励开发人员利用它来提高效率和促进代码组织。
本作品在创作共用署名相似共享3.0未移植许可许可下获得许可。
搜索Algolia