'text/plain', 'htm'=>'text/html', ); /** * Sets the initial view filename and local data. Views should almost * always only be created using [Email::factory]. * * $email = new Email($file); * * @param string $file view filename * @param array $data array of values * @return void * @uses Email::set_filename */ public function __construct($file=NULL,array $data=NULL) { $this->_key = $file; if ($file !== NULL) $this->set_filename($file); // Add the values to the current data if ($data !== NULL) $this->_data = $data + $this->_data; } /** * Magic method, searches for the given variable and returns its value. * Local variables will be returned before global variables. * * $value = $email->foo; * * [!!] If the variable has not yet been set, an exception will be thrown. * * @param string $key variable name * @return mixed * @throws Kohana_Exception */ public function & __get($key) { if (array_key_exists($key,$this->_data)) return $this->_data[$key]; elseif (array_key_exists($key,$this->_email)) return $this->_email[$key]; elseif (array_key_exists($key,Email::$_global_data)) return Email::$_global_data[$key]; else throw new Kohana_Exception('View variable is not set: :var',array(':var'=>$key)); } /** * Magic method, determines if a variable is set. * * isset($email->foo); * * [!!] `NULL` variables are not considered to be set by [isset](http://php.net/isset). * * @param string $key variable name * @return boolean */ public function __isset($key) { return (isset($this->_data[$key]) OR isset($this->_email[$key]) OR isset(Email::$_global_data[$key])); } /** * Magic method, calls [Email::set] with the same parameters. * * $email->foo = 'something'; * * @param string $key variable name * @param mixed $value value * @return void */ public function __set($key,$value) { switch ($key) { case 'from': case 'bcc': case 'to': if (! is_array($value) OR ! array_intersect(array('email','account'),array_keys($value))) throw new Email_Exception('Values for to should be an array of either "mail" or "account", however :value was given', array(':value'=>serialize($value))); case 'subject': $this->_email[$key] = $value; break; default: $this->set($key,$value); } } /** * Magic method, returns the output of [Email::render]. * * @return string * @uses Email::render */ public function __toString() { $e = Email::connect(); try { return (string)$this->render(); } catch (Exception $e) { /** * Display the exception message. * * We use this method here because it's impossible to throw an * exception from __toString(). */ $error_response = Kohana_Exception::_handler($e); return $error_response->body(); } } /** * Magic method, unsets a given variable. * * unset($email->foo); * * @param string $key variable name * @return void */ public function __unset($key) { unset($this->_data[$key],$this->_email[$key],Email::$_global_data[$key]); } /** * Assigns a value by reference. The benefit of binding is that values can * be altered without re-setting them. It is also possible to bind variables * before they have values. Assigned values will be available as a * variable within the view file: * * // This reference can be accessed as $ref within the view * $email->bind('ref', $bar); * * @param string $key variable name * @param mixed $value referenced variable * @return $this */ public function bind($key,&$value) { $this->_data[$key] =& $value; return $this; } /** * Assigns a global variable by reference, similar to [Email::bind], except * that the variable will be accessible to all views. * * Email::bind_global($key,$value); * * @param string $key variable name * @param mixed $value referenced variable * @return void */ public static function bind_global($key,&$value) { Email::$_global_data[$key] =& $value; } /** * Captures the output that is generated when a view is included. * The view data will be extracted to make local variables. This method * is static to prevent object scope resolution. * * $output = Email::capture($file,$data); * * @param string $kohana_view_filename filename * @param array $kohana_view_data variables * @return string */ protected static function capture($kohana_view_filename,array $kohana_view_data) { return Email::complete(file_get_contents($kohana_view_filename),Arr::merge(Email::$_global_data,$kohana_view_data)); } /** * Exchange the variables for values */ private static function complete($output,$data) { foreach (Email::variables($output) as $v) $output = str_replace('$'.$v.'$',$data[$v],$output); return $output; } /** * Deliver the email */ public function deliver(array $admin=array()) { // @todo - Setup queue mode return Email::connect()->send($this->render(NULL,$admin)); } /** * Get email details */ private function email($key) { if (is_array($this->_email[$key]) AND isset($this->_email[$key]['email'])) return $this->_email[$key]['email']; else return (is_array($this->_email[$key]) AND isset($this->_email[$key]['account'])) ? $this->_email[$key]['account'] : $this->_email[$key]; } /** * Returns a new Email object. If you do not define the "file" parameter, * you must call [Email::set_filename]. * * $email = Email::factory($file); * * @param string $file email filename * @param array $data array of values * @return Email */ public static function factory($file=NULL,array $data=NULL) { return new Email($file,$data); } /** * Renders the view object to a string. Global and local data are merged * and extracted to create local variables within the view file. * * $output = $email->render(); * * [!!] Global variables with the same key name as local variables will be * overwritten by the local variable. * * @param string $file view filename * @return string * @throws Email_Exception * @uses Email::capture */ public function render($file=NULL,array $admin=array()) { if ($file !== NULL) $this->set_filename($file); if (empty($this->_file)) throw new Email_Exception('You must set the file to use within your email before rendering'); if ($x=array_diff(array('to','from','subject'),array_keys($this->_email))) throw new Email_Exception('You are missing :missing from the Email',array(':missing'=>join('|',$x))); $sm = Swift_Message::newInstance() ->setFrom($this->email('from')) ->setSubject($this->email('subject')); foreach ($this->_file as $file) { $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); $sm->addPart(Email::capture($file,$this->_data),array_key_exists($ext,$this->_mime) ? $this->_mime[$ext] : File::mime($file)); } // Our list of BCC recipients if (Kohana::$config->load('debug')->email_bcc_admin AND $x=Arr::merge($this->email('bcc'),Kohana::$config->load('debug')->email_bcc_admin)) $sm->setBcc($x); $sm->setTo(($admin OR ($admin = Config::testmail($this->_key))) ? $admin : $this->email('to')); return $sm; } /** * Assigns a variable by name. Assigned values will be available as a * variable within the view file: * * // This value can be accessed as $foo within the view * $email->set('foo','my value'); * * You can also use an array to set several values at once: * * // Create the values $food and $beverage in the view * $email->set(array('food' => 'bread', 'beverage' => 'water')); * * @param string $key variable name or an array of variables * @param mixed $value value * @return $this */ public function set($key,$value=NULL) { if (is_array($key)) foreach ($key as $name => $value) $this->_data[$name] = $value; else $this->_data[$key] = $value; return $this; } /** * Sets the view filename. * * $email->set_filename($file); * * @param string $file view filename * @return Email * @throws Email_Exception */ public function set_filename($file) { foreach (array_keys($this->_mime) as $ext) if ($path=Kohana::find_file('email',$file,$ext)) // Store the file path locally array_push($this->_file,$path); if (! $this->_file) throw new Email_Exception('The requested email :file could not be found',array(':file'=>$file)); return $this; } /** * Sets a global variable, similar to [Email::set], except that the * variable will be accessible to all views. * * Email::set_global($name, $value); * * @param string $key variable name or an array of variables * @param mixed $value value * @return void */ public static function set_global($key,$value=NULL) { if (is_array($key)) foreach ($key as $key2 => $value) Email::$_global_data[$key2] = $value; else Email::$_global_data[$key] = $value; } /** * Extract the variables in the text */ public static function variables($output) { $results = array(); $matches = array(); preg_match_all('/\$([A-Z0-9_]+)\$/U',$output,$matches,PREG_OFFSET_CAPTURE); foreach ($matches[1] as $k => $v) if (! in_array($v[0],$results)) array_push($results,$v[0]); return $results; } } ?>