Cakephp在通过CakeEmail发送电子邮件后没有重定向

时间:2015-06-02 16:59:27

标签: php email cakephp redirect

在CakePHP 2.X中,对于我的一个控制器操作,每次创建新记录时,我都会尝试向所有用户发送电子邮件。

更新了drmonkeyninja的建议:

// NewslettersContoller.php

public function add() {
  if($this->request->is('post')) {
    $this->Newsletter->create();

  if($this->Newsletter->save($this->request->data)) {
      $this->Session->setFlash(__('Your newsletter has been submited.'));
      $this->redirect(array('action' => 'view', $this->Newsletter->id));
  }
  else {
      $this->Session->setFlash(__('Unable to add your post.'));
      return $this->redirect(array('action' => 'add'));
  }
 }
}

// Newsletter.php
public function afterSave($created, $options = []) {
  parent::afterSave($created, $options);
  if ($created === true) {
    $newsletter = $this->findById($this->id);

    // Get all users with an email address.
    $emails = ClassRegistry::init('User')->find(
        'list',
        array(
            'fields' => array(
                'User.id',
                'User.email'
            ),
            'conditions' => array(
                'User.email <>' => null
            )
        )
    );

    $Email = new CakeEmail('gmail');
    $Email->from(array('me@example.com' => 'Caprock Portal'));
    $Email->to($emails);
    $Email->subject($newsletter['Newsletter']['title']);
    $Email->message($newsletter['Newsletter']['content']);
    try {
       $Email->send();
    } catch (Exception $exception) {
        $this->log($exception);
    }
  }
}

正如您从代码片段中看到的,我使用CakeEmail向每个用户发送包含在操作中创建的简报的电子邮件。不幸的是,由于某些原因,每次CakeEmail完成发送电子邮件时,CakePHP都会忽略我的重定向请求并继续呈现空白视图(路径仍在添加)。我已经通过评论并验证重定向开始再次运行来验证它是CakeEmail函数。 try-catch块中没有捕获任何内容。

我对此问题原因的一个假设是电子邮件标头干扰了我的操作的重定向标头。我通过浏览器检查了网络请求,但似乎没有发送任何内容,除了从添加功能的原始发布请求。

4 个答案:

答案 0 :(得分:2)

最好通过afterSave()回调中的简报模型发送电子邮件: -

// app/Model/Newsletter.php

App::uses('CakeEmail', 'Network/Email');

public function afterSave($created, $options = []) {
    parent::afterSave($created, $options);
    if ($created === true) {
        $newsletter = $this->findById($this->id);

        // Get all users with an email address.
        $emails = ClassRegistry::init('User')->find(
            'list',
            array(
                'fields' => array(
                    'User.id',
                    'User.email'
                ),
                'conditions' => array(
                    'User.email <>' => null
                )
            )
        );

        $Email = new CakeEmail('gmail');
        $Email->from(array('me@example.com' => 'Caprock Portal'));
        $Email->to($emails);
        $Email->subject($newsletter['Newsletter']['title']);
        $Email->message($newsletter['Newsletter']['content']);
        try {
           $Email->send();
        } catch (Exception $exception) {
            $this->log($exception);
        }
    }
}

您的控制器操作就是: -

// app/Controller/NewslettersController.php
public function add() {
    if ($this->request->is('post')) {
        $this->Newsletter->create();
        if ($this->Newsletter->save($this->request->data)) {
            return $this->redirect(array('action' => 'view', $this->Newsletter->id));
        } else {
            $this->Session->setFlash(__('Unable to add your post.'));
            return $this->redirect(array('action' => 'add'));
        }
    }
}

如果视图仍未呈现,则暂时禁用afterSave()回调,以在保存简报时检查代码的Controller部分是否按预期工作。

请注意,从数据库中检索用户时,可以过滤掉没有电子邮件地址的用户。使用find('list'),您不需要使用foreach循环。

您也不需要使用$this->Newsletter->getLastInsertId();,因为$this->Newsletter->id应该在保存时设置为此。

Cake的debug()方法最好在调试变量时使用,而不是var_dump(),这在你的例子中不会起作用,因为你在输出后会重定向!

答案 1 :(得分:0)

您也可以尝试在url数组中指定控制器:

if($Email->send()) {
    return $this->redirect(
            array('controller' => 'controller_name', 'action' => 'view', $id)
        );
} else  {
    return $this->redirect(
            array('controller' => 'controller_name', 'action' => 'add')
        );
}        

答案 2 :(得分:0)

删除var_dump。如果您在内容已经发送后尝试发送标题信息(用于重定向),它会中断HTTP协议。

答案 3 :(得分:0)

另一种方法是使用Cronjob以Shell / Console的形式发送电子邮件。

这是本书的链接,您可以在其中找到有关创建shell的大量信息。

CakePHP 3.x http://book.cakephp.org/3.0/en/console-and-shells.html

CakePHP 2.x. http://book.cakephp.org/2.0/en/console-and-shells.html

这可以消除阻止您的处理。如果您在控制器或型号中发送电子邮件,您的应用程序仍在等待在呈现或重定向页面之前发送电子邮件。因此,通过转移到cronjob,用户可以获得更快的体验,因为不会等待发送电子邮件。

那么你怎么知道通过shell发送什么?嗯,这取决于你的用例,但我标记需要与数据库列一起发送的记录,找到所有尚未发送的记录,标记那些找到的记录与另一个标志正在处理,数据库中的第二个标志当第一个cronjob仍在处理时,阻止两个cron任务读取和发送相同的记录。我喜欢为交易类型的电子邮件设置尽可能低的邮件cronjobs,但这可能取决于托管服务提供商及其设置。