Transports are Cached?

Swift Mailer is a fantastic library for sending email with php. Discuss this library or ask any questions about it here.

Moderators: Chris Corbyn, General Moderators

Post Reply
BrandonMUS
Forum Newbie
Posts: 15
Joined: Mon Nov 10, 2008 9:45 am

Transports are Cached?

Post by BrandonMUS »

I'm having a hard time figuring this out. I'm not sure if it's a bug or a feature, so I posted here instead of lighthouseapp.

Here's some quick sample code to try and explain what I'm experiencing:

Code: Select all

<?php
require_once '../lib/Swift/swift_required.php';
$emailer_1 = new Swift_Mailer(new Swift_SmtpTransport('localhost'));
 
print_r($emailer_1);
 
$emailer_1->registerPlugin(new Swift_Plugins_LoggerPlugin(new Swift_Plugins_Loggers_ArrayLogger()));
 
$emailer_2 = new Swift_Mailer(new Swift_SmtpTransport('localhost'));
 
print_r($emailer_2);
I see no reason why those two dumps shouldn't match 100%. What really happens, though, is that the $emailer_2 shows the same LoggerPlugin that $emailer_1 was given. Basically, if I attach a LoggerPlugin (or probably any plugin for that matter) to a Swift_Mailer instance, it seems that it is there forever. Is this the intended result? How do I turn it off?

What I am trying to do in my application is send emails for orders that meet certain conditions. As I iterate through the orders, if the order needs an email sent, it goes off and creates it's own Swift_Mailer. Unfortunately, it seems that it is inheriting the mailer settings of other orders, which won't work for me. Specifically, the LoggerPlugin I use is passed the trigger criteria of the order and it goes off to see if that order was already triggered (preventing duplicate emails). If the LoggerPlugin is reused, the criteria it is passed never gets updated (since it is passed at creation).

Anyone have any ideas for a fix or workaround?

EDIT: So I found the dependencies being used/created and see where the problem exists. The first instance of Swift_Mailer (Swift_Transport really) registers the listeners to transport.eventdispatcher, so then in the future if any new Swift_Transport comes along, it has to use that dispatcher too. Adding an additional plugin does not overwrite, but just appends to the array of existing plugins. Just your typical global variable problem I guess. Since there is no way to remove a plugins (viewtopic.php?f=52&t=95441&p=521160#p521160) or reset the dependencies, I don't think there is a frontend fix to this... Here's some new code just for reference:

Code: Select all

<?php
require_once '../lib/Swift/swift_required.php';
 
print_r(
    Swift_DependencyContainer::getInstance()
    ->lookup('transport.eventdispatcher')
);
 
$emailer_1 = new Swift_Mailer(new Swift_SmtpTransport('localhost'));
$emailer_1->registerPlugin(new Swift_Plugins_LoggerPlugin(new Swift_Plugins_Loggers_ArrayLogger()));
 
$emailer_2 = new Swift_Mailer(new Swift_SmtpTransport('localhost'));
 
print_r(
    Swift_DependencyContainer::getInstance()
    ->lookup('transport.eventdispatcher')
);
 
$emailer_2->registerPlugin(new Swift_Plugins_LoggerPlugin(new Swift_Plugins_Loggers_ArrayLogger()));
 
print_r(
    Swift_DependencyContainer::getInstance()
    ->lookup('transport.eventdispatcher')
);
Still open to ideas as I haven't figured out a workable solution yet.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Transports are Cached?

Post by Chris Corbyn »

Plugins are globally applied, even though the interface adds the via the mailer. I'm not sure if this is desirable or not.

It would do the same thing to do:

Code: Select all

Swift_DependencyContainer::lookup('transport.eventdispatcher')->bindEventListener($plugin);
Does this cause a problem for you?

To change this behaviour, in the dependency map, change from:

Code: Select all

-> asSharedInstanceOf('Swift_Events_SimpleEventDispatcher')
 
// Change to
 
-> asNewInstanceOf('Swift_Events_SimpleEventDispatcher')
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Transports are Cached?

Post by Chris Corbyn »

I may actually make this change myself. I'm not sure if my original reasoning for using a shared instance still stands since I've re-designed the event dispatcher since that time.

Note also, you don't need to physically edit the dependency maps if you want to change something, you can override parts of the map immediately after requiring swift_required.php or swift_init.php:

Code: Select all

<?php
 
require_once 'swift_required.php';
 
Swift_DependencyContainer::getInstance()
  ->register('transport.eventdispatcher')
  ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher')
  ;
 
// ... Continue as normal ...
Like I say... this might (probably will) be the default in 4.0.3.
BrandonMUS
Forum Newbie
Posts: 15
Joined: Mon Nov 10, 2008 9:45 am

Re: Transports are Cached?

Post by BrandonMUS »

Thanks for the info. Your fix is a whole lot more graceful than what I thought would be possible, so I applaud you for that. I see you fixed this in the git, so this brings me to my next question:

I've been watching the development in git, and I was wondering what the proper way to make a release (?) out of the current git. If I just copy the lib directory over, the Swift::VERSION constant doesn't work (and possibly other things). Is there a command a guest can run, or are only the official releases able to be used? (this is development, not production btw)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Transports are Cached?

Post by Chris Corbyn »

BrandonMUS wrote:Thanks for the info. Your fix is a whole lot more graceful than what I thought would be possible, so I applaud you for that. I see you fixed this in the git....
Yes, today I will release 4.0.3 with this change in it, along with a bugfix for the 76 character line length in base64 encoding being exceeded.
I've been watching the development in git, and I was wondering what the proper way to make a release (?) out of the current git. If I just copy the lib directory over, the Swift::VERSION constant doesn't work (and possibly other things). Is there a command a guest can run, or are only the official releases able to be used? (this is development, not production btw)
Yes. If you've grabbed the source from git you need two things and then you can basically put yourself in my shoes and package it up like a distribution release :P

1. You need to have Java installed on your machine
2. You need to have Ant installed (uses Java)

Most likely you'll have at least Java, and you'll probably have Ant if you're running a Mac.

To create a distribution release (which has the correct version number), go to the base directory of the checkout from git, make sure there's a directory named "build" and if not, create it. Now run:

ant bundle

This will basically copy over all of the needed files into the build/ directory, removing stuff that is not needed and setting the Swift::VERSION constant. It create a directory in build/ called "Swift-X.Y.Z" where the actual name is taken from the VERSION file.

If you need a .tar.gz instead of an uncompressed directory:

ant package

This will do the same thing, except instead of a folder inside the build/ directory, you'll have a .tar.gz file.

I'm probably going to update build.xml (the script Ant reads from) today so that it generates the CHANGES file based on the matching tag message in git.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Re: Transports are Cached?

Post by Chris Corbyn »

The change that I pushed to github has now gone live and is available in http://swiftmailer.org/downloads/get/Swift-4.0.3.tar.gz
Post Reply