diff --git a/system/str.php b/system/str.php index 7ab40159..ec446c34 100644 --- a/system/str.php +++ b/system/str.php @@ -46,6 +46,17 @@ public static function title($value) return (function_exists('mb_convert_case')) ? mb_convert_case($value, MB_CASE_TITLE, Config::get('application.encoding')) : ucwords(strtolower($value)); } + /** + * Get the length of a string. + * + * @param string $value + * @return int + */ + public static function length($value) + { + return function_exists('mb_strlen') ? mb_strlen($value, Config::get('application.encoding')) : strlen($value); + } + /** * Generate a random alpha or alpha-numeric string. * diff --git a/system/validation/error_collector.php b/system/validation/error_collector.php new file mode 100644 index 00000000..13285ce8 --- /dev/null +++ b/system/validation/error_collector.php @@ -0,0 +1,70 @@ +messages = $messages; + } + + /** + * Add an error message to the collector. + * + * @param string $attribute + * @param string $message + * @return void + */ + public function add($attribute, $message) + { + $this->messages[$attribute][] = $message; + } + + /** + * Get the first error message for an attribute. + * + * @param string $attribute + * @return string + */ + public function first($attribute) + { + return (count($messages = $this->get($attribute)) > 0) ? $messages[0] : ''; + } + + /** + * Get all of the error messages for an attribute. + * + * If no attribute is specified, all of the error messages will be returned. + * + * @param string $attribute + * @return array + */ + public function get($attribute = null) + { + if (is_null($attribute)) + { + $all = array(); + + foreach ($this->messages as $messages) + { + $all = array_merge($all, $messages); + } + + return $all; + } + + return (array_key_exists($attribute, $this->messages)) ? $this->messages[$attribute] : array(); + } + +} \ No newline at end of file diff --git a/system/validation/rule.php b/system/validation/rule.php new file mode 100644 index 00000000..d3e79289 --- /dev/null +++ b/system/validation/rule.php @@ -0,0 +1,93 @@ +attributes = $attributes; + } + + /** + * Run the validation rule. + * + * @param array $attributes + * @param Error_Collector $errors + * @return void + */ + public function validate($attributes, $errors) + { + if (is_null($this->message)) + { + throw new \Exception("An error message must be specified for every Eloquent validation rule."); + } + + foreach ($this->attributes as $attribute) + { + if ( ! $this->check($attribute, $attributes)) + { + $errors->add($attribute, $this->prepare_message($attribute)); + } + } + } + + /** + * Prepare the message to be added to the error collector. + * + * Attribute and size place-holders will replace with their actual values. + * + * @param string $attribute + * @return string + */ + private function prepare_message($attribute) + { + $message = $this->message; + + if (strpos($message, ':attribute')) + { + $message = str_replace(':attribute', Lang::line('attributes.'.$attribute)->get(), $message); + } + + if ($this instanceof Rules\Size_Of) + { + $message = str_replace(':max', $this->maximum, $message); + $message = str_replace(':min', $this->minimum, $message); + $message = str_replace(':size', $this->length, $message); + } + + return $message; + } + + /** + * Set the validation error message. + * + * @param string $message + * @return Rule + */ + public function message($message) + { + $this->message = $message; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/acceptance_of.php b/system/validation/rules/acceptance_of.php new file mode 100644 index 00000000..001c9a30 --- /dev/null +++ b/system/validation/rules/acceptance_of.php @@ -0,0 +1,39 @@ +accepts; + } + + /** + * Set the accepted value. + * + * @param string $value + * @return Acceptance_Of + */ + public function accepts($value) + { + $this->accepts = $value; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/confirmation_of.php b/system/validation/rules/confirmation_of.php new file mode 100644 index 00000000..02185cca --- /dev/null +++ b/system/validation/rules/confirmation_of.php @@ -0,0 +1,25 @@ +reserved); + } + + /** + * Set the reserved values for the attribute + * + * @param array $reserved + * @return Exclusion_Of + */ + public function from($reserved) + { + $this->reserved = $reserved; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/format_of.php b/system/validation/rules/format_of.php new file mode 100644 index 00000000..df0cd2de --- /dev/null +++ b/system/validation/rules/format_of.php @@ -0,0 +1,43 @@ +expression, $attributes[$attribute]); + } + + /** + * Set the regular expression. + * + * @param string $expression + * @return Format_Of + */ + public function with($expression) + { + $this->expression = $expression; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/inclusion_of.php b/system/validation/rules/inclusion_of.php new file mode 100644 index 00000000..db1e0afb --- /dev/null +++ b/system/validation/rules/inclusion_of.php @@ -0,0 +1,43 @@ +accepted); + } + + /** + * Set the accepted values for the attribute. + * + * @param array $accepted + * @return Inclusion_Of + */ + public function in($accepted) + { + $this->accepted = $accepted; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/presence_of.php b/system/validation/rules/presence_of.php new file mode 100644 index 00000000..06c05fd5 --- /dev/null +++ b/system/validation/rules/presence_of.php @@ -0,0 +1,70 @@ +allow_null) + { + return false; + } + + if (trim((string) $attributes[$attribute]) === '' and ! $this->allow_empty) + { + return false; + } + + return true; + } + + /** + * Allow an empty string to be considered present. + * + * @return Presence_Of + */ + public function allow_empty() + { + $this->allow_empty = true; + return $this; + } + + /** + * Allow a null to be considered present. + * + * @return Presence_Of + */ + public function allow_null() + { + $this->allow_null = true; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/size_of.php b/system/validation/rules/size_of.php new file mode 100644 index 00000000..8cefa1f6 --- /dev/null +++ b/system/validation/rules/size_of.php @@ -0,0 +1,160 @@ +check_number($attribute, $attributes); + } + else + { + return $this->check_string($attribute, $attributes); + } + } + + /** + * Evaluate the validity of a numeric attribute. + * + * @param string $attribute + * @param array $attributes + * @return void + */ + private function check_number($attribute, $attributes) + { + if ( ! is_null($this->length) and $attributes[$attribute] !== $this->length) + { + return false; + } + + if ( ! is_null($this->maximum) and $attributes[$attribute] > $this->maximum) + { + return false; + } + + if ( ! is_null($this->minimum and $attributes[$attribute] < $this->minimum)) + { + return false; + } + + return true; + } + + /** + * Evaluate the validity of a string attribute. + * + * @param string $attribute + * @param array $attributes + * @return void + */ + public function check_string($attribute, $attributes) + { + $value = trim((string) $attributes[$attribute]); + + if ( ! is_null($this->length) and Str::length($value) !== $this->length) + { + return false; + } + + if ( ! is_null($this->maximum) and Str::length($value) > $this->maximum) + { + return false; + } + + if ( ! is_null($this->minimum) and Str::length($value) < $this->minimum) + { + return false; + } + + return true; + } + + /** + * Set the exact size the attribute must be. + * + * @param int $length + * @return Size_Of + */ + public function is($length) + { + $this->length = $length; + return $this; + } + + /** + * Set the minimum and maximize size of the attribute. + * + * @param int $minimum + * @param int $maximum + * @return Size_Of + */ + public function between($minimum, $maximum) + { + $this->minimum = $minimum; + $this->maximum = $maximum; + + return $this; + } + + /** + * Set the minimum size the attribute. + * + * @param int $minimum + * @return Size_Of + */ + public function at_least($minimum) + { + $this->minimum = $minimum; + return $this; + } + + /** + * Set the maximum size the attribute. + * + * @param int $maximum + * @return Size_Of + */ + public function less_than($maximum) + { + $this->maximum = $maximum; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/uniqueness_of.php b/system/validation/rules/uniqueness_of.php new file mode 100644 index 00000000..938e813a --- /dev/null +++ b/system/validation/rules/uniqueness_of.php @@ -0,0 +1,60 @@ +column)) + { + $this->column = $attribute; + } + + return DB::table(Eloquent::table($this->table)->where($this->column, '=', $attributes[$attribute])->count() == 0; + } + + /** + * Set the database table and column. + * + * @param string $table + * @param string $column + * @return Uniqueness_Of + */ + public function on($table, $column = null) + { + $this->table = $table; + $this->column = $column; + + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/with_callback.php b/system/validation/rules/with_callback.php new file mode 100644 index 00000000..7ddbb75e --- /dev/null +++ b/system/validation/rules/with_callback.php @@ -0,0 +1,48 @@ +callback)) + { + throw new \Exception("A validation callback for the [$attribute] attribute is not callable."); + } + + return call_user_func($this->callback, $attributes[$attribute]); + } + + /** + * Set the validation callback. + * + * @param function $callback + * @return With_Callback + */ + public function using($callback) + { + $this->callback = $callback; + return $this; + } + +} \ No newline at end of file diff --git a/system/validator.php b/system/validator.php new file mode 100644 index 00000000..3264dae8 --- /dev/null +++ b/system/validator.php @@ -0,0 +1,94 @@ +attributes = ($target instanceof DB\Eloquent) ? $target->attributes : (array) $target; + + $this->errors = new Validation\Error_Collector; + } + + /** + * Create a new Eloquent validator instance. + * + * @param mixed $target + * @return Validator + */ + public static function of($target) + { + return new static($target); + } + + /** + * Determine if the model passes all of the validation rules. + * + * @return bool + */ + public function is_valid() + { + $this->errors->messages = array(); + + foreach ($this->rules as $rule) + { + // --------------------------------------------------------- + // The error collector is passed to the rule so that the + // rule may conveniently add error messages. + // --------------------------------------------------------- + $rule->validate($this->attributes, $this->errors); + } + + return count($this->errors->messages) === 0; + } + + /** + * Magic Method for dynamically creating validation rules. + */ + public function __call($method, $parameters) + { + // --------------------------------------------------------- + // Check if the validation rule is defined in the rules + // directory. If it is, create a new rule and return it. + // --------------------------------------------------------- + if (file_exists(SYS_PATH.'validation/rules/'.$method.EXT)) + { + $rule = '\\System\\Validation\\Rules\\'.$method; + + return $this->rules[] = new $rule($parameters); + } + + throw new \Exception("Method [$method] does not exist on Validator class."); + } + +} \ No newline at end of file