php classes... validation - php

im am making a php validation class
with sub classes that extend it, eg, mobile, suburb, credit_card, ect
so, the idea is you can call
$validation = new Validation('mobile');
$valid = $validation->validate($number);
$validation->type('suburb');
$valid2 = $validation->validate($suburb);
now my idea for doing this is having
class Validation() {
private $v_type = null;
function __construct($type) {
$this->type($type);
}
public function type($type) {
$this->v_type = new $type();
}
public function validate($info) {
return $this->v_type->validate($info);
}
}
as a very basic example
but is there a better way of doing this?

You could do it this way, but it could be improved. Having the actual validators capsule their own validation logic is good. Extending them from a base class isn't. Let's implement an interface instead. This way, any class can be a Validator.
interface IValidate
{
public function validate($value);
}
Your validators would look like this then:
class IsNumeric implements IValidate
{
public function validate($value)
{
return is_numeric($value);
}
}
and
class GreaterThan implements IValidate
{
protected $_value;
public function __construct($value)
{
$this->_value = $value;
}
public function validate($value)
{
return $value > $this->_value;
}
}
You'd still have a main Validator class. Unlike in your example, the Validator below accepts multiple Validators, which will allow you to create a Filter Chain.
class Validator implements IValidate
{
protected $_validators;
public function addValidator(IValidate $validator)
{
$this->_validators[] = $validator;
return $this;
}
public function validate($value)
{
foreach($this->_validators as $validator) {
if ($validator->validate($value) === FALSE) {
return FALSE;
}
}
return TRUE;
}
}
And this could be used like:
$validator = new Validator;
$validator->addValidator(new IsNumeric)
->addValidator(new GreaterThan(5));
var_dump( $validator->validate('ten') ); // FALSE
var_dump( $validator->validate('10') ); // TRUE
var_dump( $validator->validate('1') ); // FALSE
The above is pretty much a Command pattern. And due to the Validator implementing IValidate as well, it is also a Composite. You could take the Validator chain from above and stack it into another Validator Chain, e.g.
$numericGreaterThanFive = new Validator;
$numericGreaterThanFive->addValidator(new IsNumeric)
->addValidator(new GreaterThan(5));
$otherValidator = new Validator;
$otherValidator->addValidator(new Foo)
->addValidator(new Bar)
->addValidator($numericGreatherThanFive);
For convenience, you could add a static factory method for creating Validators with the actual Validation Command objects (as shown elsewhere).
On a sidenote: the Zend Framework already has an extensive number of Validators you can build on. Since ZF is a component library, you can use them without having to migrate your entire application to ZF.

Usually you do these kind of things using the Factory pattern, something like this:
class ValidatorFactory {
public static function get($type) {
$validator = "Validator_$type";
return new $validator();
}
}
$valid = ValidatorFactory::get('mobile')->validate($number);
Would of course need some error checking and such, but you should get the idea

...
public function type($type) {
return new self($type);
}
...
Note: This one every time returns a new instance of your Validator class so it would be a better idea to use the Factory pattern as Dennis suggested or not to tie the new Validator to the type() method.

Related

Return different objects based on conditional argument

I need help with some code desiging. I have a package which is used in many projects.
$p = new Package();
$result = $p->method();
While the Package looks like:
class Package {
public function method($fooArg = 1, $barArg = 1)
{
// some logic
return new SomeClass(
$fizzArg,
$buzzArg
);
}
}
Now, in one project which is using Package I need to change returned class. So, the call will look like this:
$p = new Package();
$result = $p->method(10, 10, true);
And the Package will look like this:
class Package {
public function method($fooArg = 1, $barArg = 1, $condArg = false)
{
// some logic
if (false === $condArg) {
return new SomeClass(
$fizzArg,
$buzzArg
);
}
return new MyNewClass(
$fizzArg,
$fooBarArg
);
}
}
Which design pattern should be used here? I do not want to return different object types based on condition, because it seems very ugly to me.
Since you explicitly set $condArg from the calling script and it is the only argument that control which instance to return, consider to create a second public method to return MyNewClass, and extract some logic into private method to share it between 2 public methods:
class Package {
public function method($fooArg = 1, $barArg = 1)
{
list $fizzArg, $fooBarArg = $this->someLogic($fooArg, $barArg);
return new SomeClass(
$fizzArg,
$buzzArg
);
}
public function newMethod($fooArg = 1, $barArg = 1)
{
list $fizzArg, $fooBarArg = $this->someLogic($fooArg, $barArg);
return new MyNewClass(
$fizzArg,
$fooBarArg
);
}
protected function someLogic($fooArg, $barArg)
{
// some logic
return [
$fizzArg,
$fooBarArg
]
}
}
This could be resolved with a combination of the Factory and Dependency Injection patterns:
The example below is a bit long winded, but it illustrates the basic principle. By providing your Package class with a factory implemented by the specific project. You don't need to change the code of that class. Instead, the changes are made with abstractions via interfaces.
/*
* Shared library
*/
interface IEntity
{
}
interface IFactory
{
/**
* #param $arg1
* #param $arg2
* #return IEntity
*/
public function create($arg1, $arg2);
}
class Package
{
protected $factory;
public function __construct(IFactory $factory)
{
$this->factory = $factory;
}
public function method($arg1, $arg2)
{
return new $this->factory->create($arg1, $arg2);
}
}
/*
* Project A
*/
class FactoryA implements IFactory
{
public function create($arg1, $arg2)
{
return new EntityA();
}
}
class EntityA implements IEntity
{
public function construct($arg1, $arg2)
{
}
}
/*
* Project B
*/
class FactoryB implements IFactory
{
public function create($arg1, $arg2)
{
return new EntityB();
}
}
class EntityB implements IEntity
{
public function construct($arg1, $arg2)
{
}
}
From a purely theoretical point of view, the very idea to use such a package that has to return something else based on where it is used is very ugly. This way it means that the widely-used package depends on a details of the package that uses it and this to me is a signal that you have to scrap the idea entirely and not use this package in this one project.
Your Package seems like a Factory method, it builds objects according to parameters. If I get it right, now you want to have different Packages for different projects with different objects.
Well Abstract factory is what you are looking for.
Make your Package abstract. Have two implementations, and load the proper package in the initiation phase you can use reflection or configuration or whatever PHP lets you do.
Note: It seems that there is some other logic in your Package class, if that logic is independent of building objects extract it to a different class, or vise versa.
since you don't have access to all project using Package, and you can change the source of Package if it does not affect other projects, then it is safer to create a descendant of Package instead. this way, you can change existing methods without affecting other projects, and you can also add new methods.
include('package.php');
class myPackage extends Package(){
public function newMethod($arg1, $arg2){
return new otherClass($arg1, $arg2);
}
//if you want to change existing method
public function method($fooArg = 1, $barArg = 1){
//some new logic
}
}
then you can use it in your project:
$obj = new myPackage();
if ($i_want_regular_class){
$newObj = $obj->method(1, 2); // call parent's method or modified parent's method
} else {
$newObj = $obj->newMethod(3, 4); // call new method
}
as for why i suggest you to create new method is because you already know which object you want to create, hence the argument passed to the method. so instead of putting the conditional in the method, why not put the conditional in the logic and call the appropriate method?

PHP unit testing External static method call from different class

I am trying to write a unit test for a function that immediately loads an object from a different class that uses the input to the function as a parameter. I am new to php unit testing and couldn't find anything that address my particular problem. A few leads that I had that led to no avail was using an injector, and trying to us a reflection.
The code I am trying to write a unit test for is:
public static function isUseful($item) {
$objPromo = MyPromoCodes::Load($item->SavedSku);
if (!is_null($objPromo)
&& ($objPromo->PromoType == MyPromoCodes::Interesting_Promo_Type)) {
return true;
}
return false;
}
My attempt at mocking this out:
public function testIsUseful() {
$injector = $this->getMockBuilder('MyPromoCodes')
->setMethods(array('Load'))
->getMock();
$objPromo = $this->getMock('MyPromoCodes');
$objPromo->PromoType = 'very interesting promo type';
$injector->set($objPromo, 'MyPromoCodes');
$lineItem1 = $this->getDBMock('LineItem');
$this->assertTrue(MyClass::isUseful($lineItem1));
}
however this doesn't work because there is no set method for this object....
Not sure what else to try, any help would be appreciated.
I made the library that makes static classes mocking possible:
class MyClass {
public static $myPromoCodes = 'myPromoCodes';
public static function isUseful($item) {
$objPromo = self::$MyPromoCodes::Load($item->SavedSku);
if (!is_null($objPromo)
&& ($objPromo->PromoType == MyPromoCodes::Interesting_Promo_Type)) {
return true;
}
return false;
}
}
class MyClassTest extends \PHPUnit_Framework_TestCase
{
public function testSomething()
{
$myClass = Moka::stubClass('MyClass');
$myClass::$myPromoCodes = Moka::stubClass(null, ['::Load' => (object)[
'PromoType' => MyPromoCodes::Interesting_Promo_Type
]]);
$this->assertTrue($myClass::isUseful((object)['SavedSku' => 'SKU']);
$this->assertEquals([['SKU']], $myClass::$myPromoCodes->moka->report('::Load'));
}
}
To start with you cannot mock static method with PHPUnit. At least not with 4.x and 5.x.
I would suggest a DI approach like this:
class MyClass
{
private $promoCodesRepository;
public function __construct(MyPromoCodesRepository $promoCodesRepository)
{
$this->promoCodesRepository = $promoCodesRepository;
}
public function isUseful(MyItem $item)
{
$objPromo = $this->promoCodesRepository->Load($item->SavedSku);
// ...
}
}
Here you can easily mock the Load method.
Unfortunately the "static" approach creates a lot of issues during tests so it is better to avoid it whenever possible.

How to use reusable validation in a ValueObject

I'm trying to get my head around combining some techniques.
It seems good practice to never make it possible to create a ValueObject that is not valid. The ValueObject constructor therefor should fail whenever the provided content is not good enough to create a valid ValueObject. In the examples I have, an EmailAddress object can only be created when there is a value present. So far, so good.
Validating the value of the provided emailaddress, that's where I begin to doubt the principles. I have four examples, but I can't tell which one should be considered the best practice.
Example 1 is the easy one: simply a construct function, a required parameter "value", and a separate function validate to keep the code clean. All the validation code stays inside the class, and will never be available to the outside world. The class has only one purpose: store the emailaddress, and make sure it will never be an invalid one. But the code will never be reusable - I create an object with it, but that's all.
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
Example 2 makes the validate function a static function. The function will never change the state of the class, so it is a correct use of the static keyword, and the code in it will never be able to change anything to any instance created from the class embedding the static function. But if I want to reuse the code, I can call the static function. Still, this feels dirty to me.
public function __construct ($value)
{
if ( $self::validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
public static function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
Example 3 introduces another class, hardcoded inside the body of my object. The other class is a validation class, containing the validation code, and creates thus a class that can be used whenever and wherever I need a validation class. The class itself is hardcoded, which also means that I create a dependency on that validation class, which should be always nearby, and is not injected through dependency injection. One could say that having a validator hard coded is as bad as having the complete code embedded in the object, but on the other hand: DI is important, and this way one has to create a new class (extending, or simply rewriting) to simply change the dependency.
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
$validator = new \Validator();
return $validator->validate($value);
}
Example 4 uses the validator class again, but puts it in the constructor. My ValueObject thus needs a validator class already present and created, before creating the class, but it is possible to easily overwrite the validator. But how good is it for a simple ValueObject class to have such a dependency in the constructor, as the only thing really important is the value, it should not be my concern to know how and where to handle if the email is correct, and providing a correct validator.
public function __construct ($value, \Validator $validator)
{
if ( $validator->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
The last example I started thinking about, is providing a default validator, and meanwhile make it possible to inject through DI an overwrite for the validator in the constructor. But I started doubting how good a simple ValueObject is when you overwrite the most important part: the validation.
So, anyone has an answer which way one should best write this class, that is correct for something as easy as an emailaddress, or something more complex like a barcode or a visa card or whatever one may think about, and doesn't violate DDD, DI, OOP, DRY, wrong use of static, and so on...
The complete code:
class EmailAddress implements \ValueObject
{
protected $value = null;
// --- --- --- Example 1
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
// --- --- --- Example 2
public function __construct ($value)
{
if ( $self::validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
public static function validate ($value)
{
return is_string($value); // Wrong function, just an example
}
// --- --- --- Example 3
public function __construct ($value)
{
if ( $this->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
protected function validate ($value)
{
$validator = new \Validator();
return $validator->validate($value);
}
// --- --- --- Example 4
public function __construct ($value, \Validator $validator)
{
if ( $validator->validate($value) )
{
throw new \ValidationException('This is not an emailaddress.');
}
$this->value = $value;
}
}
Example 4!
Why? Because it's testable, plain and simple.
Depending on what your validator actually does (in some circumstances your validator may rely on an API call or a call to a database) the injectable validator is completely testable via mocks. All of the other's are either impossible to test under the circumstances I just mentioned, or incredibly hard to test.
EDIT: For those wondering how the dependency injection method helps with testing then consider the CommentValidator class below that utilises a standard Akismet spam checking library.
class CommentValidator {
public function checkLength($text) {
// check for text greater than 140 chars
return (isset($text{140})) ? false : true;
}
public function checkSpam($author, $email, $text, $link) {
// Load array with comment data.
$comment = array(
'author' => $author,
'email' => $email,
'website' => 'http://www.example.com/',
'body' => $text,
'permalink' => $link
);
// Instantiate an instance of the class.
$akismet = new Akismet('http://www.your-domain.com/', 'API_KEY', $comment);
// Test for errors.
if($akismet->errorsExist()) { // Returns true if any errors exist.
if($akismet->isError('AKISMET_INVALID_KEY')) {
return true;
} elseif($akismet->isError('AKISMET_RESPONSE_FAILED')) {
return true;
} elseif($akismet->isError('AKISMET_SERVER_NOT_FOUND')) {
return true;
}
} else {
// No errors, check for spam.
if ($akismet->isSpam()) {
return true;
} else {
return false;
}
}
}
}
And now below, when you're setting up your unit tests we have a CommentValidatorMock class that we use instead, we have setters to manually change the 2 output bools we can have, and we have the 2 functions from above mock'd up to output whatever we want without having to go through the Akismet API.
class CommentValidatorMock {
public $lengthReturn = true;
public $spamReturn = false;
public function checkLength($text) {
return $this->lengthReturn;
}
public function checkSpam($author, $email, $text, $link) {
return $this->spamReturn;
}
public function setSpamReturn($val) {
$this->spamReturn = $val;
}
public function setLengthReturn($val) {
$this->lengthReturn = $val;
}
}
If you're serious about unit testing then you need to use DI.
The first instinct is usually the best. You should use the first option. EmailAddress is a value object. It can be reused in other value objects or entities. I don't understand why you think it's not reusable. You can have a "shared library" of these common value objects used in other bounded contexts. Just be careful what you put in there. They would need to be truly generic if that's even conceptually possible.
I think if you use separate validation methods or move the validators to separate class will be butter and prevent DRY
class EmailAddress{
protected $value;
public function __construct ($value)
{
$this->value = \validateEmailAddress($value);
}
}
function validateEmailaddress(string $value) : string
{
if(!is_string($value)){
throw new \ValidationException('This is not an emailaddress.');
} // Wrong function, just an example
return $value;
}
//OR for strict OOP people
final class VOValidator{
private function __construct(){}
public static function validateEmailaddress(string $input): string{...}
}
//I will prefer even go far and use Either from (FP monads)
interface ValueObejctError {}
class InvalidEmail implements ValueObjectError {}
function validateEmailaddress(string $input): Either {
// it will be better if php supported generic so using Either<InvalidaEmail, string> is more readable but unfortunately php has no generic types, maybe in future
return is_string($input)
? new Right($input)
: new Left(new InvalidEmail());
}

Validation Class with fluent interface

I'm currently struggling with some form validation. I'm working with the class below, which is intended to be a fluent interface.
class Validator implements ValidatorInterface {
protected $_count_validators = 0;
protected $_validators;
protected $errorMsg;
public function __construct($errorMsg = '')
{
$this->errorMsg = $errorMsg;
}
public function addValidator(ValidatorInterface $validator)
{
$this->_count_validators++;
$this->_validators[] = $validator;
return $this;
}
public function validate($value)
{
foreach($this->_validators as $validator) {
if ($validator->validate($value) === false) {
return false;
}
}
return true;
}
public function getError()
{
return $this->errorMsg;
}
}
It actually works 75 % - and I can add validators like this:
$postalcodeValidator = new \Framework\Formular\Validator\Validator();
$validatePostalcode= $postalcodeValidator->addValidator(new \Framework\Formular\Validator\NotEmpty)
->addValidator(new \Framework\Formular\IsNumeric);
$cityValidator = new \Framework\Formular\Validator\Validator();
$validateCity = $lastnameValidator->addValidator(new \Framework\Formular\Validator\NotEmpty);
Now I can just write:
$result = $postalcodeValidator->validate('00000');
- or -
$result = $cityValidator->validate('London');
And I will have a boolean.
My problem is, that I need to make it easy to set some errors. In the above example - if I just added a getErrors()-function in the class - I had to get the errors for every new instantiation of the class. I want to make a function for getting all errors.
Can you help me on a solution for that?
Thanks in advance,
denlau
A simple way is to implement a static member in an abstract validator class. All your concrete Validator extends this, and will add automaticly errors to this member. Finally you can get this static member with one call. But this is an anti-pattern and you have to reset this member after getting errors.
A better practice is to use the composite pattern. A class where you can add one or more elements with assigned validators. This composite class will execute all validators on your assigned elements and collect all error messages from each validator. Then you can retrieve all collected error messages from your composite, with one call.
For more information about composite pattern see here on wiki
Here an example..
$elementA = new ElementA; // implements Validable
$elementA->addValidator(new ValidatorA)->addValidator(new ValidatorB);
$elementB = new ElementB; // implements Validable
$elementB->addValidator(new ValidatorC);
$elementA->setValue('any_posted_value_to_validate');
$elementB->setValue('another_any_posted_value_to_validate');
$composite = new Composite; // implements Validable
$composite->addElement($elementA)->addElement($elementB);
if (!composite->isValid()) { // will execute all validators on all elements
$errorMessages = $composite->getErrors();
}
Within your composite..
public function isValid()
{
$isValid = true;
foreach ($this->elements as $element) {
if (!$element->isValid()) { // will execute all assigned validators to this element
$this->addErrors($element->getErrors());
$isValid = false;
}
}
return $isValid;
}
The Validable Interface
interface Validable
{
public function isValid();
public function getErrors();
}

Lost access to same property trying to use best practice / design pattern

I had:
in a class implementing Validator:
an $errormessages property
an isCorrect() method
In the isCorrect method, I had:
switch ($type):
case 'email':
isEmailCorrect();
case 'password':
isPasswordCorrect();
case 'x':
isXCorrect();
isEmailCorrect(), isPasswordCorrect() and isXCorrect() had access to the same property with all error messages
Now, I have:
in Validator:
an $errormessages property
in an EmailValidator class extending Validator:
an isCorrect() method
in a PasswordValidator class extending Validator:
an isCorrect() method
in a XValidator class extending Validator:
an isCorrect() method
Now, in a file calling the isCorrect() methods, I have:
$EmailValidator = new EmailValidator();
$PasswordValidator = new PasswordValidator();
$XValidator = new XValidator();
$EmailValidator->isCorrect(), $PasswordValidator->isCorrect() and $XValidator->isCorrect() don't have access to the same property with all error messages
$errormessages are in different instances of different classes. They should be one, but are three.
What now?
I think you should develop another class: a ValidatorChain, which takes an arbitrary amount of validators, and that aggregates the errormessages of all validators that it has tested
For reference see the docs on Zend Framework's Validator Chain
EDIT
Now that I re-evaluate your question (thanks to Bryan M's comment); why do you want each individual Validator to have access to other Validators' error messages? I would say that collecting each individual Validators' error messages is the responsibility of an object higher in the hierarchy.
If, however, you want individual Validators to be able to act based on context, in other words, based on what the results of other Validators are, then I suppose you could add a $context parameter to the isCorrect method. This could for instance accept an arbitrary amount of Validators or something similar.
Something like:
interface ValidatorInterface
{
public function isCorrect( array $context );
public function getMessages();
}
abstract class ValidatorContextOptions
{
const SHOULD_BE_PRESENT = 'shouldBePresent';
const SHOULD_NOT_BE_PRESENT = 'shouldNotBePresent';
const SHOULD_BE_VALID = 'shouldBeValid';
}
class EmailValidator implements ValidatorInterface
{
protected $_field;
protected $_contextOptions = array();
protected $_messages = array();
public function __construct( $field, array $contextOptions )
{
$this->_field = $field;
$this->_contextOptions = $contextOptions;
}
public function isCorrect( array $context = null )
{
foreach( $this->_contextOptions as $field => $options )
{
foreach( $options as $option )
{
switch( $option )
{
case ValidatorContextOptions::SHOULD_NOT_BE_PRESENT:
if( isset( $context[ $field ] )
&& $context[ $field ] instanceof ValidatorInterface )
{
$this->_messages[] = $field . ' should not be present';
return false;
}
break;
case ValidatorContextOptions::SHOULD_BE_PRESENT:
if( !isset( $context[ $field ] )
|| !$context[ $field ] instanceof ValidatorInterface )
{
$this->_messages[] = $field . ' should be present';
return false;
}
break;
case ValidatorContextOptions::SHOULD_BE_VALID:
if( !isset( $context[ $field ] )
|| !$context[ $field ] instanceof ValidatorInterface
|| !$context[ $field ]->isCorrect() )
{
$this->_messages[] = $field . ' should be valid';
return false;
}
break;
}
}
}
// some dummy function which you should replace with real validation
return isAnEmailAddress( $this->_field );
}
public function getMessages()
{
return $this->_messages;
}
}
Usage:
$emailValidatorContextOptions = array
(
'phone' => array(
ValidatorContextOptions::SHOULD_BE_PRESENT,
ValidatorContextOptions::SHOULD_BE_VALID
)
);
$phoneValidator = new PhoneValidator( $phoneString );
$emailValidator = new EmailValidator( $emailString, $emailValidatorContextOptions );
if( !$emailValidator->isCorrect( array( 'phone' => $phoneValidator ) ) )
{
print_r( $emailValidator->getMessages() );
}
What I've shown here, needs a lot more thinking (and I really mean A LOT), is buggy as hell and definately not bulletproof. But I hope you catch my drift of where I'm going with this.
Moreover, where do you insert the values in your validator that need to be validated anyway?
Well you could make an external properties factory to control access to your property, assuming you are talking about properties files that is the approach I usually take.
If you are referring to a shared field then you can place it in your base class and access it that way.
I'll often use Zend_Validate classes to perform the validation, and aggregate any error message to a property on the object that's being validated (as well as a flag that control valid status).
My setup would be similar to this:
class User {
public $email;
protected $_errorMessages = array();
public function validate()
{
$valid = true;
$emailValidator = new EmailValidator();
if (!$emailValidator->isCorrect($this->email)) {
$valid = false;
// validation message are added to the $errormessages property in
// the validator class upon failure of isCorrect()
$this->_errorMessages[] = $emailValidator->getMessages();
}
// repeat this for all your validators
return $valid
}
public function getErrorMessages()
{
return $this->_errorMessages();
}
}
// in your page....
if (!$user->validate()) {
$messages = $user->getErrorMessages();
}
If I read you right, you want multiple instances to share the same error messages property, such that you can instantiate several validators and have them all contribute to a single array.
If this is the case, there are a few ways to do it. One would be to create a validator manager class which has responsibility for instantiating and registering validators. Then once validation is complete you could call $validator_manager->getErrors() which would aggregate the errors present in all the validators registered with it.
Another way you could do it would be to use a singleton error store class, which you acquire in the constructor of each validator. Each validator's addError() method would then delegate the job to the singleton.
There are other methods still, but basically you're going to have to use another object, either for managing the validators or storing the errors.
Someone below mentioned using a singleton for this.
I am not convinced that it's a great use of that design pattern, especially since it's commonly held that singletons are the "anti-pattern" and often over/mis-used.
Nonetheless, keeping that in mind, here's an example along those lines:
<?php
//Error Class implemented as a Singleton
class ErrorClass
{
static private $instance = false;
static private $errorMessages;
function getInstance() {
if (!self::$instance) {
self::$instance = new ErrorClass();
self::$errorMessages = "No errors;";
}
return self::$instance;
}
public function setError($errorMessage){
self::$instance->errorMessages .= $errorMessage;
}
public function getError(){
return self::$instance->errorMessages;
}
}
abstract class AbstractClass
{
// Force Extending class to define this method
abstract protected function isCorrect($b);
// Common Method for setting error
public function setError($errorMessage) {
ErrorClass::getInstance()->setError($errorMessage);
}
// Common Method for getting error
public function getError() {
return ErrorClass::getInstance()->getError();
}
}
class EmailValidator extends AbstractClass
{
public function isCorrect($b) {
if(!$b) {
$this->setError('EmailValidator->isCorrect();');
}
}
}
class PasswordValidator extends AbstractClass
{
public function isCorrect($b) {
if(!$b) {
$this->setError('PasswordValidator->isCorrect();');
}
}
}
// Then in your code
$errorState = 1; // used for testing purposes
$EmailValidator = new EmailValidator();
$EmailValidator->isCorrect($errorState);
$PasswordValidator = new PasswordValidator();
$PasswordValidator->isCorrect($errorState);
echo $EmailValidator->getError();
echo $PasswordValidator->getError();

Categories