Don't forget about the Specification pattern either though,
PHP Code:
include_once( 'interfaces/specification.php' );
/**
* @since Feb 2005
* @author les quinn (nukebaghdad@yahoo.co.uk)
* @version 0.1
* @abstract
*/
abstract class Specification implements ISpecification {
abstract public function isSatisfiedBy( IDataspace $dataspace, $logger );
public function orSpecification( ISpecification $specification ) {
return new OrSpecification( $this, $specification );
}
public function andSpecification( ISpecification $specification ) {
return new AndSpecification( $this, $specification );
}
}
final class OrSpecification extends Specification {
protected $or_specification = null;
protected $specification = null;
public function __construct( ISpecification $specification, ISpecification $or_specification ) {
$this -> or_specification = $or_specification;
$this -> specification = $specification;
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
return ( $this -> specification -> isSatisfiedBy( $dataspace, $logger ) || $this -> or_specification -> isSatisfiedBy( $dataspace, $logger ) );
}
}
final class AndSpecification extends Specification {
protected $and_specification = null;
protected $specification = null;
public function __construct( ISpecification $specification, ISpecification $and_specification ) {
$this -> and_specification = $and_specification;
$this -> specification = $specification;
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
return ( $this -> specification -> isSatisfiedBy( $dataspace, $logger ) && $this -> and_specification -> isSatisfiedBy( $dataspace, $logger ) );
}
}
Here are some rules,
PHP Code:
final class ExpectedArrayRule extends Specification {
protected $field_name;
protected $error_message = '';
public function __construct() {
$parameters = func_get_args();
$this -> field_name = array_shift( $parameters );
$this -> error_message = array_shift( $parameters );
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
if( is_array( $dataspace -> get( $this -> field_name ) ) && count( $dataspace -> get( $this -> field_name ) ) ) {
return true;
}
$logger -> set( $this -> field_name, $this -> error_message );
return false;
}
}
final class RegExpressionRule extends Specification {
protected $field_name;
protected $reg_expression;
protected $error_message = '';
public function __construct() {
$parameters = func_get_args();
$this -> field_name = array_shift( $parameters );
$this -> reg_expression = array_shift( $parameters );
$this -> error_message = array_shift( $parameters );
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
if( !preg_match( $this -> reg_expression, $dataspace -> get( $this -> field_name ) ) ) {
$logger -> set( $this -> field_name, $this -> error_message );
return false;
} else {
return true;
}
}
}
final class MinimumSizeRule extends Specification {
protected $field_name;
protected $length = 0;
protected $error_message = '';
public function __construct() {
$parameters = func_get_args();
$this -> field_name = array_shift( $parameters );
$this -> length = array_shift( $parameters );
$this -> error_message = array_shift( $parameters );
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
if( strlen( $dataspace -> get( $this -> field_name ) ) < $this -> length ) {
$logger -> set( $this -> field_name, $this -> error_message );
return false;
}
return true;
}
}
final class MaximumSizeRule extends Specification {
protected $field_name;
protected $length = 0;
protected $error_message = '';
public function __construct() {
$parameters = func_get_args();
$this -> field_name = array_shift( $parameters );
$this -> length = array_shift( $parameters );
$this -> error_message = array_shift( $parameters );
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
return false;
}
}
final class BetweenSizeRule extends Specification {
protected $field_name;
protected $minimum = 0;
protected $maximum = 0;
protected $error_message = '';
public function __construct() {
$parameters = func_get_args();
$this -> field_name = array_shift( $parameters );
$this -> minimum = array_shift( $parameters );
$this -> maximum = array_shift( $parameters );
$this -> error_message = array_shift( $parameters );
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
return false;
}
}
final class RequiredRule extends Specification {
protected $field_name;
protected $error_message = '';
public function __construct() {
$parameters = func_get_args();
$this -> field_name = array_shift( $parameters );
$this -> error_message = array_shift( $parameters );
}
public function isSatisfiedBy( IDataspace $dataspace, $logger ) {
$value = $dataspace -> get( $this -> field_name );
if( empty( $value ) || !isset( $value ) ) {
$logger -> set( $this -> field_name, $this -> error_message );
return false;
} else {
return true;
}
}
}
I use the Specification in this manner,
PHP Code:
// form handler abstraction
abstract class FormActionHandler implements IActionHandler {
protected $id;
protected $rules = array();
protected $children = array();
protected $successor = null;
public function __construct() {}
public function getId() {
return $this -> id;
}
public function hasChildren() {
return count( $this -> children );
}
public function getChildren() {
return $this -> children;
}
public function attach( IComposite $composite ) {
$this -> children[$composite -> getId()] = $composite;
}
public function setHandler( IActionHandler $successor ) {
$this -> successor = $successor;
}
public function addRule( ISpecification $rule ) {
$this -> rules[] = $rule;
}
protected function validate( IDataspace $request, $logger ) {
$validation = true;
foreach( $this -> rules as $rule ) {
$validation = $rule -> isSatisfiedBy( $request, $logger ) && $validation;
}
return $validation;
}
abstract public function execute( IDataspace $nodes, Context $context );
}
PHP Code:
final class BodyActionHandler extends FormActionHandler {
public function __construct() {
$this -> initialise();
$this -> id = 'body';
}
public function execute( IDataspace $nodes, Context $context ) {
if( $this -> validate( $request = $context -> get( 'request' ), $context -> get( 'logger' ) ) ) {
$this -> successor -> execute( $nodes, $context );
} else {
$page = new WebPage( $nodes, $request );
$page -> render( $request -> language().'/admin/login/body.tpl' );
}
}
protected function initialise() {
$this -> setHandler( new SuccessActionHandler() );
$this -> addRule( new PostRequestRule() );
}
}
final class SuccessActionHandler extends FormActionHandler {
public function __construct() {
$this -> initialise();
$this -> id = 'body';
}
public function execute( IDataspace $nodes, Context $context ) {
if( !$this -> validate( $request = $context -> get( 'request' ), $context -> get( 'logger' ) ) ) {
$this -> successor -> execute( $nodes, $context );
} else {
$request -> get( 'session' ) -> set( 'unique', null );
$username = $request -> get( 'email' );
$password = $request -> get( 'password' );
$user = new UserRecord( $context -> get( 'connection' ), new UserStatement() );
if( $user -> authenticate( $username, $password, true ) ) {
$session = $request -> get( 'session' );
$session -> set( 'id', $user -> id );
$session -> set( 'username', $user -> email );
$session -> set( 'password', md5( $password ) );
// $user -> acknowledge( time() );
header( 'location:/admin/' );
exit();
}
header( 'location:/admin/logout/' );
exit();
}
}
protected function initialise() {
$this -> setHandler( new FailureActionHandler() );
$this -> addRule( new UniqueTokenRule( 'unique', 'Suspected form tampering.' ) );
$this -> addRule( new RequiredRule( 'email', 'Email form field is required.' ) );
$this -> addRule( new RequiredRule( 'password', 'Password form field is required.' ) );
}
}
final class FailureActionHandler extends ActionHandler {
public function __construct() {
$this -> id = 'body';
}
public function execute( IDataspace $nodes, Context $context ) {
$page = new WebPage( $nodes, $request = $context -> get( 'request' ) );
$page -> render( $request -> language().'/admin/login/body.tpl' );
}
}
The idataspace type is just a container with accessors so nothing to chock on
Bookmarks