系统学习magento二次开发,推荐小册:《Magento中文全栈二次开发 》
本小册面向Magento2以上版本,书代码及示例兼容magento2.0-2.4版本。涵盖了magento前端开发,后端开发,magento2主题,magento2重写,magento2 layout,magento2控制器,magento2 block等相关内容,带领您成为magento开发技术专家。
本文是解释Magento 2的对象管理器/依赖注入系统的系列文章中的第一篇。我们将探讨程序员(你!)如何在Magento 2中创建对象,探索Magento 2的对象系统带来的其他功能,在此过程中,我们将讨论Magento 1的变化,并开始探索Magento 2的约定。
### Magento 2命令行框架
Magento 2的架构转变带来的重大变化之一是命令行框架。这不是Magento 1中的简单框架(在我的短书No Frills Command Line Magento中讨论过)。相反,Magento 2附带了Symfony控制台组件的完整实现。
安装 Magento 2 后,您可以通过打开终端应用程序并键入以下命令来查看系统附带的默认命令列表。
$ php bin/magento
您应该看到如下所示的输出。
Magento CLI version 0.74.0-beta16 Usage: command [options] [arguments] Options: --help (-h) Display this help message --quiet (-q) Do not output any message --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug --version (-V) Display this application version --ansi Force ANSI output --no-ansi Disable ANSI output --no-interaction (-n) Do not ask any interactive question Available commands: help Displays help for a command list Lists commands //... full command list snipped ...
除了附带许多有用的命令外,第三方开发人员还可以创建Magento模块,向系统添加新命令。
在本教程中,我们将使用命令行框架来运行代码示例。命令行是一个很好的干净的地方,可以运行示例代码,观察输出,并且无需担心浏览器页面加载和Magento代码运行之间的抽象层和层。
### 安装教程示例代码
我们准备了一个Magento 2模块,其中包含一个简单的命令行界面(cli)命令。Magento 2模块安装的方法和原因仍在到位,所以现在我们最好的选择是手动安装这个模块。
我们已将模块源代码放在 GitHub 上。此模块将添加一个名为 的命令,我们将在下面使用它。安装此模块ps:tutorial-object-manager-1
### 导航到 GitHub 发布页面
找到最新版本(编写本教程时的 0.0.3 现在是 0.0.4),然后单击 或 链接下载版本存档ziptar.gz
将存档源提取到Magento 2安装中,与文件夹结构匹配app
您现在应该能够从Magento安装的根目录运行以下命令,并查看模块的顶级文件。lsPulsestorm_TutorialObjectManager1
$ ls -l app/code/Pulsestorm/TutorialObjectManager1/ total 0 drwxr-xr-x@ 4 alanstorm staff 136 Jul 9 08:49 Command drwxr-xr-x@ 3 alanstorm staff 102 Jul 9 08:49 Model drwxr-xr-x@ 4 alanstorm staff 136 Jul 9 08:49 etc
您还可以通过运行以下命令来检查模块是否已正确安装module:status
$ php bin/magento module:status List of enabled modules: Magento_Store //...
如果已将模块正确解压缩到文件夹中,则在运行 时应看到类似于上述的输出。不过,眼尖的读者会注意到一个问题——虽然存在,但它被列为禁用模块。我们需要告诉Magento 2此模块已启用。app/codemodule:statusPulsestorm_TutorialObjectManager1
为此,我们需要编辑文件。在您喜欢的文本编辑器中打开此文件并查找以下部分app/etc/config.php
#File: app/etc/config.php <?php return array ( 'modules' => array ( 'Magento_Store' => 1, //... full module list snipped ... 'Magento_Wishlist' => 1, ), );
该文件是一个简单的 PHP 包含文件,返回已配置模块的数组。您看到的模块是系统附带的核心模块。我们希望将模块添加到此列表的末尾。app/etc/config.php
#File: app/etc/config.php <?php return array ( 'modules' => array ( 'Magento_Store' => 1, //... full module list snipped ... 'Magento_Wishlist' => 1, 'Pulsestorm_TutorialObjectManager1' => 1 ), );
现在如果我们运行 ,我们应该看到我们的模块列在启用列表中。module:status
$ php bin/magento module:status List of enabled modules: Magento_Store //... Pulsestorm_TutorialObjectManager1 List of disabled modules: None
与Magento 1相同,模块的全名来自其“命名空间”文件夹和“模块名称”文件夹的组合。但是,这里有一些事情可能会让Magento 1开发人员陷入循环。具体说来
Magento的模块命名空间现在代替了Magento_Mage_
和代码池消失了。所有模块都位于corecommunitylocalapp/code
核心团队已将“模块声明文件”替换为更简单的基于 PHP 的配置app/etc/modules
在我看来,要更改是中立的,但是删除代码池和模块声明文件对Magento来说是积极的。MagentoMage
虽然、、和代码池/包含文件夹允许系统所有者通过代码池覆盖对Magento功能进行快速更改,但这些文件在很大程度上导致了商家不愿意升级他们的系统,并且当开发人员更改过多的类文件的隐式契约时,通常会导致微妙的系统问题。corecommunitylocal
模块声明文件的丢失 - 虽然是一个有趣的想法(整个系统的一个全局配置)的一部分 - 不会被错过。虽然这些文件的初衷可能是配置哪些模块应该或不应该在系统中启用,但早期开发人员的布道和核心团队实践不佳意味着扩展开发人员开始将这些文件与他们的扩展打包在一起,并且任何希望这些文件是用户可配置的文件都消失了。简单的开/关配置阵列的Magento 2方法更有意义。app/etc/modules
### 运行命令和清除缓存
好的,现在我们已经安装了模块,我们要确保显示新命令。在我们这样做之前,还有一步要做。我们需要清除Magento的缓存。ps:tutorial-object-manager-1
从概念上讲,Magento 2中的缓存清除与Magento 1相同。有长时间运行的操作将运行一次,然后Magento缓存结果以便下次更快地加载。例如,虽然我们已经将新模块添加到Magento的配置中,但Magento的配置是缓存的,因此正在运行的系统实际上还不知道我们的模块。
Magento 2提供了一个用于清除缓存的cli命令。只需运行以下内容,您应该就可以开始了。
$ php bin/magento cache:clean Cleaned cache types: config layout block_html view_files_fallback view_files_preprocessing collections db_ddl eav full_page translate config_integration config_integration_api config_webservice
我们说应该,因为尽管这将清除Magento的所有缓存类型,但这并不是100%清楚这是否会清除整个缓存。Magento 1包含许多非类型的缓存条目(例如Zend的模块列名称),Magento 1的缓存清除命令不会删除这些条目。Magento 2对于我们来说还太年轻,无法发现这些边缘情况,但是如果您不确定Magento的缓存是否被清除并且使用的是默认缓存存储,则可以通过手动删除Magento文件夹中的所有文件和文件夹来取消整个缓存。var/cache
$ rm -rf /path/to/magento/var/cache/*
此外,虽然它与我们在这里无关,但Magento 2也使用了一些自动代码生成功能,虽然不是严格的缓存,但如果某些系统配置或代码文件被更改/更新,则可能需要重新生成。如果要清除缓存,最好清除这些生成的代码文件。在开发计算机上执行此操作的最快和最简单的方法是删除
$ rm -rf /path/to/magento/var/generation/*
对于生产系统,您需要小心执行此操作。Magento 2仍然足够新,以至于代码生成的所有陷阱尚未被发现。
假设您已经清除了缓存,让我们寻找我们的命令。您可以使用命令查看命令列表list
$ php bin/magento list //... ps:tutorial-object-manager-1 A cli playground for testing commands //...
假设您看到上面的命令,让我们尝试运行它!
$ php bin/magento ps:tutorial-object-manager-1 You did it!
祝贺!您只需手动安装第一个Magento模块。
更新:Kristof Ringleff指出,实际上有两个命令可以启用/禁用Magento 2模块(和)。在设置新模块时,您肯定希望使用这些命令module:enablemodule:disable
$ php bin/magento module:enable Pulsestorm_TutorialObjectManager1 - Pulsestorm_TutorialObjectManager1 To make sure that the enabled modules are properly registered, run 'setup:upgrade'. Cache cleared successfully. Generated classes cleared successfully. Alert: Generated static view files were not cleared. You can clear them using the --clear-static-content option. Failure to clear static view files might cause display issues in the Admin and storefront.
/ 命令的好处是他们会module:enablemodule:disable
### 自动为您清除缓存
自动为您删除生成的旧代码
通知您可能需要执行的其他操作
允许您启用/禁用模块,即使用于启用/禁用模块的内部方法发生变化
更改我们的命令
我们几乎准备好开始讨论对象管理器了。现在我们已经安装了示例模块,让我们尝试更改 的实现。ps:tutorial-object-manager-1
Magento 2中的每个cli命令都是用PHP类实现的。要更改命令的实现,您需要做的就是在您喜欢的文本编辑器中打开此类文件。尝试打开以下文件,并找到执行方法
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("You did it!"); }
然后,编辑命令定义文件,使其如下所示
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("Hello World!"); }
如果我们现在尝试运行该命令,我们应该看到以下输出。
$ php bin/magento ps:tutorial-object-manager-1 Hello World!
我们上面所做的只是将一条消息传递给命令行框架的方法——这是框架的等价物 or 。writelnechoprint
完成此操作后,我们终于可以开始讨论Magento的对象管理器了。
首先,让我们回顾一些 PHP 101。当您想在 PHP 中实例化对象时,请使用关键字。让我们在我们的方法中尝试一下newexecute
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $object = new \Pulsestorm\TutorialObjectManager1\Model\Example; $message = $object->getHelloMessage(); $output->writeln( $message ); }
尝试运行上面的代码,你应该看到这样的内容
$ php bin/magento ps:tutorial-object-manager-1 Hello Magento!
我们上面所做的只是
从类实例化对象Pulsestorm\TutorialObjectManager1\Model\Example
调用结果对象的方法以获取消息字符串,getHelloWorld
使用命令行框架的方法输出消息。writeln
到目前为止,这是普通的旧 PHP — 如果您不熟悉 PHP 命名空间或那些反斜杠字符,您可能会发现这个命名空间入门很有用。
没有什么能阻止你在Magento 2中使用普通的旧PHP类。但是,如果你想利用Magento 2的高级对象功能(自动构造函数依赖注入,对象代理等),你需要使用Magento的对象管理器。尝试以下代码
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $manager = $this->getObjectManager(); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $message = $object->getHelloMessage(); $output->writeln( $message ); }
运行上面的代码,你应该看到相同的输出
$ php bin/magento ps:tutorial-object-manager-1 Hello Magento!
这个新代码和我们的旧代码之间的最大区别在于这两行
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $manager = $this->getObjectManager(); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example');
第一个,,为我们获取对象管理器。这不是您在编写Magento 2扩展时通常会做的事情 - 这是我们为本教程添加的帮助程序方法。我们稍后会回到这个概念,但现在接受 将返回 Magento 对象管理器的实例。$manager = $this->getObjectManager();getObjectManagergetObjectManager
对象管理器是一个特殊的对象,Magento用它来实例化几乎所有的对象。这就是我们在第二行所做的
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example');
我们调用了对象管理器的方法,并以字符串形式传入 PHP 类名。在后台,对象管理器为我们实例化了一个。createPulsestorm\TutorialObjectManager1\Model\Example
最简单的形式就是Magento 2的对象管理器。这似乎是一个微不足道的差异,但是通过这个单一点路由所有对象实例化,Magento系统工程师能够赋予他们的对象许多“超能力”。
在我们讨论超能力之前,虽然完全介绍它超出了本文的范围,但Magento对象管理器的源代码在下面的类文件中。
#File: lib/internal/Magento/Framework/ObjectManager/ObjectManager.php namespace Magento\Framework\ObjectManager; class ObjectManager implements \Magento\Framework\ObjectManagerInterface { //... }
如果您是Magento 1开发人员,则对象管理器可以替代这三种方法。
Mage::getModel(...); Mage::helper(...); Mage::getSingleton('core/layout')->createBlock(...);
虽然Magento 2仍然具有模型,帮助程序和块的概念,但您不再需要知道这些对象的类别名(,等)。对象管理器可以实例化任何PHP类,而不仅仅是模型,帮助程序或块对象。core/templatemodel/product
### 自动单例对象
我们今天将通过讨论Magento的对象管理器赋予对象的超能力之一来结束 - 自动单例。不过,在我们这样做之前,我们可能应该描述一下我们所说的单例是什么意思!
尝试运行以下代码
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $manager = $this->getObjectManager(); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $object->message = 'Hello PHP!'; $output->writeln( $object->getHelloMessage() ); $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $output->writeln( $object->getHelloMessage() ); }
你应该看到这样的输出
$ php bin/magento ps:tutorial-object-manager-1 Hello PHP! Hello Magento!
此代码类似于我们之前的示例,但增加了一些内容。首先,我们使用对象管理器从类中实例化一个对象。Pulsestorm\TutorialObjectManager1\Model\Example
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example');
然后我们为对象设置一个自定义消息字符串
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object->message = 'Hello PHP';
然后我们使用 cli 框架的方法输出新消息。writeln
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $output->writeln( $object->getHelloMessage() );
这是第一段代码。在第二个代码块中
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php $object = $manager->create('Pulsestorm\TutorialObjectManager1\Model\Example'); $output->writeln( $object->getHelloMessage() );
我们实例化了一个新对象,然后输出其默认消息。这意味着我们的程序输出Pulsestorm\TutorialObjectManager1\Model\Example
Hello PHP! Hello Magento!
是自定义消息,后跟默认消息。
非常简单的东西。
现在,让我们尝试完全相同的代码,只是我们将使用对象管理器的方法,而不是使用对象管理器的方法createget
#File: app/code/Pulsestorm/TutorialObjectManager1/Command/Testbed.php protected function execute(InputInterface $input, OutputInterface $output) { $manager = $this->getObjectManager(); $object = $manager->get('Pulsestorm\TutorialObjectManager1\Model\Example'); $object->message = 'Hello PHP!'; $output->writeln( $object->getHelloMessage() ); $object = $manager->get('Pulsestorm\TutorialObjectManager1\Model\Example'); $output->writeln( $object->getHelloMessage() ); } Run this code, and your output will be a little different. $ php bin/magento ps:tutorial-object-manager-1 Hello PHP Hello PHP
我们的程序没有第二次打印默认消息,而是打印了我们在第一个对象上设置的相同自定义消息。为什么会这样?因为第二个对象是第一个对象。
这是Magento对象管理器的“自动单例”功能。如果您不熟悉这个概念,单例是一个只能实例化一次的对象。使用单例,将来实例化同一对象的尝试将返回原始实例。传统上,这是通过向类的构造函数添加特殊代码来实现的,但是使用Magento 2的对象管理器,任何类都可以转换为单例对象。
将返回上面的代码示例,第二次调用Magento时,我们返回了带有自定义消息集的原始对象。get
如果你来自Magento 1,/差异类似于createget
Mage::getModel(...); Mage::getSingleton(...);
差异。同样,这适用于Magento 2中的所有类和对象,而不仅仅是模型对象。
自动单例只是Magento 2的对象管理器赋予其对象的超能力之一。下次我们将讨论巨大的超能力 - 自动构造函数参数依赖注入 - 我们还将揭示为什么Magento的文档(看似矛盾)告诉你不要使用对象管理器。