如何编写自定义扩展名?


143

因为我最近在免费和商业扩展方面遇到了很多问题,所以我决定问这个问题,并按照编写扩展时通常遵循的步骤回答。随时编辑答案或添加新答案。
在大多数情况下,安装扩展程序或主题时,我必须花费几个小时(有时更多,有时更少)才能使其在我需要的所有环境中正常工作:

  • dev:通常localhost项目在子文件夹中
  • 预生产和现场

即使来自大型扩展程序提供商的扩展程序,也发生了这种情况(至少应该保持匿名,直到我非常生气并在此处添加其名称为止)。
所以主要问题是..编写扩展程序以确保质量时应考虑哪些步骤?代码,并使技术人员和非技术人员更容易使用它,并使技术人员更容易更改它?


11
似乎其中一个大型扩展提供商不喜欢这个问题,并对此予以否决。:)
Marius

1
就个人而言,绝对不会与Wyomind发生冲突,但他们会加密自己的代码,并且仍然是“高级合作伙伴”:((仅举例来说)
sv3n

Answers:


185

这是我通常的工作:

  1. 始终error_reporting坚持下去。
  2. 始终isDeveloperMode将设置为开发true。只需添加SetEnv MAGE_IS_DEVELOPER_MODE 1到您的httpd.conf文件(或Nginx或其他相应文件)中
  3. 如果扩展链接到核心功能,则在声明文件中添加依赖项 <depends><Mage_Catalog /></depend>
  4. 如果该模块供社区使用,请community用作代码池,使开发人员有机会覆盖某些类而无需直接修改代码
  5. 放入前端设计文件app/design/frontend/base/default 以使它们可用于所有主题。
  6. 将您的管理设计文件放入 app/design/adminhtml/default/default,不要更改管理主题。我可能想在我的一个模块中进行更改。
  7. 使用公司名称为布局文件名和模板文件夹名加上前缀,以便于隔离。 easylife_articles.xmlapp/design/.../easylife_articles
  8. 将您的静态资源(JavaScript,CSS和图像)放在与模板文件相似的文件夹中 easylife_articles/images/doh.png
  9. 附上一个简单的文本文件以及如何卸载扩展程序:需要删除哪些文件,需要删除哪些表,需要从core_config_data表中删除哪些配置设置。
  10. 不要直接在模型,块或帮助器中编写查询,而要使用资源模型。
  11. 不要直接使用表名编写查询Select * from sales_flat_order where ...。使用a Zend_Select并使用转换表名->getTable('sales/order')
  12. 使用基本网址js在模板中包含文件。错了 <script type="text/javascript" src="../js/some.js"></script> <script type="text/javascript" src="<?php echo Mage::getBaseUrl('js').'some.js'?>"></script>
  13. 除非必要,否则不要重写类。使用观察者,如果无法使用作为参数和您要覆盖的类的实例接收的帮助器方法。错误:重写Mage_Catalog_Model_Product添加方法 getProductArticles()。在您的助手中添加 getProductArticles(Mage_Catalog_Model_Product $product)
  14. 如果覆盖类,则将它们的列表放在readme.txt文件中
  15. 使用默认管理路径作为模块的admin部分。 管理员网址错误 articles/adminhtml_articles/index正确的管理员网址 admin/articles/index
  16. 为您的管理部分添加ACL。我可能想将访问权限限制为某些管理员。
  17. 如果不需要,请不要添加其他JavaScript框架(jQuery,MooTools等)。在原型中编写代码。
  18. 使您的模板HTML W3C有效(这适用于像我这样的OCD开发人员)。
  19. 不要将图像放在media文件夹中。使用skin。该media 文件夹通常没有版本,这使得将网站移至其他环境变得更加困难。
  20. 在打开和关闭平面目录的情况下测试扩展。为了不增加开发时间,请使用Chaos Monkey
  21. 使用cache on和cache 测试扩展off
  22. 避免在模块和类名称中使用大写字母。如果未正确测试,则可能在其他操作系统上引起问题。这更多是建议,而不是“必须”。
  23. 在代码中调度事件,以使开发人员更轻松地更改功能。
  24. 遵循Magento使用的相同编码标准并注释您的代码。
  25. 不要使用PHP短标签(<? $this->doSomething() ?>)。使用完整标签(<?php $this->doSomething()?>)。也不要使用简短的回声标签。(<?="D'oh";?>)。使用(<?php echo "D'oh";?>
  26. 使用来翻译您的文字,$this->__app/local/en_US/Easylife_Articles.csv至少在en_US语言方面添加带有文字()的语言环境翻译文件。并非所有网站都是用英语构建的,识别要翻译的文本非常耗时。
  27. 如果您出售扩展服务,至少要有基本的支持。或者至少答复您收到的支持电子邮件。
  28. 不要通过扩展名不断调用服务器以进行许可证验证。一次,安装就绰绰有余了(我也不喜欢这种方法,但是总比经常打电话要好)。(受此问题启发)
  29. 在激活日志的情况下进行开发,并不时查看该var/log/system.log文件。即使在开发人员模式下,此处列出的错误也不会显示。如果至少有一个错误,则在运行扩展几个月后,您将得到一个大日志文件。
  30. 如果您的扩展程序在某种程度上影响了结帐流程或订单,请确保其可用于多件运输,或者如果它不适用于多件运输,请确保它不影响它。
  31. 不要替换默认的管理员通知栏(或源URL)。如果我对您提供的服务感兴趣,我将订阅您的新闻通讯。让我看看Magento怎么说。对我来说更重要。
  32. 如果您使用Ioncube(或其他方式)对代码文件进行加密...那么...我只是讨厌您,希望您的公司破产

到目前为止,就是这样。一想到其他内容,我就会添加更多内容。


我同意你的看法,这绝对是一个好的开始。当然,您还将理解,并非总是可以涵盖所有不同类型的配置和问题,至少会减少可能的配置和问题。我与其他扩展程序碰到的大多数问题,或者与我碰到的其他问题都是由于与覆盖冲突而引起的。
SylvainRayé2013年

2
@Marius,请确保我+1。它涵盖了大多数情况和方案,我们在开发中面临的问题。
liyakat 2013年

4
@ColinM。首先,很荣幸在这里发表您的评论。:)。我同意这是有区别的,我将修改答案,但我仍然认为应该避免使用两者,至少要等到PHP 5.3成为“新PHP 4”。我的意思是它仍在大规模使用。
马里乌斯

4
@Marius,您的观点非常有帮助。直到#31,我都认真地专注于每一点,但在#32上,我却大笑起来。专为#32点+1
MTM

1
If you encrypt your code files with Ioncube (or something else)...well...I just hate you and I hope your business goes bankrupt我有同样的感觉。有些公司不提供更新版本,您将不得不付费,这对我来说真的很沮丧,并且不明白为什么他们要一次又一次地销售同一产品(赚钱?)。我只是不再购买他们的产品。你知道我在说谁。
Adarsh Khatri '04

31

我是使用modman的忠实拥护者,因此我可以仅对扩展名进行开发和源代码控制,而使核心文件和文件夹结构保持不变。这也使跨不同安装的测试运行更加顺畅。

哦,一个大技巧总是尝试在将干净的magento本地安装打包扩展之前,将其上传到Magento Connect,我在打包管理器中错过了很多次文件。


3
关于“在本地安装打包的扩展程序”的好话。我认为这属于以下类别:“从上至下测试您该死的扩展”。
马里乌斯

我以前也被这个迷住了。确保您在全新安装中测试了该软件包,而不是与打包它相同。
约瑟夫·利迪

22

Andreas von Studnitz和Nikolai Krambrock博士在2014年的Magento DE大会上很好地介绍了代码质量。他们区分了常规代码质量和Magento特定代码质量。简而言之,有以下一般规则:

  • 结构元素的使用-就像类和方法一样-应该安排在中间抓住的类中。这些结构元素仅在用于结构化时才有意义。因此,它们必须具有中等大小。对于类,将100-200行代码用于方法,将3-20行代码用于方法。
  • 由于使用了“ if”或“ while”,因此代码缩进了。如果缩进超过3个,则最好对其进行修改。缩进太多是代码复杂性的证据,因此应避免。
  • 死代码应避免并删除。静态分析有助于找到它是否存在。

更重要的是Magento特定的规则:

  • 模块应独立工作。他们应该只对其他模块有很少的依赖性,而对模板则没有依赖性。一种解决方案是使用layout-updates(基本/默认)而不是适应模板文件和一个涵盖模板附加功能的模块。
  • 为了保持Magento中的更新功能,应避免内核和外部模块被黑客入侵。更好的方法是改用重写器或观察器。
  • 对于更改,最好使用安装脚本,而不是直接更改数据库或管理员。多亏了他们,更改只需一次。

以下是一些更多详细信息和演示文稿的视频:http : //www.code4business.de/code-quality-magento/


1
但是,如果您使用英文版的链接,则更好。
马里乌斯

此演示文稿的英文版将很快写成。我将保持最新状态,并在英文版发布后立即分享新链接。
user3743859 2014年

演示文稿的英文版现在在线。这是它的链接:code4business.de/code-quality-magento
user3743859 2014年

嗯?它仍然是德语。但是我恰好在大约两周前参加了在MeetMagentRo上用英语发表的演讲。好东西。
马吕斯

18

如果您出售扩展或与他人共享,请考虑编写易于阅读的代码。

  1. 不要让方法太复杂
  2. 在您的方法中添加DOC块*
  3. 使用适当的变量名,例如$productIds代替$ids
  4. 方法也一样,public function myOnProductSaveMethod() {...}什么都没说,但是tryDisableInternetOnProductSave()会暗示想要的计划
  5. 在有意义的地方使用类型提示 someMethod(Varien_Data_Db_Collection $collection)
  6. 避免魔术数字和字符串**
  7. 如果您使用模型set $_eventPrefix属性(和$_eventObject)使观察者更好地访问它们
  8. 如果添加系统配置字段
    • 在中设置默认值 config.xml
    • <validate>节点添加到中的字段system.xml
    • 将ACL资源添加到 adminhtml.xml
  9. 不要在管理后端中添加无用/广告的一级菜单条目-顶栏和配置部分均不添加
  10. 为所有控制器操作添加ACL资源(也为批量操作!)
  11. 确保您的查询使用数据库表前缀
  12. 考虑(不)向后兼容性(这实际上是基于观点的)
    • 不支持Mysql4课程
    • 不要使用不推荐使用的方法
  13. 确保您的引出在每种情况下都能按预期工作-添加UnitTests(例如PhpUnit)
  14. 除了David Manners之外 ...添加一个composer.json也使部署更容易
  15. 由于PHP5.6是EOL,因此请为PHP7编写代码。使用declare(strict_types=1);并定义输入和输出类型
  16. Magento2:使用静态代码分析工具(例如phpstan)检查代码。在这里支持魔术方法。(最新提交适用于2.3,之前适用于2.1 / 2.2-要求phpstan 0.8.5)

* DOC块:

如果您使用PSR2标准或PHPMD的 PHP_CodeSniffer检查您的Magento-1代码,则可能要添加此行(在有意义的地方)...

  • 上课
    • @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
    • @phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore -继承的属性
    • @phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
    • @SuppressWarnings(PHPMD.CamelCaseClassName)
    • @SuppressWarnings(PHPMD.CamelCasePropertyName) -继承的属性
  • 方法
    • @SuppressWarnings(PHPMD.CamelCaseMethodName) -继承的方法
    • @SuppressWarnings(PHPMD.StaticAccess)-如果您使用Mage::或其他静态通话

** 经常使用:

  • 管理员商店ID
    • 0 > Mage_Core_Model_App::ADMIN_STORE_ID
  • 产品 status
    • 1 > Mage_Catalog_Model_Product_Status::STATUS_ENABLED
    • 2> Mage_Catalog_Model_Product_Status::STATUS_DISABLED (不是0预期的那样)
  • 产品 type
    • simple > Mage_Catalog_Model_Product_Type::TYPE_SIMPLE
    • bundle > Mage_Catalog_Model_Product_Type::TYPE_BUNDLE
    • configurable > Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE
    • grouped > Mage_Catalog_Model_Product_Type::TYPE_GROUPED
    • virtual > Mage_Catalog_Model_Product_Type::TYPE_VIRTUAL
  • 产品 visibity
    • 1 > Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE
    • 2 > Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG
    • 3 > Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH
    • 4 > Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH

SQL顺序ASCZend_Db_Select::SQL_ASC (例如)相同

“这不是必需品,因为它永远不会改变”?例如,catalog_product属性的实体ID 在Magento 1.5和1.9之间从10更改为4,因此这可能会破坏您的扩展名:

$collection->addFieldToFilter('entity_type_id', 10)

而是使用此方法添加一个查询,但是您会很安全...

$entityTypeId = Mage::getModel('eav/config')
    ->getEntityType(Mage_Catalog_Model_Product::ENTITY)
    ->getEntityTypeId();

$collection->addFieldToFilter('entity_type_id', $entityTypeId)

8

@marius,关于编码标准(列表中的第24点)。

我喜欢将PHP_CodeSnifferEQP ECG CS 一起使用以自动执行这些标准。

使用PHP_CodeSniffer,您不必担心忘记诸如替换array()[],避免使用is_null,保留未使用的局部变量甚至没有PHPDoc块的方法之类的东西。

PHP_CodeSniffer总是会告诉您。



我认为无法在PHPStorm中配置两个CS(对于那些使用PHPStorm的用户),但是您始终可以使用终端在代码中检查CS。也有一些工具,例如grumphp github.com/phpro/grumphp有所帮助。
diazwatson

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.