2012-02-24 62 views
4

我在SwiftMailer的最新主要版本中遇到問題,其中裝飾器插件將僅替換列表中第一個電子郵件地址的郵件中的佔位符,然後在所有以下電子郵件中使用相同的數據 - 不管電子郵件地址。PHP和SwiftMailer:Decorator插件'卡住'第一項。

舉例來說,如果...

$replacements[[email protected]] = array('{firstname}'=>'Jeff', '{age}'=>'32'); 
$replacements[[email protected]] = array('{firstname}'=>'Mary', '{age}'=>'86'); 

第一封電子郵件可能會說...... 「嗨傑夫,你是32」。 然後第二封電子郵件應該說「嗨,瑪麗,你是86」。但相反,第二封電子郵件與第一封電子郵件相同。 任何想法?我很感謝這方面的所有幫助......謝謝。

這是我的PHP代碼

foreach ($result as $user) { 
    $replacements[$user['Email']] = array(
    '{FirstName}'=>$user['FirstName'], 
    '{LastName}'=>$user['LastName'] 
); 
} 

$mailer = Swift_Mailer::newInstance($transport); 
$decorator = new Swift_Plugins_DecoratorPlugin($replacements); 
$mailer->registerPlugin($decorator); 


$message = Swift_Message::newInstance() 
    ->setSubject('Important notice for {FirstName}') 
    ->setFrom(array('[email protected]' => 'John Doe')) 
    ->setBody(
    "Hello {FirstName}, we have reset your password to {LastName}\n" . 
    "Please log in and change it at your earliest convenience." 
) 
    ; 
foreach ($result as $user) { 
$message->setTo($user['Email']); 
} 

// Create a message 
//$template = file_get_contents('../html/full_width.html'); 
//->setBody($template, 'text/html', 'utf-8'); 
//->addPart('Dear {FirstName} {LastName},This is testing mail.', 'text/plain', 'utf-8'); 
    // Send the message 



// Pass a variable name to the send() method 
if (!$numSent=$mailer->send($message,$failures)) 
{ 
    echo "Failures:"; 
    print_r($failures); 
} 
else 
printf("Sent %d messages\n", $numSent); 

這是插件代碼

<?php 

/* 
* This file is part of SwiftMailer. 
* (c) 2004-2009 Chris Corbyn 
* 
* For the full copyright and license information, please view the LICENSE 
* file that was distributed with this source code. 
*/ 


/** 
* Allows customization of Messages on-the-fly. 
* 
* @package Swift 
* @subpackage Plugins 
* 
* @author Chris Corbyn 
* @author Fabien Potencier 
*/ 
class Swift_Plugins_DecoratorPlugin 
    implements Swift_Events_SendListener, Swift_Plugins_Decorator_Replacements 
{ 

    /** The replacement map */ 
    private $_replacements; 

    /** The body as it was before replacements */ 
    private $_orginalBody; 

    /** The original headers of the message, before replacements */ 
    private $_originalHeaders = array(); 

    /** Bodies of children before they are replaced */ 
    private $_originalChildBodies = array(); 

    /** The Message that was last replaced */ 
    private $_lastMessage; 

    /** 
    * Create a new DecoratorPlugin with $replacements. 
    * 
    * The $replacements can either be an associative array, or an implementation 
    * of {@link Swift_Plugins_Decorator_Replacements}. 
    * 
    * When using an array, it should be of the form: 
    * <code> 
    * $replacements = array(
    * "[email protected]" => array("{a}" => "b", "{c}" => "d"), 
    * "[email protected]" => array("{a}" => "x", "{c}" => "y") 
    *) 
    * </code> 
    * 
    * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, 
    * the object should return just the array of replacements for the address 
    * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. 
    * 
    * @param mixed $replacements 
    */ 
    public function __construct($replacements) 
    { 
    if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) 
    { 
     $this->_replacements = (array) $replacements; 
    } 
    else 
    { 
     $this->_replacements = $replacements; 
    } 
    } 

    /** 
    * Invoked immediately before the Message is sent. 
    * 
    * @param Swift_Events_SendEvent $evt 
    */ 
    public function beforeSendPerformed(Swift_Events_SendEvent $evt) 
    { 
    $message = $evt->getMessage(); 
    $this->_restoreMessage($message); 
    $to = array_keys($message->getTo()); 
    $address = array_shift($to); 
    if ($replacements = $this->getReplacementsFor($address)) 
    { 
     $body = $message->getBody(); 
     $search = array_keys($replacements); 
     $replace = array_values($replacements); 
     $bodyReplaced = str_replace(
     $search, $replace, $body 
     ); 
     if ($body != $bodyReplaced) 
     { 
     $this->_originalBody = $body; 
     $message->setBody($bodyReplaced); 
     } 

     foreach ($message->getHeaders()->getAll() as $header) 
     { 
     $body = $header->getFieldBodyModel(); 
     $count = 0; 
     if (is_array($body)) 
     { 
      $bodyReplaced = array(); 
      foreach ($body as $key => $value) 
      { 
      $count1 = 0; 
      $count2 = 0; 
      $key = is_string($key) ? str_replace($search, $replace, $key, $count1) : $key; 
      $value = is_string($value) ? str_replace($search, $replace, $value, $count2) : $value; 
      $bodyReplaced[$key] = $value; 

      if (!$count && ($count1 || $count2)) 
      { 
       $count = 1; 
      } 
      } 
     } 
     else 
     { 
      $bodyReplaced = str_replace($search, $replace, $body, $count); 
     } 

     if ($count) 
     { 
      $this->_originalHeaders[$header->getFieldName()] = $body; 
      $header->setFieldBodyModel($bodyReplaced); 
     } 
     } 

     $children = (array) $message->getChildren(); 
     foreach ($children as $child) 
     { 
     list($type,) = sscanf($child->getContentType(), '%[^/]/%s'); 
     if ('text' == $type) 
     { 
      $body = $child->getBody(); 
      $bodyReplaced = str_replace(
      $search, $replace, $body 
      ); 
      if ($body != $bodyReplaced) 
      { 
      $child->setBody($bodyReplaced); 
      $this->_originalChildBodies[$child->getId()] = $body; 
      } 
     } 
     } 
     $this->_lastMessage = $message; 
    } 
    } 

    /** 
    * Find a map of replacements for the address. 
    * 
    * If this plugin was provided with a delegate instance of 
    * {@link Swift_Plugins_Decorator_Replacements} then the call will be 
    * delegated to it. Otherwise, it will attempt to find the replacements 
    * from the array provided in the constructor. 
    * 
    * If no replacements can be found, an empty value (NULL) is returned. 
    * 
    * @param string $address 
    * 
    * @return array 
    */ 
    public function getReplacementsFor($address) 
    { 
    if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) 
    { 
     return $this->_replacements->getReplacementsFor($address); 
    } 
    else 
    { 
     return isset($this->_replacements[$address]) 
     ? $this->_replacements[$address] 
     : null 
     ; 
    } 
    } 

    /** 
    * Invoked immediately after the Message is sent. 
    * 
    * @param Swift_Events_SendEvent $evt 
    */ 
    public function sendPerformed(Swift_Events_SendEvent $evt) 
    { 
    $this->_restoreMessage($evt->getMessage()); 
    } 

    // -- Private methods 

    /** Restore a changed message back to its original state */ 
    private function _restoreMessage(Swift_Mime_Message $message) 
    { 
    if ($this->_lastMessage === $message) 
    { 
     if (isset($this->_originalBody)) 
     { 
     $message->setBody($this->_originalBody); 
     $this->_originalBody = null; 
     } 
     if (!empty($this->_originalHeaders)) 
     { 
     foreach ($message->getHeaders()->getAll() as $header) 
     { 
      $body = $header->getFieldBodyModel(); 
      if (array_key_exists($header->getFieldName(), $this->_originalHeaders)) 
      { 
      $header->setFieldBodyModel($this->_originalHeaders[$header->getFieldName()]); 
      } 
     } 
     $this->_originalHeaders = array(); 
     } 
     if (!empty($this->_originalChildBodies)) 
     { 
     $children = (array) $message->getChildren(); 
     foreach ($children as $child) 
     { 
      $id = $child->getId(); 
      if (array_key_exists($id, $this->_originalChildBodies)) 
      { 
      $child->setBody($this->_originalChildBodies[$id]); 
      } 
     } 
     $this->_originalChildBodies = array(); 
     } 
     $this->_lastMessage = null; 
    } 
    } 

} 

另一個相關的插件頁面

<?php 

/* 
* This file is part of SwiftMailer. 
* (c) 2004-2009 Chris Corbyn 
* 
* For the full copyright and license information, please view the LICENSE 
* file that was distributed with this source code. 
*/ 

/** 
* Allows customization of Messages on-the-fly. 
* 
* @package Swift 
* @subpackage Plugins 
* 
* @author Chris Corbyn 
*/ 
interface Swift_Plugins_Decorator_Replacements 
{ 

    /** 
    * Return the array of replacements for $address. 
    * 
    * This method is invoked once for every single recipient of a message. 
    * 
    * If no replacements can be found, an empty value (NULL) should be returned 
    * and no replacements will then be made on the message. 
    * 
    * @param string $address 
    * 
    * @return array 
    */ 
    public function getReplacementsFor($address); 

} 

參考:1. 迅速郵件插件page:http://swiftmailer.org/docs/plugins.html(Usin克裝飾插件)

  1. 涉訴在官方論壇1. https://github.com/swiftmailer/swiftmailer/issues/101

  2. 涉訴在官方論壇2. https://github.com/swiftmailer/swiftmailer/issues/161

+0

它應該是這樣的公共職能beforeSendPerformed()只調用一次。我該如何解決它?謝謝 – user782104 2012-02-24 17:03:25

回答

4

不應該send()方法被調用作爲循環的一部分?否則,你只是遍歷所有的用戶,而send()只會在用戶數組的最後一個元素上被調用。

foreach ($result as $user) { 

    $message->setTo($user['Email']); 

    // Pass a variable name to the send() method 
    if (!$numSent=$mailer->send($message,$failures)) { 
     echo "Failures:"; 
     print_r($failures); 
    } 
} 

似乎很奇怪,調用代碼負責調用beforeSendPerformed()方法,但如果是這樣的話,我會在foreach循環中的send()前加入。

- 更新 -

試試這個:

$mailer = Swift_Mailer::newInstance($transport); 

$message = Swift_Message::newInstance() 
    ->setSubject('Important notice for {FirstName}') 
    ->setFrom(array('[email protected]' => 'John Doe')); 

foreach ($result as $user) { 

    $message->setTo($user['Email']); 

    $message->setBody(setBody(sprintf("Hello %s, we have reset your password to %s\n" . "Please log in and change it at your earliest convenience.", $user['FirstName'], $user['LastName']); 

    if (!$numSent=$mailer->send($message,$failures)) { 
     $failures[] = $failures; 
    } 
} 

if (isset($failures)) { 
    var_dump($failures); 
} 
+0

謝謝你的回答。有道理。不幸的是,問題仍然存在。實際上,使用這個插件,我可以發送郵件而不用循環。現在我發送郵件和名字,姓氏仍然不是自定義的。它應該是在plugin.php – user782104 2012-02-24 17:24:07

+0

中的一些錯誤如果你不把循環中的send(),插件期望一個數組?現在你傳遞數組的一個元素。 – 2012-02-24 17:27:03

+0

我明白你的觀點,但不會像我預期的那樣改變。對於相同的內容郵件,它是 $ message = Swift_Message :: newInstance('Wonderful Subject') - > setFrom(array('[email protected]'=>'John Doe')) - > setTo(array ('[email protected]','other @ domain。有機」 => 'A名稱')) - > setBody( '這裏是消息本身') ; – user782104 2012-02-24 17:30:57