1<?php 2 3/* 4 * This file is part of SwiftMailer. 5 * (c) 2004-2009 Chris Corbyn 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11//@require 'Swift/Events/SendListener.php'; 12//@require 'Swift/Events/SendEvent.php'; 13//@require 'Swift/Plugins/Decorator/Replacements.php'; 14 15/** 16 * Allows customization of Messages on-the-fly. 17 * 18 * @package Swift 19 * @subpackage Plugins 20 * 21 * @author Chris Corbyn 22 */ 23class Swift_Plugins_DecoratorPlugin 24 implements Swift_Events_SendListener, Swift_Plugins_Decorator_Replacements 25{ 26 27 /** The replacement map */ 28 private $_replacements; 29 30 /** The body as it was before replacements */ 31 private $_orginalBody; 32 33 /** The original subject of the message, before replacements */ 34 private $_originalSubject; 35 36 /** Bodies of children before they are replaced */ 37 private $_originalChildBodies = array(); 38 39 /** The Message that was last replaced */ 40 private $_lastMessage; 41 42 /** 43 * Create a new DecoratorPlugin with $replacements. 44 * 45 * The $replacements can either be an associative array, or an implementation 46 * of {@link Swift_Plugins_Decorator_Replacements}. 47 * 48 * When using an array, it should be of the form: 49 * <code> 50 * $replacements = array( 51 * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"), 52 * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y") 53 * ) 54 * </code> 55 * 56 * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, 57 * the object should return just the array of replacements for the address 58 * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. 59 * 60 * @param mixed $replacements 61 */ 62 public function __construct($replacements) 63 { 64 if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) 65 { 66 $this->_replacements = (array) $replacements; 67 } 68 else 69 { 70 $this->_replacements = $replacements; 71 } 72 } 73 74 /** 75 * Invoked immediately before the Message is sent. 76 * 77 * @param Swift_Events_SendEvent $evt 78 */ 79 public function beforeSendPerformed(Swift_Events_SendEvent $evt) 80 { 81 $message = $evt->getMessage(); 82 $this->_restoreMessage($message); 83 $to = array_keys($message->getTo()); 84 $address = array_shift($to); 85 if ($replacements = $this->getReplacementsFor($address)) 86 { 87 $body = $message->getBody(); 88 $search = array_keys($replacements); 89 $replace = array_values($replacements); 90 $bodyReplaced = str_replace( 91 $search, $replace, $body 92 ); 93 if ($body != $bodyReplaced) 94 { 95 $this->_originalBody = $body; 96 $message->setBody($bodyReplaced); 97 } 98 $subject = $message->getSubject(); 99 $subjectReplaced = str_replace( 100 $search, $replace, $subject 101 ); 102 if ($subject != $subjectReplaced) 103 { 104 $this->_originalSubject = $subject; 105 $message->setSubject($subjectReplaced); 106 } 107 $children = (array) $message->getChildren(); 108 foreach ($children as $child) 109 { 110 list($type, ) = sscanf($child->getContentType(), '%[^/]/%s'); 111 if ('text' == $type) 112 { 113 $body = $child->getBody(); 114 $bodyReplaced = str_replace( 115 $search, $replace, $body 116 ); 117 if ($body != $bodyReplaced) 118 { 119 $child->setBody($bodyReplaced); 120 $this->_originalChildBodies[$child->getId()] = $body; 121 } 122 } 123 } 124 $this->_lastMessage = $message; 125 } 126 } 127 128 /** 129 * Find a map of replacements for the address. 130 * 131 * If this plugin was provided with a delegate instance of 132 * {@link Swift_Plugins_Decorator_Replacements} then the call will be 133 * delegated to it. Otherwise, it will attempt to find the replacements 134 * from the array provided in the constructor. 135 * 136 * If no replacements can be found, an empty value (NULL) is returned. 137 * 138 * @param string $address 139 * 140 * @return array 141 */ 142 public function getReplacementsFor($address) 143 { 144 if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) 145 { 146 return $this->_replacements->getReplacementsFor($address); 147 } 148 else 149 { 150 return isset($this->_replacements[$address]) 151 ? $this->_replacements[$address] 152 : null 153 ; 154 } 155 } 156 157 /** 158 * Invoked immediately after the Message is sent. 159 * 160 * @param Swift_Events_SendEvent $evt 161 */ 162 public function sendPerformed(Swift_Events_SendEvent $evt) 163 { 164 $this->_restoreMessage($evt->getMessage()); 165 } 166 167 // -- Private methods 168 169 /** Restore a changed message back to its original state */ 170 private function _restoreMessage(Swift_Mime_Message $message) 171 { 172 if ($this->_lastMessage === $message) 173 { 174 if (isset($this->_originalBody)) 175 { 176 $message->setBody($this->_originalBody); 177 $this->_originalBody = null; 178 } 179 if (isset($this->_originalSubject)) 180 { 181 $message->setSubject($this->_originalSubject); 182 $this->_originalSubject = null; 183 } 184 if (!empty($this->_originalChildBodies)) 185 { 186 $children = (array) $message->getChildren(); 187 foreach ($children as $child) 188 { 189 $id = $child->getId(); 190 if (array_key_exists($id, $this->_originalChildBodies)) 191 { 192 $child->setBody($this->_originalChildBodies[$id]); 193 } 194 } 195 $this->_originalChildBodies = array(); 196 } 197 $this->_lastMessage = null; 198 } 199 } 200 201} 202