DISABLE ADBLOCK

ADBlock is blocking some content on the site

ADBlock errore

Swiftmailer: dbReplacements by user id?

StackOverflow https://stackoverflow.com/questions/13217217

Question

The Swiftmailer docs says you can create your own class to handle replacements using the Decorator plugin:

class DbReplacements implements Swift_Plugins_Decorator_Replacements {
  public function getReplacementsFor($address) {
    $sql = sprintf(
      "SELECT * FROM user WHERE email = '%s'",
      mysql_real_escape_string($address)
    );

    $result = mysql_query($sql);

    if ($row = mysql_fetch_assoc($result)) {
      return array(
        '{username}'=>$row['username'],
        '{password}'=>$row['password']
      );
    }
  }
}

But in my case my database contains duplicated email address, i.e. the same address can appear on 3-4 accounts, so I need to get the replacements based on the user id instead.

How do I modify the above class to match my criteria?

Solution

Since swiftmailer don't know anything about id, you have to translate email to id by yourself. For example add new property to DbReplacements holding an associative array 'email' => 'id' (of course firstly limited to known ID, ie. SELECT email, id FROM user WHERE id IN(1,3,6,77) ) and in getReplacementsFor simply use email as index in this array to get user id.

Code sample to make it more clear:

class DbReplacements implements Swift_Plugins_Decorator_Replacements {
  public $email2id = array();
  public function getReplacementsFor($address) {
    $sql = sprintf(
      "SELECT * FROM user WHERE id = %d", $this->email2id[$address]
    );

    $result = mysql_query($sql);

    if ($row = mysql_fetch_assoc($result)) {
      return array(
        '{username}'=>$row['username'],
        '{password}'=>$row['password']
      );
    }
  }
}

$dbReplacer = new DbReplacements();
$decorator = new Swift_Plugins_DecoratorPlugin($dbReplacer); 
$mailer->registerPlugin($decorator);

$users = array(
    array('email'=>'john.doe@example.com', 'id' => 16),
    array('email'=>'john.doe2@example.com', 'id' => 13),
);

foreach ($users as $user) {
  $message->addTo($user['email']);
  $dbReplacer->email2id[$user['email']] = $user['id'];
}

OTHER TIPS

How do I modify the above class to match my criteria?

You can't. The ID is missing. Unless you don't have the ID at least associated with the message in question (that is the message of the event that is happening behind the scenes), you won't be able to create a concrete subtype of Class Swift_Plugins_DecoratorPlugin offering it's own _Replacements interface providing the message when asking for replacements.

Let's create your own plugin that still is a decorator plugin for the replacements:

<?php

interface My_Swift_Plugins_Decorator_Replacements extends Swift_Plugins_Decorator_Replacements
{
    public function setMessage(Swift_Mime_Message $message);
}

class My_Swift_Plugins_DecoratorPlugin extends Swift_Plugins_DecoratorPlugin implements My_Swift_Plugins_Decorator_Replacements
{

    private $_replacements;

    public function __construct(My_Swift_Plugins_Decorator_Replacements $replacements) {
        $this->_replacements = $replacements;
    }

    /**
     * Invoked immediately before the Message is sent.
     *
     * @param Swift_Events_SendEvent $evt
     */
    public function beforeSendPerformed(Swift_Events_SendEvent $evt) {
        $this->setMessage($evt->getMessage());
        parent::beforeSendPerformed($evt);
    }

    public function setMessage(Swift_Mime_Message $message) {
        $this->_replacements->setMessage($message);
    }
}

If you assign the ID to the message in your plugin you would get the message set before the getReplacementsFor is called. You could then assign it to a property and read it out in that function.

class DbReplacements implements My_Swift_Plugins_Decorator_Replacements {
  private $message;
  public function setMessage(Swift_Mime_Message $message) {
      $this->message = $message;
  }

  public function getReplacementsFor($address) {
    $sql = sprintf(
      "SELECT * FROM user WHERE email = '%s' and id = '%d'",
      mysql_real_escape_string($address),
      $this->message->emailID;
    );

    $result = mysql_query($sql);

    if ($row = mysql_fetch_assoc($result)) {
      return array(
        '{username}'=>$row['username'],
        '{password}'=>$row['password']
      );
    }
  }
}

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow