submitted = ! empty($array); parent::__construct($array, ArrayObject::ARRAY_AS_PROPS | ArrayObject::STD_PROP_LIST); } public function __clone() { $this->errors = array(); $this->messages = array(); } public function copy(array $array) { $copy = clone $this; $copy->exchangeArray($array); return $copy; } public function submitted($value = NULL) { if (is_bool($value)) { $this->submitted = $value; } return $this->submitted; } public function field_names() { $fields = array_keys(array_merge ( $this->pre_filters, $this->rules, $this->callbacks, $this->post_filters )); $fields = array_diff($fields, array('*')); return $fields; } public function as_array() { return $this->getArrayCopy(); } public function safe_array() { $choices = func_get_args(); $choices = empty($choices) ? NULL : array_combine($choices, $choices); $fields = $this->field_names(); $safe = array(); foreach ($fields as $field) { if ($choices === NULL OR isset($choices[$field])) { if (isset($this[$field])) { $value = $this[$field]; if (is_object($value)) { $value = $value->getArrayCopy(); } } else { $value = NULL; } $safe[$field] = $value; } } return $safe; } public function allow_empty_rules($rules) { $rules = func_get_args(); $this->empty_rules = array_merge($this->empty_rules, $rules); return $this; } protected function callback($callback) { if (is_string($callback)) { if (strpos($callback, '::') !== FALSE) { $callback = explode('::', $callback); } elseif (function_exists($callback)) { $callback = $callback; } elseif (method_exists($this, $callback)) { $callback = array($this, $callback); } elseif (method_exists('valid', $callback)) { $callback = array('valid', $callback); } } if ( ! is_callable($callback, FALSE)) { if (is_array($callback)) { if (is_object($callback[0])) { $name = get_class($callback[0]).'->'.$callback[1]; } else { $name = $callback[0].'::'.$callback[1]; } } else { $name = $callback; } throw new Kohana_Exception('validation.not_callable', $name); } return $callback; } public function pre_filter($filter, $field = TRUE) { if ($field === TRUE OR $field === '*') { $fields = array('*'); } else { $fields = func_get_args(); $fields = array_slice($fields, 1); } $filter = $this->callback($filter); foreach ($fields as $field) { $this->pre_filters[$field][] = $filter; } return $this; } public function post_filter($filter, $field = TRUE) { if ($field === TRUE) { $fields = array('*'); } else { $fields = func_get_args(); $fields = array_slice($fields, 1); } $filter = $this->callback($filter); foreach ($fields as $field) { $this->post_filters[$field][] = $filter; } return $this; } public function add_rules($field, $rules) { $rules = func_get_args(); $rules = array_slice($rules, 1); if ($field === TRUE) { $field = '*'; } foreach ($rules as $rule) { $args = NULL; if (is_string($rule)) { if (preg_match('/^([^\[]++)\[(.+)\]$/', $rule, $matches)) { $rule = $matches[1]; $args = preg_split('/(?array_fields[$field] = $field; } $rule = $this->callback($rule); $this->rules[$field][] = array($rule, $args); } return $this; } public function add_callbacks($field, $callbacks) { $callbacks = func_get_args(); $callbacks = array_slice($callbacks, 1); if ($field === TRUE) { $field = '*'; } foreach ($callbacks as $callback) { $callback = $this->callback($callback); $this->callbacks[$field][] = $callback; } return $this; } public function validate($object = NULL, $field_name = NULL) { if ($object === NULL) { $object = $this; } $fields = $this->field_names(); $array = $this->getArrayCopy(); foreach ($fields as $field) { if ($field === '*') { continue; } if ( ! isset($array[$field])) { if (isset($this->array_fields[$field])) { $array[$field] = array(); } else { $array[$field] = NULL; } } } $this->exchangeArray($array); $fields = array_keys($array); foreach ($this->pre_filters as $field => $callbacks) { foreach ($callbacks as $callback) { if ($field === '*') { foreach ($fields as $f) { $this[$f] = is_array($this[$f]) ? array_map($callback, $this[$f]) : call_user_func($callback, $this[$f]); } } else { $this[$field] = is_array($this[$field]) ? array_map($callback, $this[$field]) : call_user_func($callback, $this[$field]); } } } if ($this->submitted === FALSE) return FALSE; foreach ($this->rules as $field => $callbacks) { foreach ($callbacks as $callback) { list ($callback, $args) = $callback; $rule = is_array($callback) ? $callback[1] : $callback; if ($field === '*') { foreach ($fields as $f) { if (isset($this->errors[$f])) { continue; } if (empty($this[$f]) AND ! in_array($rule, $this->empty_rules)) { continue; } if ($args === NULL) { if ( ! call_user_func($callback, $this[$f])) { $this->errors[$f] = $rule; continue; } } else { if ( ! call_user_func($callback, $this[$f], $args)) { $this->errors[$f] = $rule; continue; } } } } else { if (isset($this->errors[$field])) { break; } if ( ! in_array($rule, $this->empty_rules) AND ! $this->required($this[$field])) { continue; } if ($args === NULL) { if ( ! call_user_func($callback, $this[$field])) { $this->errors[$field] = $rule; break; } } else { if ( ! call_user_func($callback, $this[$field], $args)) { $this->errors[$field] = $rule; break; } } } } } foreach ($this->callbacks as $field => $callbacks) { foreach ($callbacks as $callback) { if ($field === '*') { foreach ($fields as $f) { if (isset($this->errors[$f])) { continue; } call_user_func($callback, $this, $f); } } else { if (isset($this->errors[$field])) { break; } call_user_func($callback, $this, $field); } } } foreach ($this->post_filters as $field => $callbacks) { foreach ($callbacks as $callback) { if ($field === '*') { foreach ($fields as $f) { $this[$f] = is_array($this[$f]) ? array_map($callback, $this[$f]) : call_user_func($callback, $this[$f]); } } else { $this[$field] = is_array($this[$field]) ? array_map($callback, $this[$field]) : call_user_func($callback, $this[$field]); } } } return $this->errors === array(); } public function add_error($field, $name) { $this->errors[$field] = $name; return $this; } public function message($input = NULL, $message = NULL) { if ($message === NULL) { if ($input === NULL) { $messages = array(); $keys = array_keys($this->messages); foreach ($keys as $input) { $messages[] = $this->message($input); } return implode("\n", $messages); } if (empty($this->messages[$input])) return ''; return $this->messages[$input]; } else { $this->messages[$input] = $message; } return $this; } public function errors($file = NULL) { if ($file === NULL) { return $this->errors; } else { $errors = array(); foreach ($this->errors as $input => $error) { $key = "$file.$input.$error"; if (($errors[$input] = Kohana::lang($key)) === $key) { $errors[$input] = Kohana::lang("$file.$input.default"); } } return $errors; } } public function required($str) { if (is_object($str) AND $str instanceof ArrayObject) { $str = $str->getArrayCopy(); } if (is_array($str)) { return ! empty($str); } else { return ! ($str === '' OR $str === NULL OR $str === FALSE); } } public function matches($str, array $inputs) { foreach ($inputs as $key) { if ($str !== (isset($this[$key]) ? $this[$key] : NULL)) return FALSE; } return TRUE; } public function length($str, array $length) { if ( ! is_string($str)) return FALSE; $size = utf8::strlen($str); $status = FALSE; if (count($length) > 1) { list ($min, $max) = $length; if ($size >= $min AND $size <= $max) { $status = TRUE; } } else { $status = ($size === (int) $length[0]); } return $status; } public function depends_on($field, array $fields) { foreach ($fields as $depends_on) { if ( ! isset($this[$depends_on]) OR $this[$depends_on] == NULL) return FALSE; } return TRUE; } public function chars($value, array $chars) { return ! preg_match('![^'.implode('', $chars).']!u', $value); } }