doubanduo7620 2017-09-16 08:11
浏览 33

CakePHP 3.x在Shell中使用控制器方法

I am trying to do background email sending in my application.

I am making a shell that I will eventually schedule to be run through a crontask.

I am trying to run the following code in my 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
    }   
}
?>

The code that I need from the MessagesController is as such:

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

However when I run the shell through the command line terminal using bin/cake email

I get the following error:

Exception: Call to undefined method Cake\Core\App::import() in [/home/cabox/workspace/src/Shell/EmailShell.php, line 7]

  • 写回答

1条回答 默认 最新

  • doude4924 2017-09-16 13:12
    关注

    As pointed out in the answer to the question linked in the comments, you shouldn't use a controller in your shell at all. That code should be in your model, for example in a finder, or just a regular class method.

    It should also be noted that the use of the paginator contradicts the method name, which says "find all", the paginator however will by default find only a maximum of 20 records. Also I'd suggest to filter the records on SQL level instead, so that you only receive those records that you actually need, reducing them afterwards will break the pagination, as it operates with the numbers calculated for the original result.

    So in your MessagesTable class add for example a custom finder like:

    public function findUnsent(\Cake\ORM\Query $query, array $options)
    {
        return $query->where([
            $this->aliasField('sent') => false
        ]);
    }
    

    And in your shell use the model, like:

    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) {
                // ...
            }
        }   
    }
    

    Similarily you'd use the finder then in your controller too, and pass a query to the paginate() method instead.

    btw, there is no App::import() anymore, CakePHP 3.x uses Composer autoloading now, that call there should trigger an error.

    See also

    评论

报告相同问题?

悬赏问题

  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 个人网站被恶意大量访问,怎么办
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大