Доброго времени суток уважаемый %username%.
Каждый программист хоть раз в своей жизни сталкивался с унаследованным кодом. Иногда такой код вызывает реакцию: «Что это за дрянь|лапша|говнокод, давайте его перепишем».
Так произошло и с проектом к которому я присоединился. 200-300 строчные методы, дублирование кода, процедурный подход вместо использования ООП не вызывали ни каких положительных эмоций. К счастью ПМ оказался очень адекватным человеком и не отмахнулся от просьбы выделить время на рефакторинги. Один из таких рефакторингов в итоге вылился в плагин валидации HTML-форм, которым я и хочу поделиться.
Причиной для создания этого плагина послужил код вида:
if($this->request->data['Model']['field'] > 0) {
$this->Session->setFlash(«message»);
$this->redirect($this->referer());
}
if($this->request->data['Model']['field'] == «string») {
$this->Session->setFlash(«message»);
$this->redirect($this->referer());
}
Которым изобиловали экшены. В некоторых экшенах количество аналогичных конструкций доходило до десятка. В итоге логика экшена полностью терялась за множественными ifами. Часто «коллекции» этих конструкций дублировались в нескольких экшенах и даже контроллерах. Те кто использует CakePHP, знают об удобном валидаторе полей моделей. В моем случае напрямую его не всегда удавалось задействовать, в формах передавались поля которые не ассоциировались с полями таблиц в моделях.
После рассмотрения вариантов рефакторинга для этого кода, было принято решение о создании класса-валидатора для передаваемых в формах данных. В качестве базы для него был использован класс ModelValidator. К сожалению его архитектура не позволила использовать наследование. Пришлось воспользоваться старым добрым копи-пастом.
В итоге получился класс, который позволяет проверять ассоциативные массивы вида:
array( 'Model' => array(field_list))
используя всю мощь класса Validation.
Примеры использования
HTML — форма:
echo $this->Form->create('Model');
echo $this->Form->input('first_field', array('type' => 'text'));
echo $this->Form->input('second_field', array('type' => 'text));
echo $this->Form->end();
Класс формы:
App::uses('Form', 'Forms.Lib/Form');
class ExampleForm extends Form {
public $model = 'Example';
public $fields = array(
'first_field' => array(
'type' => 'text',
),
'second_field' => array(
'type' => 'text',
)
);
public $validate = array(
'second_field' => array(
'isActive' => array(
'rule' => 'isActive',
'message' => "Is fields not active!"
),
),
'first_field' => array(
'aboveZero' => array(
'rule' => 'aboveZero',
'message' => "Number must be greater than 0",
),
),
);
/**
* @return bool
*/
public function isActive(){
if(isset($this->options['user_id'])) {
return false;
}
return (bool)$this->data[$this->model]['second_field'];
}
/**
* @return bool
*/
public function aboveZero() {
return (is_numeric($this->data[$this->model]['first_field']) && ($this->data[$this->model]['first_field'] > 0));
}
}
Использование класса ExampleForm для валидации данных формы:
class ExamplesController extends AppController {
public $name = 'Examples';
public $uses = array(
'Example',
);
public $components = array(
'Forms.FormValidator'
);
public $forms = array(
'ExampleForm',
);
/**
* Example validation html-form data in $this->request->data
*/
public function example() {
if ($this->ExampleForm->validates($this->request->data)) {
echo 'true validations';
} else {
echo 'false validation';
}
}
}
Использование класса ExampleForm для валидации ассоциативного массива:
public function example2() {
$data = array(
'Example' => array(
'first_field' => 0,
'second_field' => true
)
);
if ($this->ExampleForm->validates($data)) {
echo 'true validations';
} else {
echo 'false validation';
}
}
Использование класса ExampleForm для валидации ассоциативного массива, с передачей дополнительных данных для проверок:
public function example3() {
$data = array(
'Example' => array(
'first_field' => 0,
'second_field' => true
)
);
$this->ExampleForm->addOptions(array('user_id' => $this->Auth->user('id')));
if ($this->ExampleForm->validates($data)) {
echo 'true validations';
} else {
echo 'false validation';
}
}
В планах автоматическое добавление правил валидации на основании типа полей описанных в классе формы, хелперы для вывода формы с использованием разных шаблонов.
Код плагина на github.
Автор: bigl