Magento 2创建shell脚本
Magento 2创建shell脚本
shell脚本是在Magento中快速运行维护命令的好方法。在Magento 2中,shell脚本通过命令行执行
php bin/magento
背景
Magento CLI在MagentoFrameworkConsoleCli类中定义,这是一个Symphony Application。应用程序从Symphony application中定义的运行命令开始运行,该命令执行初始配置,例如将输入设置为控制台输入,将输出设置为控制台。一旦初始化完成,应用程序doRun()方法就会被调用。此方法执行以下步骤:
-
检查是否传递了版本参数以显示版本信息。
-
如果没有请求版本信息,脚本将检索命令名。
-
检查是否传递了帮助参数,如果是,则将命令名设置为“帮助”。
-
如果没有请求帮助信息,也没有传递命令,则命令名将设置为应用程序默认命令,在Magento 2中,该命令将列出可用的命令。
-
接下来,它在已注册命令列表中查找该命令。
-
最后,它执行命令并返回退出代码。
开始编码
在编写与类别交互的扩展时,最好运行Magento测试框架提供的Catalog测试,以确保没有中断Magento功能。运行这些测试的缺点是会产生大量的测试类别和产品,从而影响系统的性能,有时无法继续开发和测试。在本文中,我们将构建一个命令行工具来清理测试框架生成的测试类别。因此,不需要恢复数据库,在开发期间重新运行测试就更容易了。为了本文的目的,调用脚本的命令将是catalog:category:clean,即在执行以下控制台命令时将调用我们的命令
php bin/magento catalog:category:clean
1.创建命令类
该命令通过扩展SymphonyCommand类的类来处理。创建类后,需要配置类并将其绑定到命令。catalog:category:clean。这是通过将类名属性设置为我们的命令并调用SymphonyCommand配置()方法来完成的。
class CatalogCleanCommand extends Command
{
protected function configure()
{
$this->setName('catalog:category:clean')
->setDescription('Cleans the catalog from extra categories (ending with more than 4 numbers');
parent::configure();
}
}
在本文中,我们将类放置在名称空间ClanceCommandConsoleCommand下。
2.使用CLI工具注册类
当我们调用命令来清理类别时,称为CLI应用程序的doRun将获取需要执行该命令的类。这是通过在di.xml文件中注册我们的类来处理的,如下所示:
// di.xml
- ClounceCommandsConsoleCommandCatalogCleanCommand
注意,项目名是一个任意名称,但是,将命令项命名为与没有冒号分隔符的命令名相同并在末尾附加工作‘Command’是Magento的最佳实践。
2.1检查该班是否已适当注册
现在我们已经创建了命令类,并且已经在di.xml中注册了它,我们可以检查命令是否已注册。若要从命令行执行此操作,请运行命令
php bin/magento
这将加载可用命令的列表,如果所有命令都已正确设置,则我们的命令应该显示在列表中。

图1:CLI命令清单
图1显示了列表中的新命令,其中包含指定的描述。注意,第一个冒号之前的单词用于分组。这是由SymphonyApplication类自动完成的。
3.处理命令
立即运行命令,返回图2中的错误。

图2:缺少EXECUTE()函数
3.1初始化对象管理器
在使用命令执行任何有用的操作之前,我们需要初始化对象管理器。这是Magento中用于初始化类的基类。为了本文的目的,将使用Admin范围初始化对象管理器。
/**
* Constructor
*
* @param ObjectManagerFactory $objectManagerFactory
*/
public function __construct(
ObjectManagerFactory $objectManagerFactory
){
$params = $_SERVER;
$params[StoreManager::PARAM_RUN_CODE] = 'admin';
$params[StoreManager::PARAM_RUN_TYPE] = 'store';
$this->objectManager = $objectManagerFactory->create($params);
parent::__construct();
}
3.2定义命令执行
既然有了对象管理器,就可以实现该命令了。首先重写execute()方法,并将一些信息输出到控制台,以便用户知道该命令已经找到并开始执行。
/**
* @param InputInterface $input
* @param OutputInterface $output
* @throws MagentoFrameworkExceptionLocalizedException
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Starting Category Cleanup ');
}
值得注意的是,writeln()命令可以解释一些标记来对输出进行样式化。根据SiteSymfony 2控制台组件,通过示例Symfony 2控制台组件(示例)-输出writeln()命令提供了4个标记:
-
信息-将所附文本更改为绿色。
-
注释-将所附文本更改为黄色
-
问题-在青色背景上以黑色显示所附文字。
-
错误-文本显示在红色背景上,白色文本颜色。

图3:控制台输出标记
3.2.1获取类别集合
本文中的示例将清理由测试框架创建的类别。要获得类别,需要创建类别集合。使用对象管理器,我们获得类别集合,如下所示。
/** @var MagentoCatalogModelResourceModelCategoryCollectionFactory $categoryCollectionFactory */
$categoryCollectiOnFactory= $this->objectManager->get('MagentoCatalogModelResourceModelCategoryCollectionFactory');
/** @var MagentoCatalogModelResourceModelCategoryCollection $categoryCollection */
$categoryCollection = $categoryCollectionFactory->create();
$categoryCollection->addAttributeToSelect('name');
注意,我们已经将‘name’属性添加到集合中。在Magento 2中,Eav集合不会自动向集合添加自定义属性。
3.2.2删除测试类别
获得类别集合后,可以识别和删除测试类别。通过对所创建的测试数据的快速分析,测试框架创建的类别最终都有一个通常为8位或更长的数字序列。为了简单起见,我们的命令将删除末尾至少有4个字符的任何类别。
/** @var MagentoCatalogModelCategory $category */
foreach ($categoryCollection as $category) {
if (preg_match('/\d{4,}$/', $category->getName()) == 1) {
$output->writeln('Deleting Cateogry with Name: "'. $category->getName() . '" ');
$category->delete();
}
}
注意,虽然我们的集合只定义了属性名,但它仍然返回一个类别对象。但是,类别对象将只具有catalog_category_entity表和name属性。这足以允许在定义类别ID时删除类别。
当我们试图运行代码时,会出现一个错误,即不允许使用Delete操作。发生此错误的原因是类别模型要求只从安全区域执行删除操作。

图4:禁止操作
3.2.3设置安全区
看着RemoveAction功能,注意到执行了检查以确保从安全区域调用操作。因为我们打算从命令行中删除这些类别,所以我们需要将脚本设置为在安全区域中运行。这是通过设置isSecureArea在登记处。
/**
* @var MagentoFrameworkRegistry
*/
$registry = $this->objectManager->get('MagentoFrameworkRegistry');
$registry->register('isSecureArea', true);
既然脚本已被标记为安全,则可以执行命令并删除类别。

图5:代码执行
全部代码
php
/**
* Copyright © 2015 Clounce. All rights reserved.
* See COPYING.txt for license details.
*/
namespace ClounceCommandsConsoleCommand;
use MagentoFrameworkAppObjectManagerConfigLoader;
use MagentoFrameworkAppObjectManagerFactory;
use MagentoFrameworkAppState;
use MagentoStoreModelStoreManager;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
class CatalogCleanCommand extends Command
{
/**
* @var MagentoFrameworkObjectManagerInterface
*/
protected $objectManager;
/**
* Constructor
*
* @param ObjectManagerFactory $objectManagerFactory
*/
public function __construct(
ObjectManagerFactory $objectManagerFactory
){
$params = $_SERVER;
$params[StoreManager::PARAM_RUN_CODE] = 'admin';
$params[StoreManager::PARAM_RUN_TYPE] = 'store';
$this->objectManager = $objectManagerFactory->create($params);
parent::__construct();
}
protected function configure()
{
$this->setName('catalog:category:clean')
->setDescription('Cleans the catalog from extra categories (ending with more than 4 numbers');
parent::configure();
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @throws MagentoFrameworkExceptionLocalizedException
* @return null|int null or 0 if everything went fine, or an error code
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Starting Category Cleanup ');
/**
* @var MagentoFrameworkRegistry
*/
$registry = $this->objectManager->get('MagentoFrameworkRegistry');
$registry->register('isSecureArea', true);
/** @var MagentoCatalogModelResourceModelCategoryCollectionFactory $categoryCollectionFactory */
$categoryCollectionFactory = $this->objectManager->get('MagentoCatalogModelResourceModelCategoryCollectionFactory');
/** @var MagentoCatalogModelResourceModelCategoryCollection $categoryCollection */
$categoryCollection = $categoryCollectionFactory->create();
$categoryCollection->addAttributeToSelect('name');
/** @var MagentoCatalogModelCategory $category */
foreach ($categoryCollection as $category) {
if (preg_match('/\d{4,}$/', $category->getName()) == 1) {
$output->writeln('Deleting Category with Name: "' . $category->getName() . '"');
$category->delete();
}
}
$output->writeln('Categories Cleaned ');
return 0;
}
}
