如何在控制台/外壳中加载组件



在CakePHP中,如何在shell中加载组件?

若要在控制器中使用组件,请在名为$components的属性中包含一组组件。这对我的Shell不起作用。文档中建议的"动态"加载也没有。

class MakePdfsShell extends Shell {
    public $components = array('Document'); // <- this doesn't work
    public function main()
    {
        $this->Document = $this->Components->load('Document'); // <- this doesnt work either
        $this->Document->generate(); // <- this is what I want to do
    }
    ...

我在一些控制器中使用了一些xml实用程序。其中一个控制器通过cake控制台启动一个繁重的任务,这样它就可以通过PHP CLI在后台安静地运行,而用户的请求立即完成(一旦任务完成,它就会通过电子邮件将结果发送给用户)。

xml实用程序足够通用,可以在控制器和shell中使用,对于应用程序来说太特殊,无法保证它们的供应商状态。提供的带有Lib文件夹的解决方案不起作用,因为在CakePhp v3中似乎没有Lib文件夹。

经过一段相当长的时间,我设法将控制器组件加载到shell任务中。以下是如何:

namespace AppShell;
use CakeConsoleShell;
use CakeCoreApp;
use CakeControllerComponent;
use CakeControllerComponentRegistry;
use AppControllerComponentXmlUtilitiesComponent;   // <- resides in your app's src/Controller/Component folder
class XmlCheckShell extends Shell
{
    public function initialize() {
        $this->Utilities = new XmlUtilitiesComponent(new ComponentRegistry());
    }
...

$this->Utilities现在可以在我的整个shell类中使用。

您根本不需要

如果您认为必须在shell中加载组件,那么您的应用程序体系结构设计不好,应该进行重构。

从技术上讲,这是可能的,但没有意义,可能会产生相当严重的副作用。组件不会在请求范围之外运行。组件被认为是在HTTP请求和控制器的范围内运行的——这显然不存在于shell中。

把东西放在正确的地方

为什么XML操作的东西必须进入组件?这简直是个错误的地方。这应该进入一个类,例如AppUtilityXmlUtils,并且与请求和控制器都没有任何依赖关系。

然后,逻辑被适当地解耦,可以在其他需要它的地方使用。此外,如果你得到了传入的XML,那么(通过使用实用程序类)进行此操作的正确位置将在模型层内,而不是控制器内。

您想了解关注点分离和紧密耦合

因为你违背了这两个原则。

  • https://en.wikipedia.org/wiki/Separation_of_concerns
  • 在面向对象的范例中,松耦合和紧耦合之间有什么区别

询问前搜索

你可以尝试通过谷歌或在SO上搜索,你会发现其中一个:

  • 在Cakephp2+Shell中使用组件
  • 使用Shell cronjob中的电子邮件组件的CakePHP
  • 在cakehp2.0.2中使用shell类中的插件组件

请注意,他们中的一些人可能会鼓励不良行为。我还没有全部检查。

我假设您有一个名为YourComponent:的组件

<?php
App::uses('Component', 'Controller');
class YourComponent extends Component {
    public function testMe() {
        return 'success';
    }
}

-使用蛋糕2。,您可以像这样加载组件

App::uses('ComponentCollection', 'Controller');
App::uses('YourComponent', 'Controller/Component');
class YourShell extends AppShell {
    public function startup() {
        $collection = new ComponentCollection();
        $this->yourComponent = $collection->load('Your');
    }
    public function main() {
        $this->yourComponent->testMe();
    }
}

-使用蛋糕3。您可以这样加载组件

<?php
namespace AppShell;

use AppControllerComponentYourComponent;
use CakeConsoleShell;
use CakeControllerComponentRegistry;
class YourShell extends Shell {
    public function initialize() {
        parent::initialize();
        $this->yourComponent = new YourComponent(new ComponentRegistry(), []);
    }
    public function main() {
        $pages = $this->yourComponent->testMe();
    }
}

如果您正试图从shell访问自定义XyzComponent,那么您可能在那里拥有常用的功能。常用功能(也可以从shell访问)的正确位置是/Lib/

您可以将旧的XyzComponent类从/Controller/Component/XyzComponent.php移动到/Lib/Xyz/Xyz.php。(您应该重命名您的类以删除"Component"后缀,例如,"XyzComponent"变为"Xyz"。)

要访问新位置,请在控制器中,从class::$components阵列中删除"Xyz"。在控制器文件的顶部,添加

App::uses('Xyz', 'Xyz'); // that's ('ClassName', 'folder_under_/Lib/')

现在您只需要实例化该类。在您的方法中,您可以执行$this->Xyz = new Xyz();。现在您使用相同的代码,但也可以从Shell访问它。

//TestShell.php

class TestShell extends AppShell{
    public function test(){
        //to load a component in dis function
     App::import('Component', 'CsvImporter');
     $CsvImporter = new CsvImporterComponent();
     $data = $CsvImporter->get();
    }
}

//CsvImporterComponent.php

App::uses('Component', 'Controller');
class CsvImporterComponent extends Component {
    function get(){
    //your code
    }
}

最新更新