Magento技术指南.docx
- 文档编号:28685751
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:18
- 大小:90.42KB
Magento技术指南.docx
《Magento技术指南.docx》由会员分享,可在线阅读,更多相关《Magento技术指南.docx(18页珍藏版)》请在冰豆网上搜索。
Magento技术指南
技术指南
总览
本文档列出了指导Magento2开发人员团队的基本编码和应用程序设计原则。
Magento核心开发人员在代码审查期间将本文档用作参考;有些规则在Magento静态测试中具有相应的代码检查。
这些准则来自多年的辛勤工作,经验和讨论。
我们坚信,新的技术倡议应遵循这些建议,并且应改进现有的规范以符合这些建议。
文本约定
使用RFC2119来解释关键字,如:
∙MUSTandMUSTNOT
∙REQUIRED
∙SHALLandSHALLNOT
∙SHOULDandSHOULDNOT
∙RECOMMENDED
∙MAY
∙OPTIONAL
1.基本编程原则
1.1。
函数参数不应该被修改。
1.2。
显式返回类型必须在函数上声明。
1.3。
应该使用标量参数的类型提示。
1.3.1。
所有新的PHP文件都必须以declare(strict_types=1)开头启用严格类型模式。
所有更新的PHP文件都应该启用严格类型模式。
PHP接口可能有这样的声明。
2.类的设计
2.1。
对象分解必须遵循SOLID原则。
2.2。
对象实例化
2.2.1。
对象必须在实例化后准备好使用。
不允许使用其他公共初始化方法。
2.2.2。
Factories应该用于对象实例化而不是new关键字。
为了测试或可扩展性,对象应该是可替换的。
例外:
DTO。
DTO中没有任何行为,因此没有理由可替换。
测试可以为存根创建真正的DTO。
数据接口,异常和Zend_Db_Expr是DTO的示例。
2.3。
类构造函数只能具有依赖项分配操作和/或参数验证操作。
不允许其他操作。
2.3.1。
当参数验证失败时,构造方法应该抛出异常。
2.3.2。
不得在构造函数中触发事件。
2.4。
所有依赖项必须由client对象所需的最通用类型请求。
2.5。
绝对不能在构造函数中明确请求代理和拦截器。
2.6。
不应使用继承。
组合应该用于代码重用。
2.7。
所有非公共属性和方法都应该是私有的。
2.8。
抽象类不得标记为public @api。
2.9。
服务类(提供行为但不提供数据的类,如EventManager)不应具有可变状态。
2.10。
只有数据对象或实体(产品,类别等)能具有任何可见状态。
2.11。
不应使用“Setters”。
它们只允许在数据传输对象中使用。
2.12。
“Getters”不应更改对象的状态。
2.13。
不应使用静态方法。
2.14。
必须避免时间耦合
2.15。
必须避免在类设计中使用方法链。
2.16。
应当遵守Demeter的定律。
2.17。
模式
2.17.1。
代理应该用于延迟加载可选的依赖项。
2.17.2。
当需要将树作为单个对象使用时,应使用复合材料。
2.17.3。
当执行一个操作有多个算法时,应该使用策略。
3.依赖注入
3.1。
对象之间不应有循环依赖。
3.2。
app/etc/di.xml文件必须只包含框架级别的依赖注入(DI)设置。
3.3。
所有模块化DI设置(表示层配置除外)都应存储在中
3.4。
所有模块化的PresentationlayerDI设置都应存储在中
4.拦截
4.1。
Around-plugins应该只在原始方法的行为应该在某些场景中被替换的时候使用。
4.2。
插件不应在自己的模块中使用。
4.3。
不应将插件添加到数据对象。
4.4。
插件必须是无状态的。
4.5。
插件不应该更改被拦截对象的状态(被拦截对象为$subject)。
5.异常
5.1。
所有出现在终端用户面前的异常必须产生以下格式的错误消息:
∙症状(Symptom)
∙详情(Details)
∙解决方案或解决方法(Solutionorworkaround)
5.2。
不得在抛出异常的同一函数中处理异常。
5.3。
如果函数A调用函数B,并且函数B可能引发异常,则此异常必须由函数A处理或由函数A的文档模块中的@throws批注声明。
5.4。
异常不得处理消息输出。
处理代码决定了如何处理异常。
5.5。
业务逻辑(应用程序和域)都不得进行例外管理。
应改为使用条件语句。
5.6。
异常类的简短名称必须清晰、有意义,并说明异常的原因。
5.7。
被抛出的异常应该尽可能具体。
顶级通用名\Exception不应扔在任何地方。
5.8。
与第三方库的所有直接通信都必须使用try/catch语句包装。
5.9。
\Exception除了捕获库抛出的特定异常之外,应该仅在调用第三方库的代码中捕获该异常。
5.10。
\Exception不应在前端控制器和动作控制器中抛出该异常。
5.11。
应在每个应用程序层上定义一个单独的异常层次结构。
允许引发仅在同一层上定义的异常。
5.12。
如果在应用程序层上捕获到与抛出异常不同的异常,并且应该重新抛出该异常,则应该创建一个适用于当前层的新异常实例。
在这种情况下,原始异常必须通过“previous”参数传递给新实例。
5.13。
在没有日志记录或/和未执行任何变通方法操作的情况下,不允许吸收异常。
5.14。
任何异常都应仅记录在catch处理异常的块中,而不应该被重新抛出。
5.15。
不应该在循环中捕获异常。
循环应该用try/catch结构来包装。
5.16。
如果方法使用系统资源(例如文件,套接字,流等),则代码必须用一个try块和相应的finally块包装。
在本finally节中,应该适当地释放所有资源。
5.17。
需要显示给用户的异常必须是LocalizedException的子类型。
在显示给用户之前,任何其他类型的异常都必须使用LocalizedException进行包装。
5.18。
LocalizedException应该只在表示层中抛出。
5.19。
每个模块或组件必须声明其自己的异常。
在其他组件中声明的异常不应抛出。
5.20。
插件必须只抛出由插件所在的方法声明的异常或派生的异常。
观察者只能抛出由触发事件或派生异常的方法声明的异常。
6.应用层
6.1。
所有层
6.1.1。
应用程序应该按照CQRS原则进行结构化。
6.1.2。
每个应用程序层(Presentation,ServiceContracts,DataAccess)必须处理(处理或重新抛出)底层的异常。
6.1.3。
层不能依赖于调用它的层。
一个层必须只直接依赖于一个层。
6.2。
表示层
6.2.1。
根据CQRS的介绍,表示层承载命令和查询基础结构:
∙命令的行为
∙查询布局及其元素(块和UI组件)
6.2.2。
请求,响应,会话,商店管理器和Cookie对象必须仅在Presentation层中使用。
6.2.3。
所有操作都必须返回ResultInterface实现。
6.2.4。
动作绝不能引用布局中声明的块。
6.2.5块不能假设当前请求调用了特定的或任何的控制器。
6.3。
数据访问(持久性)层
6.3.1。
实体的字段范围可能有所不同(在产品中,EAV–每个商店,选项–每个网站)。
6.3.2。
每个持久性操作必须在一组作用域下执行。
6.3.3。
实体绝不能包含与持久性有关的逻辑。
6.3.4。
MySQL的strict_mode变量应该与最新MySQL版本的默认strict_mode一致。
6.4。
服务合同(应用程序)层
6.4.1。
API接口的位置
6.4.1.1。
服务合同接口应放置在单独的API模块中,除非现有模块的Api文件夹中已包含服务合同。
其他模块将取决于API模块,并且可以通过轻松交换实现di.xml。
API模块名称必须以Api后缀结尾。
例如,如果模块名为MyModule,则其API应在名为模块中声明MyModuleApi。
6.4.1.2。
应该作为WebAPI公开的服务接口必须放在MyModuleApi/Api目录下。
服务数据接口必须放在下MyModuleApi/Api/Data。
MyModuleApi/Api下的目录不应该嵌套。
6.4.1.3。
所有其他API(包括明确的扩展点,例如Chain或Composite实现)都必须放在下MyModuleApi/Model。
6.4.2。
服务接口结构
6.4.2.1。
具有相似名称的方法必须在不同的服务之间具有相似的用途,但是它们仍然可能具有不同的签名。
6.4.2.2。
服务合同不应在店面中用于读取方案。
相反,GraphQL应该用于店面方案。
查看WebAPI技术远景以了解更多详细信息。
6.4.2.3。
每个服务接口都应该声明一个公共方法。
接口名称应该反映要执行的任务或动作。
例如,Magento\InventoryApi\Api\StockSourceLinksDeleteInterface:
:
execute(array$links)。
唯一的例外是存储库API,为方便起见,可以添加该API,并且必须将其限制为单个CRUD操作和getList($searchCriteria)。
6.4.3。
服务方法签名
6.4.3.1。
对于位于MyCompany/MyModuleApi/Api下的服务和数据接口,将强制执行严格的类型。
只允许以下类型:
∙Scalartypes:
string(包括Date和DateTime);int; float;boolean
∙Datainterfaces
∙标量或数据接口的一维索引数组:
例如string[],\MyCompany\MyModuleApi\Api\Data\SomeInterface[]。
不支持哈希映射(关联数组)。
∙可空标量或数据接口:
例如string|null。
禁止使用justnull。
∙void
6.4.3.2。
服务合同应支持批量数据处理。
例如,实体持久化方法应该接受一组实体持久化而不是单个实体。
通过插件实现的自定义应分别进行调整。
6.4.3.3。
批检索操作必须接受SearchCriteriaInterface并返回SearchResultInterface来支持分页。
6.4.3.4。
修改状态的批处理操作必须接受实体数组并返回包含以下内容的响应对象:
∙成功处理的项的数组
∙带有可检索错误的项的数组
∙带有不可检索错误的项的数组
6.4.3.5。
修改状态的批处理操作应该以最有效的方式实现,并且不应该加载修改后的实体来生成响应。
6.4.3.6。
WebAPI框架应支持命令服务的异步调用。
6.4.3.7。
UUID操作可能由客户端在服务调用期间提供。
UUID必须允许客户端获取操作状态信息。
6.4.3.8。
服务合同返回的数据对象应该被完全加载以确保一致性。
6.4.3.9。
服务合同应允许客户端生成ID。
服务应该接受ID而不是生成ID。
请参阅UUID作为客户端生成的ID的示例。
6.4.4。
服务实施
6.4.4.1。
服务数据接口应从Magento\Framework\Api\ExtensibleDataInterface扩展。
唯一的例外是在不需要扩展性时,例如在值对象的情况下。
6.4.4.2。
可扩展的数据接口不得形成层次结构。
如果接口MyInterface扩展ExtensibleDataInterface,则必须没有接口扩展MyInterface。
否则,将为层次结构中的所有可扩展接口共享扩展属性列表。
6.4.4.3。
服务实现和插件务必不得依赖于存储特定的完整性功能,例如外键约束。
6.4.4.4。
替换策略应用于保留主要实体字段/属性,子实体和关系链接。
6.4.4.5。
在更新操作期间,使用PATCHHTTP方法的WebAPI 和所有接受实体的动作控制器应首先预加载它们,然后合并请求数据,并将完整数据提供给服务。
6.4.4.6。
如果服务方法需要修改参数,则不得修改原始参数对象,而应修改其副本。
6.4.4.7。
服务不应将ACL规则应用于方法或返回的数据。
6.4.4.8。
如果一个商店有多个范围(网站,商店),则每个调用务必只能在一个范围内保留一个实体。
如果一个实体需要保存在多个范围内,那么应该进行多次调用。
6.4.4.9。
服务合同不应将表示层格式应用于返回的数据。
6.4.4.10。
服务数据接口不得包含任何业务逻辑。
它们应该表示可通过网络传输的数据容器。
所有业务逻辑都应该转移到服务上。
6.4.4.11。
域/业务逻辑必须在服务合同层上执行。
6.4.4.12。
对域/业务逻辑的任何自定义都必须在服务合同层上执行,因此必须在global配置区域中声明。
6.4.4.13。
服务合同不得依赖执行上下文(应用程序区域)。
服务实现不得依赖于应用程序状态。
6.4.4.14。
服务合同应该是 idempotentmethod。
7.配置
7.1。
应用程序实例包括:
∙代码(Code)
∙环境配置(EnvironmentConfiguration)
∙数据(Data)
7.2。
代码包括:
∙应用程序代码库(applicationcodebase)
∙XML配置(XML configuration)
∙生成的代码和静态文件(generatedcodeand staticfiles)
∙数据库结构(databasestructure)
∙系统配置值(systemconfigurationvalues)
∙配置范围(商店/商店组/网站)(configurationscopes(stores/storegroups/websites))
∙CMS实体(CMS entities)
7.3。
环境配置包括有关应用程序服务连接的信息。
7.4。
数据包括业务实体数据。
7.5。
代码和环境配置不得存储在数据存储中。
7.6。
安装过程中不得修改代码。
7.7。
所有XML配置格式都必须是声明性的。
不允许命令式节点。
7.8。
所有配置对象必须使用Magento\Framework\Config。
8.模块化
8.1。
应用程序框架(Magento\Framework\*)一定不要依赖应用程序模块。
8.2。
所有依赖项必须在组件的composer.json文件中声明。
8.3。
如果组件A使用组件B的行为,则该组件B必须在组件A的composer.json文件的require部分中声明但在定制组件B行为的代码中使用了组件B的情况除外。
8.4。
如果组件A通过其定制点(布局句柄,插件,事件等)扩展/定制了组件B的行为,则必须在suggest组件A 的部分中声明此类组件B。
8.5。
只有任何模块的@api代码可以被其他模块引用。
8.6。
模块不得包含对主题资源的引用。
8.7。
组件既不能依赖于依赖项的依赖项,也不能依赖于它所包含的项目的依赖项(例如,Magento应用程序)。
必须显式地声明所有组件依赖关系。
9.Web应用程序中的浏览器-服务器交互
9.1。
所有客户端服务器调用都必须遵循HTTP协议。
9.2。
所有与客户无关的数据(产品,类别,CMS页面)都必须呈现在服务器上,并缓存在公共缓存服务器(Varnish)中。
9.3。
必须使用JavaScript(JS)应用程序在浏览器端呈现所有特定于客户的数据。
9.4。
在服务器上生成的HTML 标记不得包含用户特定的数据。
9.5。
在服务器上生成的HTML标记不得包含特定于会话的数据(例如,带有CSRF令牌的表单元素)。
9.6。
JS应用程序可以使用CustomerDataJS API接收特定于客户的数据。
9.7。
来自浏览器的所有状态修改请求都应该使用AJAX请求执行。
9.8。
如果在请求处理期间发生错误,则服务器务必返回适当的HTTP状态代码和响应正文中的错误说明。
9.9。
必须遵守所有标头。
9.10。
请求,会话和Cookie对象一定不能注入到对象构造函数中。
它们只能作为方法参数传递。
9.11。
操作必须始终显式地请求操作范围(不应该使用StoreManager来检索存储ID)。
10.JavaScript(JS)应用程序
10.1。
Magento2 UI组件框架必须用于构建前端应用程序。
10.2。
只有私有内容才能在浏览器中呈现。
10.3。
RequireJS模块的所有模块依赖项必须在模块的定义头中声明。
10.3.1 除非要加载的模块列表是动态的,否则不应直接调用require。
10.3.2代码不能使用require(require('moduleIdentifier'))的同步形式。
10.4。
必须遵循W3C内容安全策略。
10.5。
应当遵循ESLint 规则。
10.5.1。
应该使用ECMAScript5.1作为JS标准。
10.5.2。
语言功能(闭包,WeakMap等)必须用于私有状态。
私有属性不应该有_(下划线)命名约定。
。
10.5.3。
XMLHttpRequest的所有使用(包括jQuery的$.ajax)必须是异步的。
10.5.4。
不得添加新的全局属性(通过显式window分配或var在顶级范围内)。
RequireJS模块系统应该用于共享对象。
10.5.5。
模块不得有外部副作用。
10.5.6。
代码不能重新声明在可达范围内已经声明的任何标识符(重新赋值是可以接受的)。
11.测试
11.1。
白盒测试(单元,集成,功能)
11.1.1。
仅应测试公共方法。
私人和受保护的行为应通过公共方法进行测试。
11.2。
单元测试
11.2.1。
所有对象应单独进行测试。
11.2.2。
ObjectManager不得在单元测试中使用。
11.2.3。
ObjectManagerHelper可以用来自动模拟被测对象的所有依赖关系。
11.3。
功能测试
11.3.1。
页面
11.3.1.1。
页面文件名必须遵循以下模式:
∙{AdminorStorefront}{Description}Page.xml,其中{Description}简要介绍了要测试的页面。
∙使用PascalCase。
∙例:
AdminProductAttributeGridPage.xml
11.3.1.2。
页面name属性必须与文件名相同。
11.3.1.3。
页面module属性必须遵循以下模式:
∙{VendorName}_{ModuleName}
∙例:
Magento_Backend
11.3.1.4。
11.3.2。
段(Section)
11.3.2.1。
段文件名必须遵循以下模式:
∙{AdminorStorefront}{Description}Section.xml,其中{Description}简要介绍了要测试的部分。
∙使用PascalCase。
∙例:
StorefrontCheckoutCartSummarySection.xml
11.3.2.2。
段name属性必须与文件名相同。
11.3.2.3。
11.3.3。
元素
11.3.3.1。
所有元素选择器必须遵循这些最佳实践。
11.3.3.2。
元素在中name必须唯一
11.3.3.3。
元素name应该用camelCase编写。
11.3.3.4。
参数化选择器必须为其参数使用描述性名称。
11.3.3.5。
元素应该使用该timeout属性在交互后等待。
11.3.4。
数据实体
11.3.4.1。
数据实体文件名必须遵循以下模式:
∙{Type}Data.xml,其中{Type}描述实体的类型。
∙使用PascalCase。
∙示例:
ProductData.xml或CustomerData.xml
11.3.4.2。
数据实体应该使用unique="suffix"或unique="prefix"确保使用该实体的测试可以针对相同的环境反复运行。
11.3.4.3。
对现有数据实体的更改必须与现有测试兼容。
11.3.5。
操作组
11.3.5.1。
操作组文件名必须遵循以下模式:
∙如果操作组正在声明,则使用以下格式:
Assert{AdminorStorefront}{Functionality}ActionGroup.xml其中{Functionality}简要描述了操作组正在做什么。
∙否则,请使用以下格式:
{AdminorStorefront}{Functionality}ActionGroup.xml
∙例:
AssertStorefrontMinicartContainsProductActionGroup.xml
11.3.5.2。
动作组参数必须指定type属性。
11.3.5.3。
操作组不得有未使用的参数。
11.3.5.4。
操作组不得引用已创建的数据实体,例如,$$createdOutOfScopeData.property$$或$createdOutOfScopeData.property$从操作组范围之外创建的数据实体。
相反,操作组必须使用参数来访问此范围外的数据。
11.3.5.5。
操作组参数应该指定默认值。
11.3.6。
元数据
11.3.6.1。
元数据文件名必须遵循以下模式:
∙{Type}Meta.xml,其中{Type}描述实体的类型。
∙使用PascalCase。
∙示例:
CategoryMeta.xml和ProductAttributeMeta.xml
12.WebAPI
12.1。
REST和SOAPAPI都必须公开。
12.2。
所有WebAPI GET端点必须返回实体列表。
13.命令行界面(CLI)
13.1。
必须遵循Magento2 CLI命令命名准则。
13.2。
必须为系统集成商/系统管理员/开发人员打算使用的任何功能创建CLI命令(例如:
更改indexer模式、生成配置文件等)。
13.3。
CLI命令必须始终在全局区域中运行。
如果一个命令需要一个特定的区域来执行其功能,那么应该在执行之前设置该区域。
13.4。
单个CLI命令中的异常不应破坏CLI框架;仍然可以运行其他命令。
14.事件(Event)
14.1。
传递给事件的所有值(包括对象)都不得在事件观察器中进行修改。
相反,应该使用插件来修改函数的输入或输出。
14.2。
应该尽可能具体地观察所使用的事件。
当受影响的区域只是前端时,不应该使用事件的全局订阅。
14.3。
事件不应该改变可观察对象的状态。
15.安全性
15.1。
对SQL查询使用预处理语句。
15.2。
身份验证保护失败。
15.2.1。
在可能的情况下,请执行多因素身份验证,以防止自动进行凭据填充,暴力破解和凭据重用攻击。
15.2.2。
不要使用任何默认凭据(特别是对于管理员用户)进行运送或部署。
15.2.3。
实现弱密码检查,例如针对最糟糕的10000个密码列表测试新密码或更改的密码。
15.2.4。
根据NIST800-63B在5.1.1节中关于记忆秘密或其他现代的、基于证据的密码策略的指南,调整密码长度、复杂性和轮换策略。
15.2.5。
通过对所有结果使用相同的消息,确保对注册、凭据恢复和API路径进行强化,以抵御帐户枚举攻击。
15.2.6。
限制或越来越多地延迟失败的登录尝试。
记录所有故障,并在检测到凭据填充,暴力破解或其他攻击时提醒管理员。
15.2.7。
使用服务器端、安全的内置会话管理器,在登录后生成一个新的随机会话ID。
会话id不应该在URL中,应该在注销、空闲和绝对超时之后安全地存储和失效。
15.3。
跨站点脚本(XSS)保护。
15.3.1。
Sanitize输入;转义输出。
15.3.2。
请遵循XSS预防策略
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Magento 技术 指南