Файл: system/core/form.php
Строк: 300
<?php
class cmsForm {
public $is_tabbed = false;
private $params = array();
private $structure = array();
private $disabled_fields = array();
//============================================================================//
//============================================================================//
/**
* Заполняет массив полей формы
* Должен быть переопределен в наследуемом классе
*/
// public function init(){
// return array();
// }
public function setStructure($structure=array()){
$this->structure = $structure;
}
/**
* Возвращает массив полей формы
* @return array
*/
public function getStructure(){
return $this->structure;
}
//============================================================================//
//============================================================================//
public function setParams($params=array()){
$this->params = $params;
}
public function getParams(){
return $this->params;
}
//============================================================================//
//============================================================================//
public function addHtmlBlock($id, $content=null){
$this->structure[$id] = array(
'type' => 'html',
'content' => $content
);
return $id;
}
public function addHtmlBlockToBeginning($id, $content=null){
$block = array(
'type' => 'html',
'content' => $content
);
$this->structure = array($id => $block) + $this->structure;
return $id;
}
public function addHtmlBlockAfter($after_id, $id, $content=null){
$block = array(
'type' => 'html',
'content' => $content
);
$pos = array_search($after_id, array_keys($this->structure));
$before = array_slice($this->structure, 0, $pos+1);
$after = array_slice($this->structure, $pos + 1);
$this->structure = $before + array($id => $block) + $after;
return $id;
}
//============================================================================//
//============================================================================//
/**
* Добавляет набор полей в форму.
* Возращает id набора полей
* @param string $title Заголовок набора полей
* @param string $id ID набора полей
* @return mixed
*/
public function addFieldset($title='', $id=null, $options=array()){
if (is_null($id)){
$id = sizeof($this->structure);
}
$fieldset = array(
'type' => 'fieldset',
'title' => $title,
'childs' => array()
);
$fieldset = array_merge($fieldset, $options);
$this->structure[$id] = $fieldset;
return $id;
}
public function addFieldsetToBeginning($title='', $id=null, $options=array()){
if (is_null($id)){
$id = sizeof($this->structure);
}
$fieldset = array(
'type' => 'fieldset',
'title' => $title,
'childs' => array()
);
$fieldset = array_merge($fieldset, $options);
$this->structure = array($id => $fieldset) + $this->structure;
return $id;
}
public function addFieldsetAfter($after_id, $title='', $id=null, $options=array()){
if (is_null($id)){
$id = sizeof($this->structure);
}
$fieldset = array(
'type' => 'fieldset',
'title' => $title,
'childs' => array()
);
$fieldset = array_merge($fieldset, $options);
$pos = array_search($after_id, array_keys($this->structure));
$before = array_slice($this->structure, 0, $pos+1);
$after = array_slice($this->structure, $pos + 1);
$this->structure = $before + array($id => $fieldset) + $after;
return $id;
}
public function getLastFieldsetId(){
$ids = array_keys($this->structure);
return $ids[count($ids)-1];
}
/**
* Добавляет поле в указанный набор полей формы
* @param string $fieldset_id ID набора полей
* @param string $name Название поля
* @param array $params Параметры поля
*/
public function addField($fieldset_id, $field){
$this->structure[ $fieldset_id ]['childs'][] = $field;
}
public function addFieldToBeginning($fieldset_id, $field){
$this->structure[ $fieldset_id ]['childs'] = array($field->name => $field) + $this->structure[ $fieldset_id ]['childs'];
}
//============================================================================//
//============================================================================//
/**
* Изменяет аттрибут набора полей в форме
* @param string $fieldset_id ID набора полей
* @param string $attr_name Название аттрибута
* @param mixed $value Новое значение
*/
public function setFieldsetAttribute($fieldset_id, $attr_name, $value){
$this->structure[ $fieldset_id ][ $attr_name ] = $value;
}
/**
* Изменяет аттрибут поля в форме
* @param string $fieldset_id ID набора полей
* @param string $field_name Название поля
* @param string $attr_name Название аттрибута
* @param mixed $value Новое значение
*/
public function setFieldAttribute($fieldset_id, $field_name, $attr_name, $value){
foreach( $this->structure[ $fieldset_id ]['childs'] as $field) {
if ($field->getName() == $field_name){
$field->setOption($attr_name, $value);
break;
}
}
}
//============================================================================//
//============================================================================//
/**
* Скрывает набор полей в форме
* @param string $fieldset_id ID набора полей
*/
public function hideFieldset($fieldset_id){
$this->setFieldsetAttribute($fieldset_id, 'is_hidden', true);
}
/**
* Скрывает поле в форме
* @param string $fieldset_id ID набора полей
* @param string $field_name Название поля
*/
public function hideField($fieldset_id, $field_name){
$this->setFieldAttribute($fieldset_id, $field_name, 'is_hidden', true);
}
//============================================================================//
//============================================================================//
/**
* Удаляет набор полей из формы
* @param string $fieldset_id ID набора полей
*/
public function removeFieldset($fieldset_id){
unset($this->structure[ $fieldset_id ]);
}
/**
* Удаляет поле из формы
* @param string $fieldset_id ID набора полей
* @param string $field_name Название поля
*/
public function removeField($fieldset_id, $field_name){
foreach( $this->structure[ $fieldset_id ]['childs'] as $field_id => $field) {
if ($field->getName() == $field_name){
unset($this->structure[ $fieldset_id ]['childs'][ $field_id ]);
break;
}
}
}
/**
* Отключает поле в форме
* Поле не удаляется, но перестает участвовать в парсинге и валидации
*
* @param string $field_name Название поля
*/
public function disableField($field_name){
$this->disabled_fields[] = $field_name;
}
//============================================================================//
//============================================================================//
/**
* Возвращает массив полей формы, заполнив их значениями переданными в запросе $request
* @param cmsRequest $request
* @param bool $is_submitted
* @param array $item
* @return array
*/
public function parse($request, $is_submitted=false, $item=false){
$result = array();
foreach($this->structure as $fieldset){
if (!isset($fieldset['childs'])) { continue; }
foreach($fieldset['childs'] as $field){
$name = $field->getName();
// если поле отключено, пропускаем поле
if (in_array($name, $this->disabled_fields)){ continue; }
$is_array = strstr($name, ':');
$value = $request->get($name, null);
if (is_null($value) && $field->hasDefaultValue() && !$is_submitted) { $value = $field->getDefaultValue(); }
$old_value = $item ? (isset($item[$name]) ? $item[$name] : null) : null;
$field->setItem($item);
$value = $field->store($value, $is_submitted, $old_value);
if ($value === false) { continue; }
if (!$is_array){
$result[$name] = $value;
}
if ($is_array){
$name_parts = explode(':', $name);
$result[$name_parts[0]][$name_parts[1]] = $value;
}
}
}
return $result;
}
//============================================================================//
//============================================================================//
/**
* Проверяет соответствие массива $data правилам
* валидации указанным для полей формы
* @param cmsController $controller
* @param array $data
* @param bool $is_check_csrf
* @return bool Если ошибки не найдены, возвращает false
*/
public function validate($controller, $data, $is_check_csrf = true){
$errors = array();
//
// Проверяем CSRF-token
//
if ($is_check_csrf){
$csrf_token = $controller->request->get('csrf_token');
if ( !self::validateCSRFToken( $csrf_token ) ){
return true;
}
}
//
// Перебираем поля формы
//
foreach($this->structure as $fieldset){
if (!isset($fieldset['childs'])) { continue; }
foreach($fieldset['childs'] as $field){
$name = $field->getName();
// если поле отключено, пропускаем поле
if (in_array($name, $this->disabled_fields)){ continue; }
// если нет правил, пропускаем поле
if (!$field->getRules()){ continue; }
// проверяем является ли поле элементом массива
$is_array = strstr($name, ':');
//
// получаем значение поля из массива данных
//
if (!$is_array){
$value = isset($data[$name]) ? $data[$name] : '';
}
if ($is_array){
$name_parts = explode(':', $name);
$value = isset($data[$name_parts[0]][$name_parts[1]]) ? $data[$name_parts[0]][$name_parts[1]] : '';
}
if ($data) { $field->setItem($data); }
//
// перебираем правила для поля
// и проверяем каждое из них
//
foreach($field->getRules() as $rule){
if (!$rule) { continue; }
// каждое правило это массив
// первый элемент - название функции-валидатора
$validate_function = "validate_{$rule[0]}";
// к остальным элементам добавляем $value, т.к.
// в валидаторах $value всегда последний аргумент
$rule[] = $value;
// убираем название валидатора из массива,
// оставляем только параметры (аргументы)
unset($rule[0]);
// вызываем валидатор и объединяем результат
// с предыдущими
$result = call_user_func_array(array($controller, $validate_function), $rule);
// если получилось false, то дальше не проверяем, т.к.
// ошибка уже найдена
if ($result !== true) {
$errors[$name] = $result;
break;
}
}
}
}
if (!sizeof($errors)) { return false; }
return $errors;
}
//============================================================================//
//============================================================================//
public static function getCSRFToken(){
if (cmsUser::isSessionSet('csrf_token')){
return cmsUser::sessionGet('csrf_token');
}
return self::generateCSRFToken();
}
/**
* Создает, сохраняет в сессии и возвращает CSRF-token
* @return string
*/
public static function generateCSRFToken(){
$hash = implode('::', array(session_id(), rand(0, 9999), microtime(true)));
$token = md5($hash);
cmsUser::sessionSet('csrf_token', $token);
return $token;
}
/**
* Проверяет валидность CSRF-токена
* @param string $csrf_token
* @return bool
*/
public static function validateCSRFToken($csrf_token){
return (cmsUser::sessionGet('csrf_token') == $csrf_token);
}
//============================================================================//
//============================================================================//
public static function mapFieldsToFieldsets($fields, $callback=null, $values=null){
$fieldsets = array();
$current = null;
$index = 0;
$fieldsets[ $index ] = array(
'title' => $current,
'fields' => array()
);
$user = cmsUser::getInstance();
foreach($fields as $field){
if (is_callable($callback)){
if (!$callback( $field, $user )) { continue; }
}
if (is_array($values)){
if (empty($values[ $field['name'] ])){ continue; }
}
if ($current != $field['fieldset']){
$current = $field['fieldset'];
$index += 1;
$fieldsets[ $index ] = array(
'title' => $current,
'fields' => array()
);
}
$fieldsets[ $index ]['fields'][] = $field;
}
return $fieldsets;
}
//============================================================================//
//============================================================================//
/**
* Загружает файлы с классами всех типов полей для генерации форм
*/
public static function loadFormFields(){
return cmsCore::getFilesList('system/fields', '*.php', false, true);
}
/**
* Возвращает список всех имеющихся типов полей
* @return array
*/
public static function getAvailableFormFields($only_public = true){
$fields_types = array();
$fields_files = cmsCore::getFilesList('system/fields', '*.php', true, true);
foreach ($fields_files as $name) {
$class = 'field' . string_to_camel('_', $name);
$field = new $class(null, null);
if ($only_public && !$field->is_public){ continue; }
$fields_types[$name] = $field->getTitle();
}
return $fields_types;
}
public static function getForm($form_file, $form_name, $params=false){
if (!file_exists($form_file)){ return false; }
cmsForm::loadFormFields();
include_once $form_file;
$form_class = 'form' . string_to_camel('_', $form_name);
$form = new $form_class();
if ($params){
$form->setParams($params);
$form->setStructure( call_user_func_array(array($form, 'init'), $params) );
} else {
$form->setStructure( $form->init() );
}
return $form;
}
//============================================================================//
//============================================================================//
}