在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
}
}