CakePHP 3.x在Shell中使用控制器方法
问题描述:
我想在我的应用程序中做后台电子邮件发送。CakePHP 3.x在Shell中使用控制器方法
我正在制作一个shell,我最终将安排通过crontask来运行。
我试图跑在我的EmailShell下面的代码:
<?php
namespace App\Shell;
use Cake\Console\Shell;
use Cake\Core\App;
App::import('Controller', 'Messages');
class EmailShell extends Shell{
public function main(){
//Check for unsent emails
$messagesCont = new MessagesController;
$messages = $messagesCont->findAllUnsent();
//Send all unsent emails
foreach ($messages as $message){
$email = new Email();
$email->to($messages->receiver)
->subject($message->subject)
->send($message->body);
}
//Update the table to be marked as sent
}
}
?>
,我从MessagesController需要的代码是这样的:
public function findAllUnsent(){
$messages = $this->paginate($this->Messages);
foreach ($messages as $message){
if ($message->sent == false){
//If message is unsent then add it to the array
$messagesFound[] = $message;
}
}
//Return the array of unsent messages
return $messagesFound;
}
}
然而,当我通过运行shell命令行终端使用bin/cake email
我收到以下错误:
Exception: Call to undefined method Cake\Core\App::import() in [/home/cabox/workspace/src/Shell/EmailShell.php, line 7]
答
正如在the answer中指出的那样,在注释中链接的问题中,根本不应该在shell中使用控制器。该代码应该放在你的模型中,例如在查找器中,或者只是一个普通的类方法。
还应该注意的是,paginator的使用与方法名称相矛盾,方法名称为“find all”,但paginator默认只会查找最多20条记录。此外,我建议过滤SQL级别的记录,以便您只接收实际需要的记录,之后减少它们将打破分页,因为它使用为原始结果计算的数字进行操作。
所以在你MessagesTable
类添加例如自定义查找,如:
public function findUnsent(\Cake\ORM\Query $query, array $options)
{
return $query->where([
$this->aliasField('sent') => false
]);
}
而在你的shell中使用的模型,如:
class EmailShell extends Shell
{
use Cake\ORM\Locator\LocatorAwareTrait;
public function main()
{
// tableLocator() before CakePHP 3.5
$MessagesTable = $this->getTableLocator()->get('Messages');
$unsentMessages = $MessagesTable->find('unsent');
foreach ($unsentMessages as $message) {
// ...
}
}
}
相若方式
你会使用取景器中,然后您的控制器也是这样,并将查询传递给paginate()
方法。
顺便说一句,没有App::import()
了,CakePHP 3.x现在使用Composer自动加载,那个调用应该会触发一个错误。
又见
- Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Using Finders to Load Data
- Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Custom Finder Methods
- API > \Cake\ORM\Locator\LocatorAwareTrait
- Cookbook > Controllers > Components > Pagination > Using Controller::paginate()
https://stackoverflow.com/questions/28511023/how-to-load-a-component-in-console-shell取代组件与控制器和答案是完全一样的。可以标记为它的副本。 – burzum
@burzum那么你会如何建议在后台做电子邮件?没有任何资源可以做到这一点,我正努力为CakePHP 3.x找到详细的最新指南。 –