TalkPHP
 
 
Account Login
Latest Articles
» The basic usage of PHPTAL, a XML/XHTML template library for PHP
» Vulnerable methods and the areas they are commonly trusted in.
» Simple way to protect a form from bot
» The Basics On: How Session Stealing Works
» How to keep your forms from double posting data
IRC Channel
IRC Speech Bubble Join the friendly bunch on IRC...
(#TalkPHP on Freenode)

...Also available via a web interface.

See this thread for information on the TalkPHP Free Hugs Initiative™. Subject to availability.
Associates
Associates
CSS Tutorials
Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old 11-15-2007, 12:19 PM   #1 (permalink)
The Reckoner
Advanced Programmer Top Contributor 
 
Karl's Avatar
 
Join Date: Sep 2007
Posts: 437
Thanks: 22
Karl is on a distinguished road
Default Interfaces Revisited

After my last article on interfaces a few people said it would have been clearer if I had given a better example. I decided to write this tutorial/article to further explain the use of interfaces (and to give a decent example).

The code in this article will solve the following real life problem that I recently had to solve: I needed a system that allowed me to send emails to different combinations of groups of users.

There were many different variations of "user groups" and so I needed a flexible system to allow me to easily send emails to different combinations of these groups and to also allow me to easily add, delete and change groups at a later date.

I decided I needed one core class (which I named GroupEmailer) and one interface (which I namded RecipientGroup). I will later create classes that implement that interface.

The class, GroupEmailer, is responsible for sending a specific email to a group of recipients. It must know which group of users we want to send emails to. I've left out the implementation of sending the actual email as I don't feel it is important to the example.

PHP Code:
class GroupEmailer
{
    private 
$m_aGroups;
    
    public function 
addGroup(RecipientGroup $pGroup)
    {
        
$this->m_aGroups[] = $pGroup;
    }
    
    public function 
send()
    {
        foreach (
$this->m_aGroups as $pGroup)
        {
            
$aRecipients $pGroup->getRecipients();
            
            foreach (
$aRecipients as $szRecipient)
            {
                echo 
$szRecipient '<br />';
            }
        }
    }

If you read the previous article on interfaces this should look very similar to the PagesController class and should therefore need little explanation. With that said, you should note that in the send() method I've simply looped through and printed out each recipient, in a real life situation we'd obviously be sending out emails instead of printing out the list of recipient addresses. In case you're wondering how you could do this, you could simply pass in the email details through the send() method, such as send('Subject', 'Message body').

You can probably imagine how this will work. We'll add "groups" to the class (using addGroup()) which represents the group of users that we want to email, then we'll call the send() method to send the emails to each member of the groups.

However, we've not actually got any code for returning the groups yet. You may have noticed that the addGroup() method is expecting an object that implements the RecipientGroup interface, this means that we need to create some classes that implement this interface. Before we do that, we need to create our interface:

PHP Code:
interface RecipientGroup
{
    public function 
getRecipients();

We can determine that this interface needs only one method because each recipient group has only one responsibility: to return the list of recipient email addresses that belong to the group that it represents, for example, an Admin group would be responsible for returning a list of email addresses for all admins of the system.

Now that we have an interface to design our groups to we can start creating our group classes. We'll create two classes for this example, one for retrieving a list of admin email addresses and one for retrieving a list of member email addresses.

Here's the class for retrieving the list of admin email addresses:

PHP Code:
class RecipientGroup_Admins implements RecipientGroup 
{
    public function 
getRecipients()
    {
        
// fetch list of admin emails from db
        
return array('karl@talkphp.com''wildhoney@talkphp.com'
                
'salathe@talkphp.com''bluesaga@talkphp.com');
    }

Notice that we're not actually fetching any emails from anywhere, I've just hard-coded them so you can run the example and actually see how this would work before implementing it.

Here's the class for retrieving the list of member email addresses. This is almost exactly the same as the previous class

PHP Code:
class RecipientGroup_Members implements RecipientGroup 
{
    public function 
getRecipients()
    {
        
// fetch list of member emails from db
        
return array('john@hotmail.com''peter@yahoo.com'
                
'paul@gmail.com''bob@aol.com');
    }

Now that we have our two recipient groups we can give this a try:

PHP Code:
// Send an email to admins only 
$pGroupEmailer = new GroupEmailer();
$pGroupEmailer->addGroup(new RecipientGroup_Admins());
$pGroupEmailer->send(); 
This would output the following:

Code:
karl@talkphp.com
wildhoney@talkphp.com
salathe@talkphp.com
bluesaga@talkphp.com
We can easily send to an additional group of users by adding that to the GroupEmailer

PHP Code:
// Let's send an email to admins and members
$pGroupEmailer = new GroupEmailer();
$pGroupEmailer->addGroup(new RecipientGroup_Admins());
$pGroupEmailer->addGroup(new RecipientGroup_Members());
$pGroupEmailer->send(); 
Running this code would send emails to both groups, resulting in:

Code:
karl@talkphp.com
wildhoney@talkphp.com
salathe@talkphp.com
bluesaga@talkphp.com
john@hotmail.com
peter@yahoo.com
paul@gmail.com
bob@aol.com
We've now got a flexible system for sending emails to groups of members. We could easily add more groups by creating more "group" classes. How you go about collecting the email addresses (for example, from a database or hard coded) is of no concern to EmailSender, this gives you the flexibility to add, delete and change groups as your project requirements change.
__________________
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Karl is offline  
Reply With Quote
The Following User Says Thank You to Karl For This Useful Post:
Wildhoney (12-02-2007)
Old 11-15-2007, 01:42 PM   #2 (permalink)
Super Moderator
Advanced Programmer 
 
bluesaga's Avatar
 
Join Date: Sep 2007
Posts: 165
Thanks: 0
bluesaga is on a distinguished road
Default

Really nice and clean mate, easy to read and definitely helps get a grasp on interfaces!

Can you think of another reason to use interfaces alike you have? I'm finding it hard to think of a good use for something similar to the:

PHP Code:
$pGroupEmailer->addGroup(new RecipientGroup_Admins());
$pGroupEmailer->addGroup(new RecipientGroup_Members()); 
Part, where you use multiple classes. Using only one would be easy, databases or something, but I cant think of a use for using two classes alike that....
__________________
Halo 3 Cheats
bluesaga is offline  
Reply With Quote
Old 11-15-2007, 01:47 PM   #3 (permalink)
La Vida es Sueño
Advanced Programmer Top Contributor 
 
Wildhoney's Avatar
 
Join Date: Sep 2007
Location: Oldham
Posts: 2,280
Thanks: 90
Wildhoney is on a distinguished road
Default

In a nutshell it saves you having to go back to modify a class. Instead you can create another class and then include it in the construct's argument. Keep in mind that although you have a little repetition of code, all that should really be a repetition is the way you handle the MySQL queries, though this should as well be used via a MySQL class which makes querying simple.
__________________
The man who comes back through the Door in the Wall will never be quite the same as the man who went out.
Send a message via AIM to Wildhoney Send a message via MSN to Wildhoney Send a message via Yahoo to Wildhoney
Wildhoney is offline  
Reply With Quote
Old 11-15-2007, 02:21 PM   #4 (permalink)
The Reckoner
Advanced Programmer Top Contributor 
 
Karl's Avatar
 
Join Date: Sep 2007
Posts: 437
Thanks: 22
Karl is on a distinguished road
Default

bluesaga, another good example of this pattern can be found in the Zend Framework (in fact, they've used this kind of pattern throughout). If you look at the Zend_Valdiate class you can see that it can be used just like the class I built, it allows you to mix and match different validations to create your own valdiation group, here's some example code from the Zend Framework Reference Manual.

PHP Code:
// Create a validator chain and add validators to it
$validatorChain = new Zend_Validate();
$validatorChain->addValidator(new Zend_Validate_StringLength(612))
               ->
addValidator(new Zend_Validate_Alnum()); 
__________________
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Karl is offline  
Reply With Quote
Old 11-15-2007, 02:32 PM   #5 (permalink)
Super Moderator
Advanced Programmer 
 
bluesaga's Avatar
 
Join Date: Sep 2007
Posts: 165
Thanks: 0
bluesaga is on a distinguished road
Default

Ah right, yea thats a great example! I see now, i take it addValidator makes an array of the classes, and then "doValidate" (or something similar) loops through those, checking for a exception and returning the exception if it finds one?

I can see exactly why that works, and how its a great thing :)

One thing though, what happens if say you have 20-30 different string to validate. Surely this method would be a little slow? (Need different instances of Zend_Validate for each different string format?)
__________________
Halo 3 Cheats
bluesaga is offline  
Reply With Quote
Old 11-15-2007, 02:40 PM   #6 (permalink)
The Reckoner
Advanced Programmer Top Contributor 
 
Karl's Avatar
 
Join Date: Sep 2007
Posts: 437
Thanks: 22
Karl is on a distinguished road
Default

yes it would be a little slow. Unfortunately you have to give up some efficiency for the flexibility of such a system. The same can be said with a lot of agile design patterns, they allow far superior flexibility but unfortunately you've got to model a lot of the data using objects, which can hinder the performance of your system :(

With that said, there are many ways to improve the performance of your PHP applications. I dont just mean small performance boosts either, you can increase performance over 50% by just using a compiler cache.
__________________
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Karl is offline  
Reply With Quote
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


All times are GMT. The time now is 02:40 PM.

 
     

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0
Inactive Reminders By Icora Web Design