diff --git a/README.md b/README.md index 137e27a..d7fcd8b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,46 @@ laravel-parsley =============== -Converts FormRequest rules to [Parsley](http://parsleyjs.org/) rules. +Converts [FormRequest](http://laravel.com/docs/5.0/validation#form-request-validation) rules to [Parsley](http://parsleyjs.org/) rules. + + +## Install + +If you have previously set up `LaravelCollective/Html` or `Illuminate/Html` you can remove its service provider from `app/config` + +in `app/config` add the following under service providers: + +`HappyDemon\LaravelParsley\LaravelParsleyServiceProvider` + +If you haven't already, add these facades: + + 'Form' => 'Collective\Html\FormFacade', + 'Html' => 'Collective\Html\HtmlFacade', + +## Useage + +All that's needed is for you to supply the name of the `FormRequest` in the `request` key when opening a form. + + Form::open(['request' => 'YourFormRequestClass']) + Form::model(['request' => 'YourFormRequestClass']) + +Lastly you should include parsley's scripts on the page and activate parsley for your form. + +easy enough don't you think? + +### Validation rules + +Implemented| Not implemented | +-----------|-----------------| + required | accepted | + email | after:(date) | + min | before:(date) | + max | before:(date) | + between | date_format | + integer | different | + url | in | + alpha_num | not_in | + alpha_dash| ip_address | + alpha | | + regex | | + confirmed | | diff --git a/composer.json b/composer.json index 358d1e1..207165e 100644 --- a/composer.json +++ b/composer.json @@ -1,22 +1,29 @@ { - "name": "idma/laravel-parsley", + "name": "happydemon/laravel-parsley", "description": "Converts FormRequest rules to Parsley rules", - "keywords": ["laravel", "laravel 5", "parsley", "parsleyjs", "html", "form"], + "keywords": ["laravel", "laravel 5", "parsley", "parsleyjs", "html", "form", "collective"], "authors": [ { "name": "idma", "email": "info@idma.ru" + }, + { + "name": "Maxim 'happyDemon' Kerstens", + "email": "maxim.kerstens@gmail.com" } ], + "replace": { + "idma/laravel-parsley":"0.*" + }, "require": { "php": ">=5.4.0", "illuminate/support": "~5.0", - "illuminate/html": "~5.0", + "laravelcollective/html": "~5.0", "illuminate/translation" : "~5.0" }, "autoload": { "psr-0": { - "Idma\\LaravelParsley": "src/" + "HappyDemon\\LaravelParsley": "src/" } }, "config": { diff --git a/resources/assets/parsley-laravel.js b/resources/assets/parsley-laravel.js new file mode 100644 index 0000000..360a125 --- /dev/null +++ b/resources/assets/parsley-laravel.js @@ -0,0 +1,72 @@ +window.ParsleyValidator + .addValidator('after', function (value, requirement) { + var params = requirement.split('|-|'); + if(params.length == 1) + { + // is valid date? + var timestamp = Date.parse(value), + minTs = Date.parse(params[0]); + + return isNaN(timestamp) ? false : timestamp > minTs; + } + else + { + // A format was given, use momentJS + var timestamp = moment(value, params[1]); + var minTs = moment(params[0], params[1]); + + // If it's a valid date + // and the difference in milliseconds is greater than 0 + return (timestamp.isValid()) ? timestamp.isAfter(minTs) : false; + } + }, 32) + .addMessage('en', 'after', 'This date should be after %s'); +window.ParsleyValidator + .addValidator('before', function (value, requirement) { + var params = requirement.split('|-|'); + if(params.length == 1) + { + // is valid date? + var timestamp = Date.parse(value), + maxTs = Date.parse(params[0]); + + return isNaN(timestamp) ? false : timestamp < maxTs; + } + else + { + // A format was given, use momentJS + var timestamp = moment(value, params[1]); + var maxTs = moment(params[0], params[1]); + + // If it's a valid date + // and the difference in milliseconds is smaller than 0 + return (timestamp.isValid()) ? timestamp.isBefore(maxTs) : false; + } + }, 32) + .addMessage('en', 'before', 'This date should be before %s'); +window.ParsleyValidator + .addValidator('formatDate', function (value, requirement) { + var d = moment(value,requirement); + + return (d == null || !d.isValid()); + }, 32) + .addMessage('en', 'formatDate', 'This date should be in this format: "%s"'); +window.ParsleyValidator + .addValidator('inList', function (value, requirement) { + var list = requirement.split(','); + + return list.indexOf(value) > -1; + }, 32) + .addMessage('en', 'inList', 'The value should be one of the following: "%s"'); +window.ParsleyValidator + .addValidator('notInList', function (value, requirement) { + var list = requirement.split(','); + + return list.indexOf(value) != -1; + }, 32) + .addMessage('en', 'notInList', 'The value should not be one of the following: "%s"'); +window.ParsleyValidator + .addValidator('different', function (value, requirement) { + return $(requirement).val() != value; + }, 32) + .addMessage('en', 'different', 'The value should not be the same as "%s"'); \ No newline at end of file diff --git a/src/HappyDemon/LaravelParsley/FormBuilder.php b/src/HappyDemon/LaravelParsley/FormBuilder.php new file mode 100644 index 0000000..3cadf83 --- /dev/null +++ b/src/HappyDemon/LaravelParsley/FormBuilder.php @@ -0,0 +1,10 @@ +reserved[] = 'request'; + $this->parsley = new ParsleyConverter(array_get($options, 'request', null)); + + return parent::open($options); + } + + /** + * {@inheritdoc} + */ + public function input($type, $name, $value = null, $options = []) + { + if ($this->parsley != null) + { + $options = array_merge($options, $this->parsley->getFieldRules($name)); + } + + return parent::input($type, $name, $value, $options); + } + + /** + * {@inheritdoc} + */ + public function textarea($name, $value = null, $options = []) + { + if ($this->parsley != null) + { + $options = array_merge($options, $this->parsley->getFieldRules($name)); + } + + return parent::textarea($name, $value, $options); + } + + public function select($name, $list = [], $selected = null, $options = []) + { + if ($this->parsley != null) + { + $options = array_merge($options, $this->parsley->getFieldRules($name)); + } + + return parent::select($name, $list, $selected, $options); + } +} \ No newline at end of file diff --git a/src/Idma/LaravelParsley/LaravelParsleyServiceProvider.php b/src/HappyDemon/LaravelParsley/LaravelParsleyServiceProvider.php similarity index 79% rename from src/Idma/LaravelParsley/LaravelParsleyServiceProvider.php rename to src/HappyDemon/LaravelParsley/LaravelParsleyServiceProvider.php index 65121b2..e32ad7a 100644 --- a/src/Idma/LaravelParsley/LaravelParsleyServiceProvider.php +++ b/src/HappyDemon/LaravelParsley/LaravelParsleyServiceProvider.php @@ -1,8 +1,8 @@ package('idma/parsley-laravel'); - parent::register(); } diff --git a/src/Idma/LaravelParsley/ParsleyConverter.php b/src/HappyDemon/LaravelParsley/ParsleyConverter.php similarity index 68% rename from src/Idma/LaravelParsley/ParsleyConverter.php rename to src/HappyDemon/LaravelParsley/ParsleyConverter.php index 12af147..03de3f8 100644 --- a/src/Idma/LaravelParsley/ParsleyConverter.php +++ b/src/HappyDemon/LaravelParsley/ParsleyConverter.php @@ -1,10 +1,12 @@ getAppNamespace() . 'Http\Requests\\'.$formRequest; + $formRequest = new $class; + } if ($formRequest && method_exists($formRequest, 'rules')) { $this->rules = $formRequest->rules(); @@ -31,7 +37,6 @@ public function __construct() public function getFieldRules($field) { $rules = []; - if (isset($this->rules[$field])) { $rawRules = explode('|', $this->rules[$field]); @@ -46,10 +51,12 @@ public function convertRules($attribute, $rules) $attrs = []; $message = null; + $date_format = null; + foreach ($rules as $rule) { list($rule, $params) = explode(':', $rule . ':'); - $params = explode(',', str_replace(' ', '', $params)); + $params = explode(',', $params); $parsleyRule = $rule; @@ -57,8 +64,13 @@ public function convertRules($attribute, $rules) $message = $this->getMessage($attribute, $rule, $rules); switch ($rule) { + case 'accepted': case 'required': + break; + case 'email': + $parsleyRule = 'type'; + $params = 'email'; break; case 'min': @@ -87,6 +99,11 @@ public function convertRules($attribute, $rules) $parsleyRule = 'integer'; break; + case 'url': + $parsleyRule = 'type'; + $params = 'url'; + break; + case 'alpha_num': $parsleyRule = 'alphanum'; $params = '/^\d[a-zа-яё\-\_]+$/i'; @@ -111,8 +128,48 @@ public function convertRules($attribute, $rules) $params = "#{$attribute}_confirmation"; break; + case 'different': + $parsleyRule = 'different'; + $message = str_replace(':other', $params[0], $message); + $params = '#'.$params[0]; + break; + + case 'date_format': + $parsleyRule = 'dateformat'; + $replace = [ + // Day + 'd' => 'DD', 'D' => 'ddd', 'j' => 'D', 'l' => 'DDDD', + 'N' => 'E', 'S' => '', 'w' => 'W', 'z' => 'DDD', + // Week + 'W' => 'w', + // Month + 'F' => 'MMMM', 'm' => 'MM', 'M' => 'MMM', 'n' => 'M', 't' => '', + // Year + 'L' => '', 'o' => 'YYYY', 'Y' => 'YYYY', 'y' => 'YY', + // Time + 'a' => 'a', 'A' => 'A', 'B' => '', 'g' => 'h', 'G' => 'H', + 'h' => 'hh', 'H' => 'HH', 'i' => 'i', 's' => 's', 'u' => '' + ]; + $params = str_replace(array_keys($replace), array_values($replace), $params[0]); + $date_format = $params; + $message = str_replace(':format', $params, $message); + break; + case 'before': + case 'after': + $params = $params[0]; + if($date_format !== null) + { + $params .= '|-|'.$date_format; + } + break; + case 'in': + case 'not_in': + $parsleyRule = camel_case($rule).'List'; + $params = implode(',', $params); + break; default: $message = null; + break; } if ($message) { @@ -126,7 +183,6 @@ public function convertRules($attribute, $rules) $message = null; } - return $attrs; } diff --git a/src/Idma/LaravelParsley/FormBuilder.php b/src/Idma/LaravelParsley/FormBuilder.php deleted file mode 100644 index 7a131f3..0000000 --- a/src/Idma/LaravelParsley/FormBuilder.php +++ /dev/null @@ -1,167 +0,0 @@ -parsley = new ParsleyConverter(); - - if ($this->model && !isset($options['method'])) { - $options['method'] = $this->model->getAttribute('id') ? 'put' : 'post'; - } - - $method = strtoupper(array_get($options, 'method', 'post')); - - // We need to extract the proper method from the attributes. If the method is - // something other than GET or POST we'll use POST since we will spoof the - // actual method since forms don't support the reserved methods in HTML. - $attributes['method'] = $this->getMethod($method); - - $attributes['action'] = $this->getAction($options); - - $attributes['accept-charset'] = 'UTF-8'; - - // If the method is PUT, PATCH or DELETE we will need to add a spoofer hidden - // field that will instruct the Symfony request to pretend the method is a - // different method than it actually is, for convenience from the forms. - $append = $this->getAppendage($method); - - if (isset($options['files']) && $options['files']) { - $options['enctype'] = 'multipart/form-data'; - } - - // Finally we're ready to create the final form HTML field. We will attribute - // format the array of attributes. We will also add on the appendage which - // is used to spoof requests for this PUT, PATCH, etc. methods on forms. - $attributes = array_merge($attributes, array_except($options, $this->reserved)); - - // Finally, we will concatenate all of the attributes into a single string so - // we can build out the final form open statement. We'll also append on an - // extra value for the hidden _method field if it's needed for the form. - $attributes = $this->html->attributes($attributes); - - return ''.$append; - } - - /** - * {@inheritdoc} - */ - public function model($model, array $options = []) { - $this->setModel($model); - - return $this->open($options); - } - - public function openModel($model, array $options = []) { - return $this->model($model, $options); - } - - /** - * {@inheritdoc} - */ - public function label($name, $value = null, $options = []) { - $this->labels[] = $name; - - $options = $this->html->attributes($options); - - $value = e($this->formatLabel($name, $value)); - - $for = ($this->modelName && !starts_with($name, '_')) ? $this->modelName.'-'.$name : $name; - - return ''; - } - - /** - * Create a Bootstrap-like help block. - * - * @param string $value - * @param array $options - * - * @return string - */ - public function helpBlock($value, array $options = []) { - if (isset($options['class'])) { - $options['class'] = 'help-block '.$options['class']; - } else { - $options['class'] = 'help-block'; - } - - return 'html->attributes($options).'>'.$value.''; - } - - /** - * {@inheritdoc} - */ - public function input($type, $name, $value = null, $options = []) - { - $options = array_merge($options, $this->parsley->getFieldRules($name)); - - return parent::input($type, $name, $value, $options); - } - - /** - * {@inheritdoc} - */ - public function textarea($name, $value = null, $options = []) - { - $options = array_merge($options, $this->parsley->getFieldRules($name)); - - return parent::textarea($name, $value, $options); - } - - public function select($name, $list = [], $selected = null, $options = []) - { - $options = array_merge($options, $this->parsley->getFieldRules($name)); - - return parent::select($name, $list, $selected, $options); - } - - /** - * {@inheritdoc} - */ -// public function getIdAttribute($name, $attributes) { -// $id = null; -// -// if (array_key_exists('id', $attributes)) { -// $id = $attributes['id']; -// } else { -// $id = $name; -// } -// -// if ($this->modelName && $id && !starts_with($id, '_')) { -// return $this->modelName.'-'.$id; -// } -// -// return null; -// } - - public function setModel($model) { - $this->model = $model; - $this->modelName = strtolower((new \ReflectionClass($this->model))->getShortName()); - } - - /** - * Gets the short model name. - * - * @return string - */ - public function getModelName() { - return $this->modelName; - } - - public function name() { - return $this->getModelName(); - } -} diff --git a/src/Idma/LaravelParsley/UseParsleyValidationTrait.php b/src/Idma/LaravelParsley/UseParsleyValidationTrait.php deleted file mode 100644 index 66b0132..0000000 --- a/src/Idma/LaravelParsley/UseParsleyValidationTrait.php +++ /dev/null @@ -1,27 +0,0 @@ -all()) { - call_user_func('parent::validate'); - } else { - if (!call_user_func([$this, 'passesAuthorization'])) { - call_user_func([$this, 'failedAuthorization']); - } - } - } -}