Quick and simple wordpress blog backup by using a SHELL script

by Jamie Hall on August 31, 2010

I wanted to implement a quick way to back up my blog. (I know there are lots of solutions, but I wanted something quick and simple to setup)

I wrote this script on the server that I want to backup:

#!/bin/bash
date="`eval date +%Y%m%d`";
mysqluser="user"
mysqlpass="password"
mysqldb="database"
backupsource="/srv/www/refineweb.co.uk/"
backupdest="/srv/backups/refineweb.co.uk/"
mysqldump -q -e -h localhost -u ${mysqluser} -p${mysqlpass} ${mysqldb} | gzip - > /${backupdest}${date}_db-backup.sql.gz
cd /${backupsource}
tar cf - . | gzip - > /${backupdest}${date}_files.tar.gz
echo "$date             Backup complete" >> /var/log/backup_refineweb.log

On my desktop at home, I created a script which transfers the files from the server and then copies them to another location (3 seperate backup locations):

#! /bin/bash
echo Backup Started `date` >> ~/backuplog
date="`eval date +%Y%m%d`";
files="${date}_files.tar.gz"
sql="${date}_db-backup.sql.gz"
# copy files from server
scp root@refineweb.co.uk:/var/backups/refineweb.co.uk/\{${files},${sql}\} /media/HALL-BACKUP/backup/refineweb.co.uk
# move to another location
cp /media/HALL-BACKUP/backup/refineweb.co.uk/${files} /home/jamie/backup/refineweb.co.uk
cp /media/HALL-BACKUP/backup/refineweb.co.uk/${sql} /home/jamie/backup/refineweb.co.uk
echo "$date             Backup complete" >> /var/log/backup_refineweb.log

On the server I have a crontab that runs at 5am in the morning. On my linux desktop at home I have a crontab that runs at 6am in the morning. I have added a ssh key for my desktop to the server (when the cron job is run, it won’t ask for a password).

Although, there is no validation etc. to make sure the backup has run successfully. It’s a quick and easy way to back up your blog.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

UPDATE: Storing emails in XML and sending them with sfMailer

by Jamie Hall on August 31, 2010

Hi all,

I have updated my previous post about sending emails which are stored in an XML file with sfMailer.

The class is better structured and it now includes i18n functionality.

Symfony – Storing email templates in XML for use with sfMailer

Thanks

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Deploying a symfony project into production using capistrano

by Jamie Hall on August 30, 2010

Please make sure you have ruby, ruby gems and capistrano (http://www.capify.org/index.php/Getting_Started) installed.

Here is a simple(ish) way to deploy your symfony project from a staging server onto your production server. It will perform all of the basic tasks such as removing dev environments, timestamping file modification dates, symlinking release folder etc.

Here’s the deploy.rb (stored in my project config directory on my staging server):

set :application, "frontend"
set :repository,  "http://example.com/svn/project/trunk"

# If you aren't deploying to /u/apps/#{application} on the target
# servers (which is the default), you can specify the actual location
# via the :deploy_to variable:
set :deploy_to, "/srv/www/"

# If there's no access to the repository from the production server, deploy via uploading tarball to the server
set :deploy_via, :export


# If you aren't using Subversion to manage your source code, specify
# your SCM below:
# set :scm, :subversion

role :app, "prodserver.example.com"
role :web, "prodserver.example.com"
# role :db,  "your db-server here", :primary => true

set :user, "root"

# path to php executable
set :php, "/usr/bin/php"

# symfony application name (used for migrations)
set :sf_app, "frontend"

namespace (:deploy) do

  desc <<-DESC
    [internal] Overriding original task to fit to symfony project needs
  DESC
  task :finalize_update, :except => { :no_release => true } do
    run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)

    run <<-CMD
      rm -rf #{latest_release}/log &&
     ln -s #{shared_path}/log #{latest_release}/log
   CMD
   
    run <<-CMD
      rm -rf #{latest_release}/cache &&
     ln -s #{shared_path}/cache #{latest_release}/cache
   CMD
   
    stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
    asset_paths = %w(images css js).map { |p| "#{latest_release}/web/#{p}" }.join(" ")
    run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", :env => { "TZ" => "UTC" }
  end
 
  desc <<-DESC
    Overriding original task to exclude restart
  DESC
  task :default do
    update
  end
 
  desc <<-DESC
    Overriding original task to use symfoy migrations (via sfMigrationsLightPlugin)
  DESC
  task :migrations do
    update
    sf.migrate
  end  
 
  after "deploy:update", 'deploy:customize'
 
  desc <<-DESC
    All custom tasks will be here
  DESC
  task :customize do
    # custmize it here
   sf.symlinks
    sf.remove_dev_environments
   
    # clear cache
   sf.cc
    # do permissions
   sf.batch_permissions
  end
 
end


namespace (:sf) do
 
  desc <<-DESC
    Run the "symfony migrate" task
  DESC
  task :migrate do
    run "cd #{current_path} && #{php} symfony migrate #{sf_app}"    
  end

  desc <<-DESC
    Run the "symfony cc" task
  DESC
  task :cc do
    run "cd #{current_path} && rm -rf cache/*"
  end

  desc <<-DESC
    Create symlink to symfony specific targets
  DESC
  task :symlinks do

       
    # symlink to uploads    
   run "rm -rf #{current_path}/web/uploads"
    run "ln -s #{shared_path}/uploads #{current_path}/web/uploads"
   
  end
 
  desc <<-DESC
    Remove DEV environments
  DESC
  task :remove_dev_environments do
    run "rm -rf #{current_path}/web/*_dev.php"    
  end
 
  desc <<-DESC
    Change permissions for batch jobs
  DESC
  task :batch_permissions do
    run "chmod -R 777 /srv/www/current/batch"
  end
 
  desc <<-DESC
    Disable symfony application
  DESC
  task :disable do
    run "cd #{current_path} && #{php} symfony disable #{sf_app} prod"    
  end
 
  desc <<-DESC
    Enable symfony application
  DESC
  task :enable do
    run "cd #{current_path} && #{php} symfony enable #{sf_app} prod"    
  end  
end

What this script does is the following:

  1. Create a folder on the production server. The folder name will a timestamp.
  2. SVN export the project into the newly created folder.
  3. Remove the exported project log directory and symlink it to to /srv/www/shared/log (this way you’ll always have a continuous log and not news one generated all of the time)
  4. Remove the exported cache directory and symlink it to /srv/www/cache
  5. Find all images, javascripts, and css files and change the modification date of each file with a new timestamp.
  6. Symlink release folder to /srv/www/current
  7. Symlink uploads folder to /srv/www/shared/uploads
  8. Remove all the dev environments, such as frontend_dev.php
  9. Clear cache
  10. Change batch files permissions (custom, you can use it if you want) so cronjobs will run successfully

Here is the output log for more details:

 * executing `deploy'
  * executing `deploy:update'
 ** transaction: start
  * executing `deploy:update_code'
    executing locally: "svn info http://example.com/svn/project/trunk  -rHEAD"
  * executing "svn export -q  -r249 http://example.com/svn/project/trunk /srv/www/releases/20100830142937 && (echo 249 > /srv/www/releases/20100830142937/REVISION)                                                                                                                   "
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing `deploy:finalize_update'
  * executing "chmod -R g+w /srv/www/releases/20100830142937"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing "rm -rf /srv/www/releases/20100830142937/log &&\\\n      ln -s /srv/www/shared/log /srv/www/releases/20100830142937/log"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing "rm -rf /srv/www/releases/20100830142937/cache &&\\\n      ln -s /srv/www/shared/cache /srv/www/releases/20100830142937/cache"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing "find /srv/www/releases/20100830142937/web/images /srv/www/releases/20100830142937/web/css /srv/www/releases/20100830142937/web/js -exec touch -t 201008301432.15 {} ';'; true"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing `deploy:symlink'
  * executing "rm -f /srv/www/current && ln -s /srv/www/releases/20100830142937 /srv/www/current"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
 ** transaction: commit
    triggering after callbacks for `deploy:update'
  * executing `deploy:customize'
  * executing `sf:symlinks'
  * executing "rm -rf /srv/www/current/web/uploads"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing "ln -s /srv/www/shared/uploads /srv/www/current/web/uploads"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing `sf:remove_dev_environments'
  * executing "rm -rf /srv/www/current/web/*_dev.php"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing `sf:cc'
  * executing "cd /srv/www/current && rm -rf cache/*"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished
  * executing `sf:batch_permissions'
  * executing "chmod -R 777 /srv/www/current/batch"
    servers: ["prodserver.example.com"]
    [prodserver.example.com] executing command
    command finished

Happy deploying! If you would like some help then please do not hesitate to leave a comment and I will try my best to assist.

VN:F [1.9.3_1094]
Rating: 10.0/10 (1 vote cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Using JaSig CAS with Symfony

by Jamie Hall on August 25, 2010

At work we use the SSO(single sign-on) library CAS to authenticate users accross our software stack. I didn’t like the code for phpCAS because it didn’t follow strict standards and it didn’t integrate very well with symfony, however, we do use it on some other php sites which aren’t running on symfony.

Please make sure you have the php XML (as we’re using SimpleXML) and cURL extensions enabled

To get CAS integrated into symfony successfully, I created a class called sfCAS. This class handles validation of a ticket, sets the correct parameters etc.

/*
 *
 * @author    Jamie Hall
 * @date      03-04-2009
 * @description           A library to use with symfony to validate a user into the SSO CAS system.
 */


class sfCAS extends sfCASRequiredFilter
{
  public function __construct($context)
  {
    $this->ssl = true;
    $this->server_uri = sfConfig::get("app_cas_server_domain");
    $this->server_port = sfConfig::get("app_cas_server_port");
    $this->server_location = sfConfig::get("app_cas_server_location");
    $this->localhost = sfConfig::get("app_cas_server_localhost");

    $this->request = $context->getRequest();
    $this->controller = $context->getController();
    $user = $context->getUser();
    $this->_pt = null;

    //Check if authenticated
    if(!$user->isAuthenticated())
    {          
      // check for ticket
      $ticket = ($this->request->hasParameter("ticket") ? $this->request->getParameter("ticket") : null);
      if(!empty($ticket))
      {
        if( preg_match('/^[SP]T-/',$ticket) )
        {
          $this->setPT($ticket);
        }
      }
    }
  }
 
  /*
   * Authenticate User to CAS
   */

 
  public function authenticate()
  {
    if(empty($this->_pt))
    {
      // redirect to Login
      $this->controller->redirect($this->getLoginURL());
    }
    else
    {
      if($this->validateTicket())
      {
        return true;
      }
      else
      {
        $this->controller->redirect($this->getLoginURL());
      }
    }
  }

  public function getLoginURL()
  {
    return $this->getURL() . "/login?service=" . urlencode($this->getService());
  }
 
  public function getLogoutURL()
  {
    return $this->getURL() . "/logout";
  }
 
  private function generateURL()
  {
    // generate the CAS URL
    // remove ticket from service URL if exists
    $service = $_SERVER['REQUEST_URI'];
    $service = preg_replace('/&ticket=[^&]*/','',$service);
    $service = preg_replace('/\?ticket=[^&;]*/','?',$service);
    $service = preg_replace('/\?%26/','?',$service);
    $service = preg_replace('/\?&/','?',$service);
    $service = preg_replace('/\?$/','',$service);
    $this->setService($service);
   
    $url = ($this->ssl) ? "https://" : "http://";
    $url .= sprintf("%s:%s/", $this->server_uri, $this->server_port);
    $url .= (empty($this->server_location)) ? "" : $this->server_location;
    $this->setURL($url);
   
  }
 
  private function setURL($url)
  {
    $this->url = $url;
  }
 
  public function getURL()
  {
    $this->generateURL();
    return $this->url;
  }
  private function setService($service)
  {
    $this->service = $service;
  }
 
  public function getService()
  {
    return  $this->localhost . $this->service;
  }
 
  public function getValidateURL()
  {
    return $this->getURL() . "/serviceValidate?service=" . urlencode($this->getService());
  }
 
  private function setPT($pt)
  {
    $this->_pt = $pt;
  }
  public function getPT()
  {
    return $this->_pt; 
  }
 
  private function setUser($user)
  {
    $this->user = $user;
  }
 
  public function getUser()
  {
    return $this->user;
  }
 
  /*
  *
  * We have a ticket, but we need to validate it using proxyValidate on the CAS Server
  */

  public function validateTicket()
  {
    // get validation URL and append the ticket
    $url = $this->getValidateURL().'&ticket='.$this->getPT();
    // new CURL object
    $curl = $this->curlInit($url);
    $result = curl_exec($curl);
    // read the response of the CAS server into a DOM object
    $dom = new DOMDocument();
    $dom->formatOutput = true;
 
    if (!($dom->loadXML($result)))
    {
      // read failed
      return false;
    }
 
    if ($dom->getElementsByTagName("authenticationSuccess")->length != 0)
    {
      // authentication succeded, extract the user name
      if ($dom->getElementsByTagName("user")->length == 0) {
        return false;
      }
      $this->setUser($dom->getElementsByTagName("user")->item(0)->nodeValue);
      return true;
    }
    else if ($dom->getElementsByTagName("authenticationFailure")->length != 0)
    {
      // authentication succeeded, extract the error code and message
      return false;
    }
  }
 
  private function curlInit($url)
  {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    return $curl;
  }
}

The class get’s it settings from the app.yml file in your app directory.

app:
cas:
server_domain: cas.example.com
server_port: 9999
server_location: cas
server_localhost: http://localhost

You’ll also need a filter (I’ve called mine sfCASRequiredFilter):

/*
 * @author    Jamie Hall
 * @description The filter is executed on every action to check if a user is authenticated with CAS or needs to be authenticated
 */

class sfCASRequiredFilter extends sfBasicSecurityFilter
{
  public function execute ($filterChain)
  {
    if ($this->isFirstCall())
    {
          if(!$this->getContext()->getUser()->isAuthenticated())
          {
            $sfCas = new sfCAS($this->getContext());
          if($sfCas->authenticate())
          {
            $this->getContext()->getUser()->authenticate($sfCas->getUser());
            }
        }
    }
   
    // Execute next filter in the chain
    $filterChain->execute();
  }
}

Please make sure you enable the filter. And that’s all there is to it. When a user first goes into the application it will check if they’re authenticated, if they’re authenticated through CAS, they will then will be authenticated into the application, if they’re not authenticated in CAS they will be redirect to the CAS login. Once approved by CAS, the ticket will be validated, if valid, they will be authenticated through your system.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)

Symfony – Storing email templates in XML for use with sfMailer

by Jamie Hall on August 23, 2010

Update: I have cleaned up the class to accept a sfContext instance to load helpers for the email templates. I have also added i18n functionality.

I wanted to come up with a cleaner solution than the current solution for sending emails in symfony. For example, I don’t like the way that if you want to send an email in an action, you have two different ways:

  1. Putting the template code in the action (yuk)
  2. Using a partial. Calling that partial content and then using it as the template for the email.

See ref: http://www.symfony-project.org/jobeet/1_4/Doctrine/en/16

Two problems: I don’t like seeing html code in the controller and if I want to use a task to send emails, using a partial is not a viable solution.

After thinking for a while, I decided the best approach would be to store the emails in an XML file in the data directory and create a MailTemplate wrapper class to insert the correct parameters for setting the content etc.

So here is what I did. I created an XML file with all of my email templates in theproject data directory. It has a bunch of configuration options. I’ll go into that later.

I then created a class called MailTemplate.class.php to extract an email template. Here is the class (stored in my project lib directory):

<?php
/*
 * @author      Jamie Hall
 * @desccription  Mail wrapper for using email templates in an
 *          XML file instead of php templates
 * @date      31st August 2010
 */

class MailTemplate
{
  protected $content_loaded = false;
  protected $email;
  protected $params = array();
  protected $context = null;
  protected $culture = null;
  protected $content = array();

  public function __construct($id, $context)
  {
    if(!$context instanceof sfContext) throw new sfException ("The context passed through is not a valid instance of sfContext");
    $this->context = $context;
    $file = sfConfig::get("sf_data_dir") . DIRECTORY_SEPARATOR . "emails.xml";
    if(!file_exists($file) || !is_readable($file)) throw new sfException("Email XML file does not exist or is not readable");
    $emails = new SimpleXMLElement(file_get_contents($file));

    if($email = $emails->xpath(sprintf("/emails/email[@id='%s']", $id)))
    {
      // load email
      $this->email = $email[0];
      // load helpers
      self::loadHelpers();
    }
    else
    {
      throw new sfException(sprintf("Could not find the email template '%s. Are you passing the correct email id?", $id));
    }
  }

  /*
   * @description   check if a parameter which is being set is valid.
   *          return exception if parameter is not valid
   */

  private function hasPHP()
  {
    return ($this->email->has_php=="true") ? true : false;
  }

  /*
   * @description Check if the template is i18n enabled
   */

  private function isInternationalised()
  {
    return ($this->email->i18n=="true") ? true : false;
  }

  /*
   * @description   If the template is i18n enabled, set the culture
   */

  public function setCulture($culture)
  {
    if(self::isInternationalised())
    {
      $this->culture = $culture;
    }
    else
    {
      throw new sfException("This is not an internationalised template.");
    }
  }

  public function loadHelpers()
  {
    $helpers = array();
    if(count($this->email->helpers->helper) > 0 )
    {
      for ($i = 0; $i < count($this->email->helpers->helper); $i++)
      {
        $helpers[] = (string) $this->email->helpers->helper[$i];
      }
      // load the helpers, anyone know of a better way to do this?
      $this->context->getConfiguration()->loadHelpers($helpers);
    }
  }

  /*
   *  @description  return an array of valid parameters for the email template
   */


  public function getParameters()
  {
    $params = array();
    for ($i = 0; $i < count($this->email->parameters->param); $i++)
    {
      $params[] = $this->email->parameters->param[$i];
    }

    return $params;
  }

  /*
   *  @description  Set a parameter. If valid, add to params array.
   */

  public function setParameter($param, $value)
  {
    if(self::isParameterValid($param))
    {
      $this->params[$param] = $value;
    }
  }

  /*
   * @description   check if a parameter which is being set is valid.
   *          return exception if parameter is not valid
   */

  private function isParameterValid($param)
  {
    for ($i = 0; $i < count($this->email->parameters->param); $i++)
    {
      if($this->email->parameters->param[$i] == $param)
      {
        return true;
      }
    }
    throw new sfException(sprintf("Parameter name '%s' is not valid", $param));
  }

  /*
   *  @description  Set the email content with the set parameters. If it has already been called
   *          once throw an exception, otherwise, set the content and flag content_loaded
   *          as true.
   */

  public function setContent()
  {
    if($this->content_loaded) throw new sfException("Content has already been set");

    $this->content['plain'] = self::setPlainContent();
    $this->content['html'] = self::setHtmlContent();

    $this->content_loaded = true;
  }

  /*
   *  @description  Extract the parameter variables from the array, evaluate the plain content from the xml
   *          return the output back into the plain content variable
   */

  private function setPlainContent()
  {

    if(isset($this->culture))
    {
      $culture = $this->culture;
      $this->content['plain'] = $this->email->content->i18n->$culture->plain;
    }
    else
    {
      $this->content['plain'] = $this->email->content->plain;
    }

    if(self::hasPHP())
    {
      extract($this->params);
      ob_start();
      ob_implicit_flush(0);
      try
      {
        eval(sprintf("?>%s<?", $this->content['plain']));
      }
      catch (sfException $e)
      {
        // need to end output buffering before throwing the exception #7596
        ob_end_clean();
        throw $e;
      }
      return ob_get_clean();
    }
    else
    {
      return $content['plain'];
    }

  }

  /*
   *  @description  Extract the parameter variables from the array, evaluate the html content from the xml
   *          return the output back into the html content variable
   */

  private function setHtmlContent()
  {

    if(isset($this->culture))
    {
      $culture = $this->culture;
      $this->content['html'] = $this->email->content->i18n->$culture->html;
    }
    else
    {
      $this->content['html'] = $this->email->content->html;
    }

    if(self::hasPHP())
    {
      extract($this->params);
      ob_start();
      ob_implicit_flush(0);
      try
      {
        eval(sprintf("?>%s<?", $this->content['html']));
      }
      catch (sfException $e)
      {
        // need to end output buffering before throwing the exception #7596
        ob_end_clean();
        throw $e;
      }
      return ob_get_clean();
    }
    else
    {
      return $this->content['html'];
    }

  }

  /*
   *  @description  Return the email subject
   */

  public function getSubject()
  {
    return $this->email->subject;
  }

  /*
   *  @description  return the html content. If the content has not been set, throw exception.
   */

  public function getHtmlContent()
  {
    if(!$this->content_loaded) throw new sfException("Content has not been loaded");
    // file is saved in utf-8, however, to display any foreign characters correctly (such as in french) we need to decode
    return utf8_decode ($this->content['html']);
  }

  /*
   *  @description  return the plain content. If the content has not been set, throw exception.
   */

  public function getPlainContent()
  {
    if(!$this->content_loaded) throw new sfException("Content has not been loaded");
    return utf8_decode(trim($this->content['plain']));
  }
}

And for the XML template file, (stored in the data directory) I have this:

<?xml version='1.0' standalone='yes'?>
<emails>
 <email id="products-expired">
  <description>We send this email when we want to inform a user when a product has expired</description>
  <!-- If the content is dynamic (uses php) set value to true, otherwise false -->
  <has_php>true</has_php>
  <!-- if the email is internationalised -->
  <i18n>false</i18n>
  <!-- Template parameters which will be used in the content -->
  <parameters>
    <param>name</param>
    <param>number_of_products</param>
                <param>products</param>
  </parameters>
  <!-- Load any required helpers which will be used to display the email content, such as url, date, escaping etc. -->
  <helpers>
    <helper>Url</helper>
      <helper>Helper</helper>
      <helper>Asset</helper>
              <helper>Tag</helper>
    <helper>Escaping</helper>
  </helpers>
  <!-- Email subject -->
  <subject>Product Expiration</subject>
  <!-- Email Content -->
  <content>
    <html>
      <![CDATA[
      Dear <?php echo $name ?>, <br />
      <p>
      Homepage url: <?php echo  url_for("@homepage", true)?>
      You have <?php echo $number_of_products ?> products that are due to expire in under 30 days. Please log in to <?php echo link_to("Application", "@homepage", array('absolute' => true))?> to review the products.
      <br /><br />
      <ul>
        <?php foreach($products as $product):?>
          <li><?php echo $product->getName() ?></li>
        <?endforeach;?>
      </ul>
      This is an automated email. Please do not reply.
      </p>
      ]]>
    </html>
    <plain>
      <![CDATA[
        Dear <?php echo $name ?>, You have <?php echo $number_of_products ?> products that are due to expired in under 30 days. Please log in to example.com review the products. This is an automated email. Please do not reply.
      ]]>
    </plain>
  </content>
  </email>
  <email id="system-update">
  <description>This is just a generic update email</description>
  <has_php>false</has_php>
  <subject>Update</subject>
  <content>
    <html>
      <![CDATA[
        Dear all,
        <p>The system has been updated. Please login to <a href="example.com">example.com</a> to view all of the changes.</p>
      ]]>
    </html>
    <plain>
      <![CDATA[
        Dear all, the system has been updated. Please login to example.com to view all of the changes.
      ]]>
    </plain>
  </content>
 </email>
</emails>

If you look in the XML file. You can set the helpers you want to use (for example if you’re using url_for in the content). You define all the valid parameters and also defined whether you’ll be using php in the content (if an email is just static content, then php is not needed).
To use an email template in an action for example, you would do the following:

  public function executeExample(sfWebRequest $request)
  {
      $products = Doctrine::getTable("Product")->findAll();
      // get email template
      $mail = new MailTemplate("products-expired", $this->getContext());
      $mail->setParameter("name", "Joe Bloggs");
      $mail->setParameter("number_of_products", count($products));
      $mail->setParameter("products", $products);
      $mail->setContent();

      // send the email using sfMailer
      $message = $this->getMailer()->compose();
      $message->setSubject($mail->getSubject());
      $message->setTo("whoever@example.com");
      $message->setFrom(array("jamie@example.com"=>"Automated Message"));
      $message->setBody($mail->getHtmlContent(), 'text/html');
      $message->addPart($mail->getPlainContent(), 'text/plain');

     $this->getMailer()->send($message);
}

If you want to send an il8n email you’ll need the following XML markup:

 <!-- i18n example -->
 <email id="message-received">
  <description>We send this email to inform a user when they have received a message</description>
  <has_php>true</has_php>
  <i18n>true</i18n>
  <parameters>
    <param>name</param>
    <param>received_from</param>
    <param>date_received</param>
  </parameters>
  <helpers>
    <helper>Url</helper>
      <helper>Helper</helper>
      <helper>Asset</helper>
              <helper>Tag</helper>
    <helper>Escaping</helper>
  </helpers>
  <subject>Message Received</subject>
  <content>
    <i18n>
      <en_GB>
        <html>
          <![CDATA[
          Dear <?php echo $name ?>, <br />
          <p>
            You have received a message from <?php echo $received_from ?> which was sent on <?php echo $date_received ?> <br />
            Please login to <?php echo link_to("Application", "@homepage", array('absolute' => true))?> to view the message.
            <br /><br />
            This is an automated email. Please do not reply.
          </p>
          ]]>
        </html>
        <plain>
          <![CDATA[
            Dear <?php echo $name ?>, You have received a message from <?php echo $received_from ?> which was sent at <?php echo $date_received ?>.
            Please login to <?php echo url_for("@homepage", array('absolute' => true))?> to view the message. This is an automated email. Please do not reply.
          ]]>
        </plain>  
      </en_GB>
      <fr_FR>
        <html>
          <![CDATA[
          Cher <?php echo $name ?>, <br />
          <p>
            Vous avez re&ccedil;u un message de <?php echo $received_from ?>, envoyé le <?php echo $date_received ?> <br />
            Merci de vous connecter à <?php echo link_to("Application", "@homepage", array('absolute' => true))?> afin de le lire. <br />
            <br /><br />
            Ceci est un courriel automatiquement généré, merci de ne pas y répondre.
          </p>         
          ]]>
        </html>
        <plain>
          <![CDATA[
            Cher <?php echo $name ?>, Vous avez reçu un message de <?php echo $received_from ?>, envoyé le<?php echo $date_received ?>. Merci de vous connecter à <?php echo url_for("@homepage", array('absolute' => true))?> afin de le lire.
            Ceci est un courriel automatiquement généré, merci de ne pas y répondre.
          ]]>
        </plain>  
      </fr_FR>
    </i18n>
  </content>
 </email>

And use the following code to send an i18n email:

public function executeExample(sfWebRequest $request)
{
  $template = new MailTemplate("message-received", $this->getContext());
  $template->setCulture("fr_FR");
  $template->setParameter("name", "Jamie Hall");
  $template->setParameter("received_from", "Joe Bloggs");
  $template->setParameter("date_received", "2010-12-12 10:10:10");
  $template->setContent();
   
  $message = $this->getMailer()->compose();
  $message->setSubject($template->getSubject());
  $message->setTo("jamie@example.com");
  $message->setFrom(array("mail@example.com"=>"Automated Message"));
  $message->setBody($template->getHtmlContent(), 'text/html');
  $message->addPart($template->getPlainContent(), 'text/plain');
  $this->getMailer()->send($message);
}

As simple as that.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)