When a company is registered in BasicCRM system, user recieves an email like this:
When you follow this link, the company becomes activated i.e. you confirm that you entered an email address owned by you:
The process of model design is the same as in case with Registering a company I’ve added the user stories I needed:
Then I wrote the code translating the requirements to PHP, did the unit tests for the new requirements. A tiny MVC bit to make it “live” and that was it. I won’t be returning to these points again as it’s all covered in the previous articles pretty thoroughly.
What is worth mentioning here is this piece of code in
Explanation needed for the usage of
transactional, since it wasn’t in the requirements. The thing is that all service functions are of integral, solid matter for the consumer of the model. In this case MVC layer calls Service Layer’s functions and expects them to either work or raise an error (via exceptions mechanism). We don’t expect a function to work “partially”, change some state then rise an error without changing something else.
In many cases when we only deal with the state through Doctrine 2 Entity Manager, we can avoid any involvement into transactions management because it’s done by Doctrine itself. The ORM has a built-in UnitOfWork and when you call “$entityManager->flush()” it runs all the queries needed inside of a transaction. However, when your side effects include something else than talking to the data storage through Doctrine, it may need some help from you.
There are different ways of addressing it. It may be a good case to apply Aspect Oriented Programming. I decided to let the infrastructure specifics affect how the function is done. The code above means that persisting data in database and sending confirmation email is an atomic operation. You can’t do one of these things and fail doing the other. It’s either both or neither.
I used the transactional() method that accepts a Closure as you can see. There are also other ways for working with transactions in Doctrine 2, but I like this one.
Some refactoring was performed in the system, nothing critical: some things were renamed and duplicated code was moved to helper methods, particularly in the unit tests. In case you are interested in the code actual for older articles in this blog, I tagged the changes with the tag “introduction” in my GitHub repo.
I also added
/application/configs/config.local.ini, which, if found, is merged with /application/configs/config.ini. This file is not included in the VCS - you may create it yourself and override some parameters specific to your environment e.g. database name and credentials. There is also a new constant that must be defined by all entry points:
APPLICATION\ENV means the section of the configuration file that must be used by the application components. It’s more flexible this way and we don’t have to manually inject configuration object in the test suite like I did before.
Here is how the last instruction in the registerCompany looks like now:
In a way this $mailer->registrationConfirmation($company) is similar to $entityManager->persist($company), looking from within the registerCompany function.
The idea is simple: utilize Zend_View for rendering templates and use Zend_Mail_Transport_* to send messages (which are Zend_Mail objects). I saw people building complex things for this purpose, while I personally find this simple little approach quite deserving. I added some comments to the code for you and here is how it looks:
And here is the “configuration” of the Mailer object, ServiceLayer::getMailer():
Zend_View instance which is passed to the Mailer knows where to look for the templates. It’s the /application/templates directory in my case:
The registrationConfirmation method accepts a Company. It gets the data needed to render the template (here it’s the company’s identifier and the security salt) and to define the recipient from the company (the admin, one who registers it) and calls the mail function. I have a plain text email version for this operation, here is how the template looks (templates/company/registration-confirmation.txt)
To add a html version I’d just need to put a file named registration-confirmation.html to the same directory and it would be automatically included via Zend_Mail::setBodyHtml().
I extended Domain\RegisterCompanyTest, making sure that $mailer->registrationConfirmation is being called. The same way as we made sure a company is persisted in the data storage in previous articles i.e. using convenient PhpUnit’s mocks.
What is a bit interesting here is the “Functional” test, making sure that emails are actually being sent and contain the information we expect them to contain. I’ve added this piece to CompanyServiceTest::testRegisterCompany:
The trick is that using a special mail transport for tests suite we don’t get emails sent but saved to filesystem instead. The transport is Zend_Mail_Transport_File, a little contribution to Zend Framework done by Oleg Lobach and myself. With the new APPLICATION_ENV constant all we have to do in order to make the tests suite use the fake transport is to change the configuration file [tests] section. Like this: