Practical example php implementation of the Observer pattern

October 12, 2010

Observer is a pattern where an object called the subject maintains a list of dependents (observers) and notifies them of any state changes. I implemented this recently to log changes to an Account object, and to notify the account holder if their account had expired – here’s the basics of the code, hopefully it’ll help someone else figure out how the pattern works

<?php
interface Observer
{
 public function update(Observable $subject);
} 

interface Observable
{
 public function attachObserver(Observer $dependent);
 public function detachObserver(Observer $dependent);
 public function notify();
}

class Account implements Observable
{
 public $status;
 private $_observers = array();

 public function __construct()
 {
  $this->attachObserver(new Logger());
  $this->attachObserver(new Mailer());
 }

 public function attachObserver(Observer $object)
 {
  $this->_observers[] = $object;
 }

 public function detachObserver(Observer $object)
 {
  foreach ($this->_observers as $index => $observer) {
   if ($object == $observer) {
    unset($this->_observers[$index]);
   }
  }
 }

 public function notify()
 {
  foreach ($this->_observers as $observer) {
   $observer->update($this);
  }
 }

 public function save()
 {
  $this->notify($this);
  $this->notify();
 }
}

class Logger implements Observer
{
 public function update(Observable $subject)
 {
 //Update status in log table
 echo "Updating status in log table.\n";
 }
}

class Mailer implements Observer
{
 public function update(Observable $subject)
 {
 switch (get_class($subject)) {      
 case "Account":
 if ($subject->status == "Expired") {
 //send email: "account expired"
 echo "Sending account expired email.\n";
 }
 }
 }
}

$account = new Account();
$account->status = "Expired";
$account->save();

The interfaces aren’t strictly necessary, but they help make the whole thing clearer (I hope).

$this->notify($this);

Problems with Japanese characters in MODx

August 5, 2010

Was having a problem with Japanese characters on a multi-lingual MODx site. I could see that the correct characters were being INSERTed into the database, but when I queried it directly after the insert I got just question marks out.

The solution was to change line 10 in manager/includes/config.inc.php from this:

$database_connection_method = ‘SET CHARACTER SET';

to this:

$database_connection_method = ‘SET NAMES';

The difference between ‘SET CHARACTER SET’ and ‘SET NAMES’ is ‘SET NAMES’ tells mysql server what character set is going to be used in the connection between the server and the client (rather than just what charset will be used on the server and on the client themselves). Because it wasn’t being used, the mysql server was just guessing the character set, and guessing it wrong.


Call a MODx snippet from within a snippet

April 22, 2010

This is really just  a note to remind myself how to to it, I keep forgetting:

$modx->runSnippet(string $snippetName [, array $params]);

http://wiki.modxcms.com/index.php/API:runSnippet


Managing which fields are displayed in a form in the MODx manager

April 2, 2010

There’s a plugin called managermanager, and the rules are set in /assets/plugins/managermanager/mm_rules.inc.php

You can hide fields, tabs and templates from the template dropdown for particular user roles. Handy for uncluttering your admin interface


Last resort debugging

September 4, 2009

When all else fails, I use The Scientific Method:

  1. comment out half the code
  2. see if I still get the bug
  3. if no then uncomment half the commented-out code and go to step 2
  4. if yes then comment out half the un-commented-out code and go to step 2

It’s fairly rare I need to do this in php, but currently hacking in vbscript which I don’t know at all …


phpunit bootstrap not working in windows

July 8, 2009

While following this tutorial and trying to set up phpunit to work with the Zend Framework, I couldn’t for the life of me figure out why my phpunit bootstrap seemed to be having no effect whatsoever. When I did figure it out, the problem was an old version of phpunit (3.3.2 instead of 3.3.17) – to update it I had to type (on the windows command line)

pear upgrade pear

and then

pear uninstall phpunit/PHPUnit

and then

pear install --alldeps phpunit/PHPUnit

Enhancing wordpress themes with regular expressions

June 22, 2009

I’ve been using wordpress quite a bit lately, and didn’t seem to be able to do something I wanted within the confines of a regular wordpress theme. Regular expressions came to the rescue – you can just use them in your theme and plugin files to do more-or-less anything you want with the content.

Here’s how I extracted the images so that they weren’t displayed within the post but instead in another div separate from the post text:

$images = ""; $matches = array();
if (preg_match_all("/(<img[^>]*>)/iUs",$content,$matches)) {
    $images = implode(" ",$matches[1]);
    $content = preg_replace("/<img[^>]*>/iUs","",$content);
}
$content = "<div class=\"text\">$content</div>".
           "<div class=\"images\">$images</div>\n";

See what I did? I grabbed all the image tags out of $content with preg_match_all(), put them all into the variable $images, and then got rid of them all in $content using preg_replace(). Then I displayed $content and $images in separate divs.

You can use it on a page level too – on the index.php page of a theme, say, you can do an ob_start() to buffer the content, then ob_get_clean() it into a variable and manipulate the variable with regular expressions before echoing it out. So, for example, you could extract all the images or links (or whatever) from the content and display them somewhere else on the page.


jpg not displaying in nokia browser

March 30, 2009

Ok so I’m doing a mobile website. When my application receives a GET request for an image, it uses wurfl to check the User-Agent header and figure out what phone the user has, then resizes the image accordingly (with caching, obviously).

It seemed to work fine on every phone in the office except my own – on mine (a basic nokia 2600) the image seemed to download, but just wouldn’t display (I was left with a correctly-sized blank instead). I could see the image was being generated and cached, and I could even save it on the phone, but when I tried to look at it it wouldn’t display.

Discovered it worked ok for gifs, and eventually I figured out the problem was jpeg image interlacing. The phone doesn’t seem to support it – turned it off and it works fine.


li bullets displaying in wrong place in IE

March 13, 2009

If the bullets are showing at the bottom rather than the top of your list items in Internet Explorer and ok in Firefox, then most likely your <li> items have a property called “layout”. The hasLayout property gets set by IE depending on the css and can’t be changed directly – the few times it’s happened to me (with css written by someone else), I’ve fixed it by removing “li { display: inline-block; }” from the css.

You can find a detailed explanation of the hasLayout property on http://www.satzansatz.de/cssd/onhavinglayout.html


Triggers within php objects using the __set() magic method

February 3, 2009

I don’t know if “trigger” is the right word for this behaviour, but if you want to automatically cause something to happen when an object variable is updated you can do so like this:

<?php
class classWithTrigger
{
    private $varOne = 0;
    private $varTwo = 0;

    public function __set($varName,$varValue)
    {
        $this->$varName = $varValue;
        if ($varName == "varOne") {
            $this->varTwo = $this->varOne * 9;
        }
    }

    public function __get($varValue)
    {
        return $this->$varValue;
    }
}

$test = new classWithTrigger;

echo $test->varOne; // Outputs 0
echo $test->varTwo; // Outputs 0

$test->varOne = 1;

echo $test->varOne; // Outputs 1
echo $test->varTwo; // Outputs 9

The __get() method gets called whenever an attempt is made (from outside the class) to get the value of an undefined or inaccessible (private or protected) variable – in this case it just returns the value as it would if the variable was public. Similarly, the __set() method gets called whenever an attempt is made (from outside the class) to set the value of an undefined or inaccessible variable. As you can see, you can use the fact that this gets called to trigger something, whether it’s an update to another object variable like here, or a DB update, or anything else you can think of.


Follow

Get every new post delivered to your Inbox.