利用表继承原则
Hugo亨茂
1.3 sy欧宝娱乐app下载地址mfony的教义已正式成为默认的ORM库而推动的发展已经过去几个月放缓。推动项目仍然支持和继续提高谢谢symfony社区成员的努力。欧宝下载链接欧宝娱乐app下载地址
原则1.2项目成为新的默认symfony ORM库不仅因为它比推动更容易使用,因为它包很多功能,欧宝娱乐app下载地址包括行为,容易DQL查询、迁移和表继承。
这一章描述了表继承是什么以及如何在symfony 1.3现在完全集成。欧宝娱乐app下载地址由于一个真实世界的例子,本章将说明如何利用教义表继承使代码更加灵活和更有条理。
表继承原则
虽然不是真正的已知和所使用的许多开发人员,表继承可能是教义的最有趣的特性之一。表继承允许开发人员创建数据库表以同样的方式互相继承的类继承在面向对象的编程语言。表继承提供了一种简单的方法来共享数据在两个或多个表在一个超级表。看看下面的图,以便更好地理解表继承原则。
学说提供了三种不同的策略来管理表遗产取决于应用程序的需要(性能、原子性、简单…):简单的,列聚合和混凝土表继承。而所有这些策略中所描述的理论的书,一些进一步的解释将有助于更好地理解每个选项在哪些情况下,他们是有用的。
简单的表继承的策略
简单的表继承的策略是最简单的,因为它存储所有列,包括儿童表列,在超级父表。如果模型模式看起来像下面的YAML代码,学说将生成一个单一的表人
,其中包括了教授
和学生
表的列。
人:列:first_name:类型:字符串(50)notnull:真正的last_name:类型:字符串(50)notnull:真正的教授:继承:类型:简单的延伸:人列:专业:类型:字符串(50)notnull:真正的学生:继承:类型:简单的延伸:人列:毕业后:类型:字符串(20)notnull:真正的晋升:类型:整数(4)notnull:真的
简单的遗传策略,额外的列专业
,毕业
和促销活动
自动注册的顶级人
模型即使学说都生成一个模型类学生
和教授
表。
这一策略有一个重要的缺点是超级父表人
不提供任何列来确定每个记录类型。换句话说,没有办法只检索教授
或学生
对象。以下原则声明返回Doctrine_Collection
所有表的记录(学生
和教授
记录)。
美元的教授= Doctrine_Core::可以获得的(“教授”)- >findAll();
简单的表继承的策略并不是真正有用的真实世界的例子,因为通常需要选择和水合物特定类型的对象。因此,它不会在本章进一步使用。
列聚合表继承的策略
列聚合表继承策略类似于简单继承策略,它包括一个除外类型
列来识别不同的记录类型。因此,当一个记录保存到数据库,输入值被添加到它为了存储它所属的类。
人:列:first_name:类型:字符串(50)notnull:真正的last_name:类型:字符串(50)notnull:真正的教授:继承:类型:column_aggregation延伸:人keyField: keyValue类型:1列:专业:类型:字符串(50)notnull:真正的学生:继承:类型:column_aggregation延伸:人keyField: keyValue类型:2列:毕业后:类型:字符串(20)notnull:真正的晋升:类型:整数(4)notnull:真的
在上面的YAML模式,继承类型已经改变了column_aggregation
并添加了两个新的属性。第一个属性,keyField
指定的列,将创建为每个记录存储类型信息。的keyField
是一个字符串列命名类型
如果没有,这是默认的列名称keyField
都是确定的。第二个属性定义了属于价值为每一个记录类型教授
或学生
类。
列聚合表继承策略是一个很好的方法,因为它创建了一个表(人
包含所有定义字段加上)类型
字段。因此,没有必要让几个表和加入一个SQL查询。下面是一些例子如何查询表和哪种类型的结果将返回:
/ /返回一个Doctrine_Collection教授的对象美元的教授= Doctrine_Core::可以获得的(“教授”)- >findAll();/ /返回一个Doctrine_Collection学生对象美元的学生= Doctrine_Core::可以获得的(“学生”)- >findAll();/ /返回一个教授对象美元教授= Doctrine_Core::可以获得的(“教授”)- >findOneBySpeciality(“物理”);/ /返回一个对象美元的学生= Doctrine_Core::可以获得的(“学生”)- >找到(42);/ /返回一个对象美元的学生= Doctrine_Core::可以获得的(“人”)- >findOneByIdAndType(数组(42,2));
当从一个子类执行数据检索(教授
,学生
),原则将自动添加SQL在哪里
子句的查询类型
列对应的值。
然而,也有一些缺点在某些情况下使用列聚合策略。首先,列聚合可以防止每个子表的字段被设置为要求
。根据有多少领域,人
表可能包含记录与几个空值。
第二个缺点与子表和字段的数量。如果模式声明很多子表,进而宣布很多字段,最后超级表将包括大量的列。因此,表可能更难以维护。
具体表继承的策略
具体表继承的策略是一个很好的办法的优点列聚合策略,性能和可维护性。事实上,这一战略为每个子类创建独立的表包含所有列:共享列和模型的独立列。
人:列:first_name:类型:字符串(50)notnull:真正的last_name:类型:字符串(50)notnull:真正的教授:继承:类型:具体的扩展:人列:专业:类型:字符串(50)notnull:真正的学生:继承:类型:具体的扩展:人列:毕业后:类型:字符串(20)notnull:真正的晋升:类型:整数(4)notnull:真的
因此,对于之前的模式,生成的教授
表的字段将包含以下:id
,first_name
,last_name
和专业
。
这种方法有几个优点对以前的策略。第一个是,所有的表都是孤立和保持相互独立的。此外,没有其他空白字段和额外的类型
不包括列。其结果是,每个表是轻和孤立于其他表。
请注意
共享这一事实在子表字段重复获得性能和可伸缩性的教义不需要做一个自动SQL加入超级表检索共享数据属于子表记录。
只有两个缺点的具体表继承策略共享字段重复(尽管通常是重复的关键性能),生成的超级表永远是空的。事实上,教义产生了人
表虽然不会填充或引用的任何查询。不会,表上执行查询一切都存储在子类型。
我们只是花时间介绍三个原则表继承策略但我们没有试着用symfony在一个真实世界的例子。欧宝娱乐app下载地址本章以下部分解释了如何利用教义表继承在symfony 1.3中,特别是在模型和框架。欧宝娱乐app下载地址
欧宝娱乐app下载地址Symfony的集成表继承
在symfon欧宝娱乐app下载地址y 1.3之前,教义表继承并不完全支持的框架形式和过滤器类没有正确地从基类继承。因此,开发人员需要使用表继承被迫调整形式和过滤器和被迫覆盖大量的方法来检索继承行为。
由于社区的反馈,sy欧宝下载链接mfony核心团队提高了形式和过滤器欧宝娱乐app下载地址以轻松和完全支持原则表继承在symfony 1.3。
本章的其余部分将解释如何使用学说的继承和如何利用它在一些情况下包括模型、表格、过滤器和管理发电机。实际案例研究示例将帮助我们更好地了解继承使用symfony,这样你可以很容易地使用它自己的需要。欧宝娱乐app下载地址
引入真实世界的案例研究
在本章中,现实世界几个案例研究将暴露的很多优势原则表继承方法几个层面:模型
,形式
,过滤器
和管理发电机
。
第一个例子来自应用程序开发的Sensio赞助了一个众所周知的法国公司。它显示了教义表继承是一个好的解决方案来管理十几个相同的参照组数据为了分享方法和属性,避免代码重复。
第二个例子展示了如何利用混凝土表继承策略与形式通过创建一个简单的模型来管理数字文件。
最后,第三个例子将演示如何利用表继承管理发电机,以及如何使其更加灵活。
在模型层表继承
类似于面向对象编程的概念,表继承鼓励数据共享。因此,它允许共享属性和方法在处理生成模型。教义表继承是一个很好的方式来分享和覆盖操作可调用继承的对象。让我们解释这个概念,一个真实世界的例子。
这个问题
很多web应用程序都需要“引用”数据功能。一组引用通常是一个小的数据表示为一个简单的表包含至少两个字段(如。id
和标签
)。然而,在某些情况下,如引用包含额外的数据is_active
或is_default
国旗。这是最近在Sensio赞助与客户应用程序。
客户想要管理大量的数据,而开车的主要表单和视图的应用程序。所有这些参考表是建立在相同的基本模型:id
,标签
,位置
和is_default
。的位置
场有助于排名记录由于ajax拖放功能。的is_default
字段表示一个国旗,显示一个记录是否应该设置为“选择”时默认提要一个HTML选择下拉框。
解决方案
管理超过两个平等的表是一个最好的问题解决表继承。在上面的问题中,具体表继承选择以适应需求和分享每一个类对象的方法。让我们看一看下面的简化模式,这说明了问题。
sfReferential:列:id:类型:整数(2)notnull:真正的标签:类型:字符串(45)notnull:真正的位置:类型:整数(2)notnull:真正的is_default:类型:布尔notnull:真正的默认值:false sfReferentialContractType:继承:类型:具体的扩展:sfReferential sfReferentialProductType:继承:类型:具体的扩展:sfReferential
具体表继承工作完全是它提供了单独的和孤立的表,因为位置
字段必须为管理记录,共享相同的类型。
构建的模型,看看会发生什么。教义和symfony生成三欧宝娱乐app下载地址个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美元){这个美元- >保存(康涅狄格州美元);}}}
由于继承原则具体表,所有的代码在同一个地方共享。代码变得更容易调试,维护,改进和单元测试。
这是第一个真正的优势在处理表继承。此外,由于这种方法,模型对象可以用来集中行动代码如下所示。的sfBaseReferentialActions
是一种特殊的动作类继承了每个动作类管理参考模型。
/ / lib /动作/ sfBaseReferentialActions.class.php类sfBaseReferentialActions扩展sfActions{/ * * * Ajax行为,节省了用户的新职位由于*使用列表视图中拖拽。* *这一行动有关感谢的~ sfDoctrineRoute ~ *缓解单个引用对象检索。* / * * @param sfWebRequest美元请求公共函数executeMoveToPosition(sfWebRequest美元的请求){这个美元- >forward404Unless(美元的请求- >isXmlHttpRequest());参照美元=这个美元- >getRoute()- >getObject();参照美元- >moveToPosition(美元的请求- >getParameter(“位置”,1));返回sfView::没有一个;}}
会发生什么如果表模式没有使用继承?需要复制的代码在每个引用子类。这种方法不会干,(不要重复你自己)尤其是对应用程序和十几个参考表。
表继承在形式层
我们继续学说的导游表继承的优势。前一节展示了如何真正有用的这个特性分享几个继承模型之间的方法和属性。现在让我们看看它如何表现在处理symfony生成形式。欧宝娱乐app下载地址
这项研究的模型
下面的YAML模式描述了一个模型来管理数字文档。其目的是存储在通用信息文件
表和子表中的特定数据视频
和PDF
。
文件:列:文件名:类型:字符串(50)notnull:真正的mime_type:类型:字符串(50)notnull:真正的描述:类型:clob notnull:真正的大小:类型:整数(8)notnull:真正的默认值:0视频:继承:类型:具体的扩展:文件列:格式:类型:字符串(30)notnull:真正的持续时间:类型:整数(8)notnull:真正的默认值:0编码:类型:字符串(50)PDF格式:表名:PDF继承:类型:具体的扩展:文件列:页面:类型:整数(8)notnull:真正的默认值:0 paper_size:类型:字符串(30)取向:类型:枚举默认值:肖像价值观:[肖像、风景]is_encrypted:类型:布尔默认值:false notnull:真的
这两个PDF
和视频
表共享相同的文件
表,其中包含全球数字文件的信息。的视频
模型封装了数据相关的视频对象等格式
(4/3,16/9…)持续时间
,而PDF
模型包含的数量页面
或文档的取向
。让我们构建该模型并生成相应的形式。
php sy欧宝娱乐app下载地址mfony学说:美元构建——所有
下面的部分将介绍如何利用表继承的类由于新形式setupInheritance ()
方法。
发现setupInheritance()方法
正如所料,教义产生了六类的形式lib /形式/学说
和lib /形式/理论/基地
目录:
BaseFileForm
BaseVideoForm
BasePDFForm
FileForm
VideoForm
PDFForm
让我们打开三个基地
发现新事物的形式类设置()
方法。一个新的setupInheritance ()
1.3方法添加了symfony。欧宝娱乐app下载地址该方法默认是空的。
最重要的是要注意的是,继承形式保存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文件* @return字符串* /美元公共函数generateFilenameFilename(sfValidatedFile美元的文件){这个美元- >setMimeType(美元的文件- >方法());这个美元- >setSize(美元的文件- >getSize());返回美元的文件- >generateFilename();}}
这种新方法旨在生成一个自定义文件名的文件存储在文件系统中。虽然generateFilenameFilename ()
方法返回一个默认的自动生成的文件名,也设置了mime_type
和大小
由于动态属性sfValidatedFile
对象作为其第一个参数传递。
如表继欧宝娱乐app下载地址承symfony 1.3完全支持原则,形成现在能够保存一个对象及其继承的值。本机继承支持允许强大的和功能形式与很少的定制代码块。
上面的例子中可以广泛且容易改善由于类继承。例如,两个VideoForm
和PDFForm
类可以覆盖文件名
等一个更具体的定制验证器验证器sfValidatorVideo
或sfValidatorPDF
。
表继承在过滤层
因为过滤器是形式,他们也继承父窗体的方法和属性过滤器。因此,VideoFormFilter
和PDFFormFilter
对象扩展FileFormFilter
可以定制类和使用setupInheritance ()
方法。
同样的,VideoFormFilter
和PDFFormFilter
可以共享相同的自定义方法FileFormFilter
类。
表继承在管理发电机层
现在是时候去发现如何利用表继承原则以及管理发电机的一个新特性:行动的基类定义。管理发电机是一种最symfony自1.0版本的改进的特征。欧宝娱乐app下载地址
2008年11月,symfony引入欧宝娱乐app下载地址了新的管理发电机系统与1.2版本绑定。这个工具有很多的开箱即用的功能等基本的CRUD操作,过滤列表和分页、批量删除等等……管理发电机是一种强大的工具,简化和加速后台生成和定制任何开发人员。
实例介绍
本章的最后部分的目的是为了说明如何利用教义表继承加上管理发电机。为了实现这一点,一个简单的后台区域将建设管理两个表,都包含数据可以排序/优先。
sym欧宝娱乐app下载地址fony的口号是不要每次都重新发明轮子,将使用的理论模型csDoctrineActAsSortablePlugin提供所有所需的API类对象彼此之间。的csDoctrineActAsSortablePlugin
插件是由CentreSource开发和维护的,最活跃的公司之一symfony的生态系统。欧宝娱乐app下载地址
数据模型非常简单。有三个模型类,sfItem
,sfTodoItem
和sfShoppingItem
帮助管理一个todo列表和一个购物清单。每一项在列表可分类的列表内允许优先项目。
sfItem:找:[Timestampable]列:名称:类型:字符串(50)notnull:真正的sfTodoItem:找:(合适的)继承:类型:具体的扩展:sfItem列:优先级:类型:字符串(20)notnull:真正的违约:小assigned_to:类型:字符串(30)notnull:真正的违约:我sfShoppingItem:找:(合适的)继承:类型:具体的扩展:sfItem列:数量:类型:整数(3)notnull:真正的默认值:1
上述模式描述了数据模型分成了三个模型类。两个孩子类(sfTodoItem
,sfShoppingItem
)都使用可分类的
和Timestampable
行为。的可分类的
行为是提供的csDoctrineActAsSortablePlugin
插件和添加一个整数位置
每个表列。两类扩展sfItem
基类。这个类包含一个id
和的名字
列。
让我们添加一些数据装置,这样我们有一些测试数据后端内玩。数据设备,像往常一样,位于数据/ fixtures.yml
symfony项目的文件欧宝娱乐app下载地址。
sfTodoItem: sfTodoItem_1:名字:“写一个新的symfony书”优先欧宝娱乐app下载地址级:“媒介”assigned_to:“法比力量”sfTodoItem_2:名字:“发布原则2.0”优先级:“小”assigned_to:“乔纳森工资”sfTodoItem_3:名字:“释放symfony 1.4”优先级:“主要”assigned_to:“克丽丝Wallsmith”sfTodoItem_4:名字:“核心API文档石灰2”优先级:“媒介”assigned_to:“伯纳德Schussek”sfShoppingItem: sfShoppingItem_1:名字:“苹果MacBook Pro 15.4英寸”数量:3 sfShoppingItem_2:名字:“外部硬盘320 g”数量:5 sfShoppingItem_3:名字:“USB键盘”数量:2 sfShoppingItem_4:名字:“激光打印机”数量:1
一旦csDoctrineActAsSortablePlugin
插件安装和数据模型准备好了,新的插件需要激活ProjectConfiguration
类位于配置/ ProjectConfiguration.class.php
:
类ProjectConfiguration扩展sfProjectConfiguration{公共函数设置(){这个美元- >enablePlugins(数组(“sfDoctrinePlugin”,“csDoctrineActAsSortablePlugin”));}}
接下来,数据库,可以生成模型、形式和过滤器和设备加载到数据库给新创建的表。可以实现这一次多亏了原则:建立
任务:
php sy欧宝娱乐app下载地址mfony学说:美元构建——都无法得到确认
symf欧宝娱乐app下载地址ony缓存必须清除完成流程和插件的资产必须在有关网络
目录:
美元$ ph欧宝娱乐app下载地址p symfony缓存:明确php symfony插件:发布资产
以下部分解释了如何构建后端模块管理生成器工具和如何受益于新的行动基类功能。
设置后端
本节描述所需的步骤设置一个新的后端应用程序包含两个生成模块管理购物和todo列表。因此,首先要做的就是生成一个后端
应用程序的房子未来的模块:
美元php 欧宝娱乐app下载地址symfony生成:应用程序的后端
尽管管理发电机是一个伟大的工具,symfony 1.3之前,开发人员被迫重复之间的通用代码生成模块。欧宝娱乐app下载地址然而,现在原则:generate-admin
引入了一个新的任务——actions-base-class
选项,允许开发人员定义模块的基本操作类。
两个模块是安静的相似,他们肯定需要共享一些通用操作代码。这段代码可以位于一个超级动作类位于lib /行动
目录如下面的代码所示:
/ / lib /动作/ sfSortableModuleActions.class.php类sfSortableModuleActions扩展sfActions{}
一旦新sfSortableModuleActions
类是创建和缓存清理,可以生成两个模块的后端应用程序:
php sy欧宝娱乐app下载地址mfony学说:美元generate-admin——模块=购物actions-base-class = sfSortableModuleActions端sfShoppingItem
php sy欧宝娱乐app下载地址mfony学说:美元generate-admin——模块= todo actions-base-class = sfSortableModuleActions端sfTodoItem
管理生成器生成模块在两个单独的目录中。当然,第一个目录是应用程序/后端模块
。大部分的生成模块文件,然而,位于缓存/后端/ dev /模块
目录中。文件位于这个位置时再生每次缓存清除或模块的配置更改。
请注意
浏览缓存的文件是一个伟大的方式来了解symfony和管理发电机一起工作。欧宝娱乐app下载地址因此,新sfSortableModuleActions
子类中可以找到缓存/后端/ dev /模块/ autoShopping /行动/ actions.class.php
和缓存/后端/ dev /模块/ autoTodo /行动/ actions.class.php
。默认情况下,symfon欧宝娱乐app下载地址y会直接生成这些类继承sfActions
。
这两个后端模块可以使用和定制。这不是本章的目标,然而,探索自动生成模块的配置。重要的文档存在于这一主题欧宝体育电话,其中包括欧宝娱乐app下载地址symfony参考书。
改变一个项目的位置
前一节中描述了如何设置两个功能齐全的后端模块,既继承相同的操作类。下一个目标是创建一个共享的行动,它允许开发人员互相之间对象从一个列表中。这是相当容易安装的插件提供了一个完整的API来处理对象的手段。
第一步是创建两个新航线能够记录在列表中向上或向下移动。管理发电机使用sfDoctrineRouteCollection
路线,新航线可以很容易地宣布和附着在收集通过配置/ generator.yml
两个模块:
#应用/后端/模块/购物/ config /发电机。yml发生器:类:sfDoctrineGenerator参数:model_class: sfShoppingItem主题:管理non_verbose_templates:真正的with_show:虚假奇异:~复数:~ route_prefix: sf_shopping_item with_doctrine_route:真正的actions_base_class: sfSortableModuleActions配置:行动:~:~列表:max_per_page: 100类型:[位置,asc]显示:[位置、名称、数量]object_actions: moveUp:{标签:“向上”,行动:“moveUp”} moveDown:{标签:“向下”,行动:“moveDown”} _edit: ~ _delete: ~过滤器:~形式:~编辑:~新:~
需要重复的变化待办事项
模块:
#应用/后端/模块/备忘录/ config /发电机。yml发生器:类:sfDoctrineGenerator参数:model_class: sfTodoItem主题:管理non_verbose_templates:真正的with_show:虚假奇异:~复数:~ route_prefix: sf_todo_item with_doctrine_route:真正的actions_base_class: sfSortableModuleActions配置:行动:~:~列表:max_per_page: 100类型:[位置,asc]显示:[位置、名称、优先级、assigned_to] object_actions: moveUp:{标签:“向上”,行动:“moveUp”} moveDown:{标签:“向下”,行动:“moveDown”} _edit: ~ _delete: ~过滤器:~形式:~编辑:~新:~
两个YAML文件描述的配置购物
和待办事项
模块。这些被定制以满足最终用户的需求。首先,列表视图是有序的位置
列一个提升
排序。接下来,每页马克斯项的数量已经增加到100,以避免分页。
最后,显示列的数量减少了位置
,的名字
,优先级
,assigned_to
和数量
列。此外,每个模块有两个新举措:moveUp
和moveDown
。最终的呈现应该类似于下面的截图:
这两个新的行动已宣布但现在什么都不做。每个必须创建共享行为类,sfSortableModuleActions
如下所述。的csDoctrineActAsSortablePlugin
每个模型类的插件提供了两个额外的有用的方法:促进()
和降级()
。每一个用于构建moveUp
和moveDown
行动。
/ / lib /动作/ sfSortableModuleActions.class.php类sfSortableModuleActions扩展sfActions{/ * * *移动列表中的一个项目。* / * * @param sfWebRequest美元请求公共函数executeMoveUp(sfWebRequest美元的请求){这个美元- >项=这个美元- >getRoute()- >getObject();这个美元- >项- >促进();这个美元- >重定向(这个美元- >getModuleName());}/ * * *移动一个项目的列表。* / * * @param sfWebRequest美元请求公共函数executeMoveDown(sfWebRequest美元的请求){这个美元- >项=这个美元- >getRoute()- >getObject();这个美元- >项- >降级();这个美元- >重定向(这个美元- >getModuleName());}}
由于这两个共同行动,todo列表和购物清单都是合适的。此外,他们很容易维护和测试与功能测试。随意提高模块的外观和感觉通过覆盖模板删除第一个对象的操作向上移动
链接,最后向下移动
链接。
特别的礼物:改善用户的体验
在结束之前,让我们波兰两个列表来改善用户的体验。每个人都同意,移动记录向上(或向下)通过点击一个链接不是很直观的最终用户。更好的方法是明确包括JavaScript ajax行为。在这种情况下,所有HTML表行拖拽,可以滴落的感谢表拖拽
jQuery插件。一个ajax调用时将用户移动HTML表中的一行。
首先抓住和安装jQuery框架下web / js
目录,然后重复的操作表拖拽
是托管在一个插件的源代码谷歌代码存储库。
工作,每个模块必须包含一个小的列表视图和两个表需要一个JavaScript片段id
属性。可以覆盖所有管理生成器模板和泛音,_list.php
位于缓存文件,默认情况下,应该复制到两个模块。
不过等等,复制_list.php
下的文件模板/
每个模块的目录不是很干。只是复制缓存/后端/ dev /模块/ autoShopping /模板/ _list.php
文件到应用程序/后端/模板/
目录,重命名它_table.php
。用下面的代码替换当前的内容:
< div类=“sf_admin_list”>< ? php如果(!美元寻呼机- >getNbResults()):? >< p > < ? php回声__(“没有结果”,数组(),“sf_admin”)? > < / p >< ? php其他的:? ><表格单元格间距=“0”id =“sf_item_table”> < thead > < tr > < id =“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”)? >< / th > < / tr > < / thead > < tfoot > < tr > < th colspan =“< ?php echo $ colspan ? > ">< ? php如果(美元寻呼机- >haveToPaginate()):? >< ? phpinclude_partial(sf_request美元- >getParameter(“模块”)。/分页的,数组(“寻呼机”= >美元寻呼机))? >< ? phpendif;? >< ? php回声format_number_choice([1][0]没有结果| 1 |结果(1 +正]% 1%的结果,数组(“% 1%”= >美元寻呼机- >getNbResults()),美元寻呼机- >getNbResults(),“sf_admin”)? >< ? php如果(美元寻呼机- >haveToPaginate()):? >< ? php回声__(”(页面% % % % / % % nb_pages % %)”,数组(% % % %页的= >美元寻呼机- >getPage(),“% % nb_pages % %”= >美元寻呼机- >getLastPage()),“sf_admin”)? >< ? phpendif;? >< / th > < / tr > < / tfoot > < tbody >< ? phpforeach(美元寻呼机- >getResults()作为我美元= >美元的项目):? >< ? php奇怪的美元=在你(+ +我美元,2)吗?“奇怪”:“甚至”? >< tr类=“sf_admin_row < ?php echo $奇怪? > ">< ? 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;? >< / div > < =脚本类型“text / javascript”>/ * < !(CDATA[ */函数checkAll(){var盒= document.getElementsByTagName(“输入”);为(var指数=0;指数< boxes.length;指数+ +){盒=盒子(指数];如果(盒子。类型==“复选框”& &盒子。类Name ==“sf_admin_batch_checkbox”)盒子。检查= . getelementbyid(“sf_admin_list_batch_checkbox”)支票}返回真正的;}/ *]]> * /> < /脚本
最后,创建一个_list.php
每个模块的内部文件模板
每一个目录,并将以下代码:
/ /应用程序/后端/模块/购物/模板/ _list.php< ? phpinclude_partial(“全球/表”,数组(“寻呼机”= >美元寻呼机,“助手”= >美元的助手,“排序”= >美元的排序,“colspan”= >5))? >
/ /应用程序/后端/模块/购物/模板/ _list.php< ? phpinclude_partial(“全球/表”,数组(“寻呼机”= >美元寻呼机,“助手”= > $helper, 'sort' => $sort, 'colspan' => 8 )) ?>
改变的位置,两个模块需要实现一个新的行动处理ajax请求。正如之前所看到的,新的共享executeMove ()
将放置在行动sfSortableModuleActions
动作类:
/ / lib /动作/ sfSortableModuleActions.class.php类sfSortableModuleActions扩展sfActions{/ * * *执行Ajax请求,一个项目移动到一个新的位置。* / * * @param sfWebRequest美元请求公共函数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”;}}
/ /应用程序/后端/模块/备忘录/ lib / todoGeneratorConfiguration.class。php类todoGeneratorConfiguration延伸BaseTodoGeneratorConfiguration{公共职能getModel(){返回“sfTodoItem”;}}
有一个最后一个手术要做。目前,表行不拖,不执行ajax调用行移动时释放。为了达到这个目标,这两个模块需要访问相应的具体途径移动
行动。因此,应用程序/后端/ config / routing.yml
文件需要以下两个新路线如下所示:
< ? phpforeach(数组(“购物”,“待办事项”)作为美元的模块):? >< ? php回声美元的模块? > _move:类:sfRequestRoute url: /< ? php回声美元的模块? >/移动参数:模块:“< ?php echo $模块? > "行动:行动要求:sf_method:(得到]< ? phpendforeach? >
为了避免代码重复,在生成的两个路线foreach
语句和基于模块名称很容易在视图中检索它。最后,应用程序/后端/模板/ _table.php
必须执行的JavaScript代码片段来初始化拖放行为和相应的ajax请求:
<脚本类型=“text / javascript”charset =“utf - 8”>美元()时(函数(){美元(“# sf_item_table”).tableDnD({onDrop:函数(表,行){var行= table.tBodies(0].rows;/ /获取移动项的idvarmovedId = $(行);(“td输入:复选框”).val();/ /计算新行的位置varpos=1;为(var我=0;我< rows.length;我+ +){var细胞=行(我]childnodes;/ /执行ajax请求的新位置如果(movedId = = $(细胞(1]);(输入:复选框的).val()){. ajax美元({url:“< ?php echo url_for (“@”。$ sf_request - > getParameter(“模块”)。“_move”) ? > ? id = "+ movedId +"等级= "+pos类型:“获得”});打破;}pos+ +;}},});});> < /脚本
现在是功能齐全的HTML表。拖行和可抛弃的,连续的新职位是自动保存归功于一个ajax调用。只有几块代码,后台的可用性大大改善为最终用户提供一个更好的体验。管理发电机是足够灵活的扩展和定制和完美主义的工作表继承。
随时提高两个模块通过移除这两个过时了moveUp
和moveDown
行动和添加任何其他定制,满足您的需要。
最终的想法
这一章描述了教义表继承是一个强大的功能,这有助于开发人员代码更快,提高代码的组织。这一原则的功能完全集成在symfony的几个层面。欧宝娱乐app下载地址鼓励开发人员利用它来提高效率,促进代码组织。
这项工作在Creative Commons许可Attribution-Share都3.0 Unported许可执照。