Cytat
3. Mógłbyś wytłumaczyć o co chodzi z
Cytat
walidatory powinny być osobnymi obiektami implementującymi jakiś interfejs
Chodzi o to, że walidatory powinny być osobnymi obiektami wyspecjalizowanymi w walidacji konkretnego rodzaju. Daje to możliwość, bym utworzył sobie swój własny walidator, niewpisany na sztywno w kod Twojej klasy - innymi słowy: zwiększamy elastyczność narzędzia.
Tutaj masz przykładowy kod, który ilustruje jak mogło by to wyglądać (oczywiście brak tutaj dziesiątek rzeczy (ustawienia czytelnej treści błędu, wielu walidatorów dla jednego elementu, przedefiniowanych opcji dla walidatorów i całej masy innych rzeczy)):
<?php
namespace Crozin\Validation {
interface Validatable {
public function configure
(array $params = array()); public function getOptions();
public function getOption($key);
public function isValid($subject);
}
class Validator {
protected
$subjects = array(); protected
$validators = array();
protected
$errors = array(); protected
$data = array();
public function isValid() {
$isValid = true;
foreach ($this->subjects as $key => $subject) {
$result = $this->validators[$key]->isValid($subject);
if ($result instanceof Response) {
$isValid = false;
$this->errors[$key] = $result;
} else {
$this->data[$key] = $result;
}
}
return $isValid;
}
public function addSubjects
(array $subjects) { foreach ($subjects as $key => $subject) {
$this->addSubject($key, $subject);
}
}
public function addSubject($key, $subject) {
$this->subjects[$key] = $subject;
}
public function addValidators
(array $validators) { foreach ($validators as $key => $validator) {
$this->addValidator($key, $validator);
}
}
public function addValidator($key, Validatable $validator) {
$this->validators[$key] = $validator;
}
public function getData() {
return $this->data;
}
public function getErrors() {
return $this->errors;
}
}
class Response {
protected $msg;
protected $subject;
protected $validator;
public function __construct($msg, $subject, Validatable $validator) {
$this->msg = $msg;
$this->subject = $subject;
$this->validator = $validator;
}
public function getMsg() {
return $this->msg;
}
public function getSubject() {
return $this->subject;
}
public function getValidator() {
return $this->validator;
}
}
}
namespace Crozin\Validation\Validator {
use \Crozin\Validation\Validatable;
use \Crozin\Validation\Response;
abstract class Base {
protected
$options = array();
public function __construct
(array $options = array()) { $this->configure($options);
}
public function configure
(array $options = array()) { $this->options = $options;
}
public function getOptions() {
return $this->options;
}
public function getOption($key) {
return isset($this->options[$key]) ?
$this->options[$key] : null; }
}
class NIP extends Base implements Validatable {
public function isValid($subject) {
/* NIP ma nieprawidłowy format (np. podano litery) */
return new Response('format', $subject, $this);
}
/* NIP ma nieprawidłową sumę kontrolną */
return new Response('control.sum', $subject, $this);
}
return $subject;
}
}
class String extends Base implements Validatable {
public function isValid($subject) {
if ($this->getOption('trim')) {
$subject = trim($subject); }
if (($min = $this->getOption('min')) && strlen($subject) < $min) { return new Response('min', $subject, $this);
}
if (($max = $this->getOption('max')) && strlen($subject) > $max) { return new Response('max', $subject, $this);
}
return $subject;
}
}
class Email extends Base implements Validatable {
public function isValid($subject) {
/* Nieprawidłowy format */
return new Response('format', $subject, $this);
}
/* Jeżeli wpisy MX nie są dobre */
return new Response('mx', $subject, $this);
}
return $subject;
}
}
class NumberRange extends Base implements Validatable {
public function isValid($subject) {
if ($this->getOption('natural.only') && false == ctype_digit($subject)) { return new Response('not.natural', $subject, $this);
}
if ($subject < $this->getOption('min') || $subject > $this->getOption('max')) {
return new Response('out.of.range', $subject, $this);
}
return $subject;
}
}
}
namespace {
use \Crozin\Validation\Validator;
use \Crozin\Validation;
'firstname' => ' Krzysiek ',
'nickname' => 'Crozin',
'age' => '7',
'mail' => 'k...s@gmail.com'
);
$v = new Validator();
$v->addSubjects($_POST);
'firstname' => new Validator\String
(array('trim' => true, 'min' => 6)), 'nickname' => new Validator\String(),
'age' => new Validator\NumberRange
(array('natural.only' => true, 'min' => 9, 'max' => 99)), 'mail' => new Validator\Email()
));
if ($v->isValid()) {
} else {
foreach ($v->getErrors() as $error) {
var_dump(sprintf('%s - %s - %s - %s', get_class
($error->getValidator()), $error->getSubject(), $error->getMsg(), print_r($error->getValidator()->getOptions(), 1
))); }
}
}
Ale dlaczego to rozwiązanie jest o niebo lepsze? Chcę utworzyć nowy walidator... wystarczy mi obiekt dowolny, który implementuje interfejs \Crozin\Validation\Validatable; Chcę spersonalizować dany walidator? Podaję mu parametr. Itp. itd.
PS. Całość pisana "z palca" bez zastanowienia (jedynie sprawdziłem czy w ogóle działa) - więc jest to na pewno kod do poprawki (przemyślenia sposobu działania, przerobienia), ale daje jako taki zarys pewnej elastyczności.
Ten post edytował Crozin 21.04.2010, 22:03:19