I was reading up on the Observer pattern, and decided it would be a perfect fit for my logging needs, which are currently pretty basic. My first implementation of the pattern is with my Email class (just your basic mime-mail class that uses the mail() function), in which I need to a) keep a 'hard-copy' record of emails sent, and b) document suspected contact form abuse and general mail() errors. These are currently all thrown in one log file.
I am using your typical, generic 'Observable' and 'Observer' interfaces, which I plan to implement in all my other classes. I decided to do this rather than make separate classes for each implementation of the pattern...we'll see how that goes...I'm also using pull instead of push here--i.e. the update() method simply passes the object to the observer which is responsible for figuring out what it wants to do with it. This seemed the most reasonable way to do this. However I have read through a few discussions that seem to favor pushing instead, so ?
Last note--my 'Logger' class currently only writes data in one way. That's all I have a need for now, but down the road when I need to write several different types of log formats, I plan to make the Logger abstract and extend it.
Just looking for any thoughts/criticisms/potential pitfalls with the way I've structured things.
Code:
PHP Code:
<?php
interface Observable {
public function attach(Observer $observer);
public function detach(Observer $observer);
public function notify();
}
interface Observer {
public function update(Observable $obs);
}
class Email implements Observable {
private $observers = array();
private $statusCode = 0;
// more vars here
/* STATUS CODES
0 email sent without issues
1 email could not be sent (mail() returned false)
2 bad header value, suspected spam, mail sent anyway
3 bad header value, suspected spam, mail not sent
*/
/*
snip--class methods here
*/
public function send()
{
// ....
// ....
// sets the status code and sends the email if no errors
$this->notify();
}
public function attach(Observer $obs)
{
$this->observers["$obs"] = $obs;
}
public function detach(Observer $obs)
{
unset($observers["$obs"]);
}
public function notify()
{
foreach ($this->observers as $obs) {
$obs->update($this);
}
}
}
class EmailLogger implements Observer {
private $statusCode;
private $loggerName = 'Email';
public function update(Observable $email)
{
if (!$email instanceof Email) { // must be passed an Email object
throw new Exception('EmailLogger was not passed an "Email" object.');
}
$this->statusCode = $email->getStatusCode();
switch($this->statusCode)
{
case 0:
$eventDescription = "MAIL FINE -- statusCode (".$this->statusCode.")";
$txt = $this->buildMailDescription($email);
$logger = new Logger($this->loggerName);
$logger->logEvent($eventDescription, $txt);
break;
case 1:
$eventDescription = "ERROR: mail() returned false -- statusCode (".$this->statusCode.")";
$txt = $this->buildMailDescription($email);
$logger = new Logger($this->loggerName);
$logger->logEvent($eventDescription, $txt);
break;
/*
..... switch statement continues ...
*/
}
}
private function buildMailDescription(Email $email)
{
$emailDesc = "TO:\t\t".implode(',', $email->getToArray())."\n";
$emailDesc .= "CC:\t".implode(',', $email->getCcArray())."\n";
$emailDesc .= "BCC:\t".implode(',', $email->getBccArray())."\n";
$emailDesc .= "FROM:\t".$email->getFrom()."\n\n";
$emailDesc .= "SUBJECT:\t".$email->getSubject()."\n\n";
$emailDesc .= "MESSAGE:\t".$email->getMessage()."\n\n";
return $emailDesc;
}
}
class Logger {
private $logFileName,
$logFilePath,
$logFileExt;
public function __construct( $logFileName,
$logFilePath=LOG_FILE_PATH,
$logFileExt=LOG_FILE_EXT )
{
$this->logFileName = $logFileName;
$this->logFilePath = $logFilePath;
$this->logFileExt = $logFileExt;
}
public function logEvent($eventDescription, $txt)
{
if (!is_dir($this->logFilePath)) {
throw new Exception('Logger error: log file directory not found ('.$fullPath.')');
}
$fullPath = $this->logFilePath.$this->logFileName.$this->logFileExt;
$writeTxt = "*******************************************************\n";
$writeTxt .= "EVENT DESCRIPTION:\t".$eventDescription."\n\n";
$writeTxt .= "*******************************************************\n";
$writeTxt .= "\tIP:\t\t\t".$_SERVER['REMOTE_ADDR']."\n";
$writeTxt .= "\tHOST:\t\t".gethostbyaddr($_SERVER['REMOTE_ADDR'])."\n";
$writeTxt .= "\tDATE:\t\t".date('m/d/Y H:i:s')."\n\n";
$writeTxt .= "-------------------------------------------------------\n";
$writeTxt .= $txt."\n\n";
if (!file_put_contents($fullPath, $writeTxt, FILE_APPEND)) { return false; }
return true;
}
}
// example usage
$email = new Email('plain');
$email->attach(new EmailLogger);
$email->setFrom('me@example.com');
// snip...more setters
$email->send();
?>
Bookmarks