diff --git a/src/Javascript/JavascriptValidator.php b/src/Javascript/JavascriptValidator.php index 69d82ef4..42cbecc6 100644 --- a/src/Javascript/JavascriptValidator.php +++ b/src/Javascript/JavascriptValidator.php @@ -3,8 +3,8 @@ namespace Proengsoft\JsValidation\Javascript; use Exception; -use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Facades\View; +use Illuminate\Contracts\Support\Arrayable; use Proengsoft\JsValidation\Exceptions\PropertyNotFoundException; class JavascriptValidator implements Arrayable @@ -137,6 +137,10 @@ protected function getViewData() $data = $this->validator->validationData(); $data['selector'] = $this->selector; + if (! is_null($this->validator->getDelegatedValidator())) { + $data['wildcards'] = $this->validator->getDelegatedValidator()->getWildcardRules(); + } + if (! is_null($this->ignore)) { $data['ignore'] = $this->ignore; } diff --git a/src/Javascript/RuleParser.php b/src/Javascript/RuleParser.php index 34468085..b14843df 100644 --- a/src/Javascript/RuleParser.php +++ b/src/Javascript/RuleParser.php @@ -2,8 +2,8 @@ namespace Proengsoft\JsValidation\Javascript; -use Proengsoft\JsValidation\Support\DelegatedValidator; use Proengsoft\JsValidation\Support\RuleListTrait; +use Proengsoft\JsValidation\Support\DelegatedValidator; use Proengsoft\JsValidation\Support\UseDelegatedValidatorTrait; class RuleParser @@ -161,11 +161,24 @@ protected function remoteRule($attribute, $forceRemote) */ protected function getAttributeName($attribute) { - $attributeArray = explode('.', $attribute); - if (count($attributeArray) > 1) { - return $attributeArray[0].'['.implode('][', array_slice($attributeArray, 1)).']'; + if (stripos($attribute, '.') === false) { + return $attribute; } - return $attribute; + $attributes = explode('.', $attribute); + + return $attributes[0]. + '['. + implode( + '][', + array_map(function ($attribute) { + if ($attribute === '*') { + return ''; + } + + return $attribute; + }, array_slice($attributes, 1)) + ). + ']'; } } diff --git a/src/JsValidatorFactory.php b/src/JsValidatorFactory.php index 21bf31c3..d84e8373 100644 --- a/src/JsValidatorFactory.php +++ b/src/JsValidatorFactory.php @@ -2,13 +2,13 @@ namespace Proengsoft\JsValidation; -use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Validator; -use Proengsoft\JsValidation\Javascript\JavascriptValidator; -use Proengsoft\JsValidation\Javascript\MessageParser; +use Illuminate\Foundation\Http\FormRequest; use Proengsoft\JsValidation\Javascript\RuleParser; -use Proengsoft\JsValidation\Javascript\ValidatorHandler; +use Proengsoft\JsValidation\Javascript\MessageParser; use Proengsoft\JsValidation\Support\DelegatedValidator; +use Proengsoft\JsValidation\Javascript\ValidatorHandler; +use Proengsoft\JsValidation\Javascript\JavascriptValidator; class JsValidatorFactory { @@ -61,7 +61,7 @@ public function make(array $rules, array $messages = array(), array $customAttri { $validator = $this->getValidatorInstance($rules, $messages, $customAttributes); - return $this->validator($validator, $selector); + return $this->validator($validator, $selector, $this->wildcardRules($rules)); } /** @@ -89,7 +89,6 @@ protected function getValidatorInstance(array $rules, array $messages = array(), * @param null $selector * * @return JavascriptValidator - * @throws FormRequestArgumentException */ public function formRequest($formRequest, $selector = null) { @@ -101,7 +100,28 @@ public function formRequest($formRequest, $selector = null) $validator = $this->getValidatorInstance($rules, $formRequest->messages(), $formRequest->attributes()); - return $this->validator($validator, $selector); + return $this->validator($validator, $selector, $this->wildcardRules($rules)); + } + + /** + * Find Laravel >= 5.2 wildcard validation rules removed by + * Illuminate\Validation\Validator@explodeRules() but required for + * JavaScript validation. + * + * @param array $rules + * + * @return array + */ + protected function wildcardRules(array $rules) + { + return array_map( + function ($attribute) use ($rules) { + return is_array($rules[$attribute]) ? $rules[$attribute] : explode('|', (string) $rules[$attribute]); + }, + array_filter(array_keys($rules), function ($attribute) { + return $attribute !== '' && mb_strpos($attribute, '*') !== false; + }) + ); } protected function parseFormRequestName($class) @@ -148,12 +168,13 @@ protected function createFormRequest($class) * * @param \Illuminate\Validation\Validator $validator * @param string|null $selector + * @param array $wildcardRules * * @return JavascriptValidator */ - public function validator(Validator $validator, $selector = null) + public function validator(Validator $validator, $selector = null, array $wildcardRules = []) { - return $this->jsValidator($validator, $selector); + return $this->jsValidator($validator, $selector, $wildcardRules); } /** @@ -161,16 +182,17 @@ public function validator(Validator $validator, $selector = null) * * @param \Illuminate\Validation\Validator $validator * @param string|null $selector + * @param array $wildcardRules * * @return JavascriptValidator */ - protected function jsValidator(Validator $validator, $selector = null) + protected function jsValidator(Validator $validator, $selector = null, array $wildcardRules = []) { $remote = ! $this->options['disable_remote_validation']; $view = $this->options['view']; $selector = is_null($selector) ? $this->options['form_selector'] : $selector; - $delegated = new DelegatedValidator($validator); + $delegated = new DelegatedValidator($validator, $wildcardRules); $rules = new RuleParser($delegated, $this->getSessionToken()); $messages = new MessageParser($delegated); diff --git a/src/Support/DelegatedValidator.php b/src/Support/DelegatedValidator.php index 39bd58d1..7af119a9 100644 --- a/src/Support/DelegatedValidator.php +++ b/src/Support/DelegatedValidator.php @@ -8,6 +8,7 @@ class DelegatedValidator { use AccessProtectedTrait; + /** * The Validator resolved instance. * @@ -22,15 +23,24 @@ class DelegatedValidator */ protected $validatorMethod; + /** + * Array validation rules with * wildcard matching. + * + * @var array + */ + protected $wildcardRules; + /** * DelegatedValidator constructor. * * @param \Illuminate\Validation\Validator $validator + * @param array $wildcardRules */ - public function __construct(BaseValidator $validator) + public function __construct(BaseValidator $validator, array $wildcardRules = []) { $this->validator = $validator; $this->validatorMethod = $this->createProtectedCaller($validator); + $this->wildcardRules = $wildcardRules; } /** @@ -38,6 +48,7 @@ public function __construct(BaseValidator $validator) * * @param string $method * @param array $args + * * @return mixed */ private function callValidator($method, $args = []) @@ -82,7 +93,17 @@ public function setData($data) */ public function getRules() { - return $this->validator->getRules(); + return $this->validator->getRules() + $this->wildcardRules; + } + + /** + * Get the validation rules with '*' wildcard. + * + * @return array + */ + public function getWildcardRules() + { + return $this->wildcardRules; } /** diff --git a/tests/Javascript/JavascriptValidatorTest.php b/tests/Javascript/JavascriptValidatorTest.php index 98c9f0a4..57561cb9 100644 --- a/tests/Javascript/JavascriptValidatorTest.php +++ b/tests/Javascript/JavascriptValidatorTest.php @@ -103,6 +103,48 @@ public function testToArray() } + + public function testToArrayWildcards() + { + $mockHandler = $this->getMockBuilder('\Proengsoft\JsValidation\Javascript\ValidatorHandler') + ->disableOriginalConstructor() + ->setMethods(['validationData','setRemote','getDelegatedValidator']) + ->getMock(); + + $mockHandler->expects($this->once()) + ->method('setRemote') + ->with(true) + ->willReturn([]); + + $mockHandler->expects($this->once()) + ->method('validationData') + ->with() + ->willReturn([]); + + $mockDelegated = $this->getMockBuilder('Proengsoft\JsValidation\Support\DelegatedValidator') + ->disableOriginalConstructor() + ->setMethods(['getWildcardRules']) + ->getMock(); + + $mockDelegated->expects($this->once()) + ->method('getWildcardRules') + ->with() + ->willReturn(['person.*.email' => ['Required', 'Email']]); + + $mockHandler->expects($this->exactly(2)) + ->method('getDelegatedValidator') + ->with() + ->willReturn($mockDelegated); + + $validator = new JavascriptValidator($mockHandler); + + $expected=['selector'=>'form','wildcards' => ['person.*.email' => ['Required', 'Email']]]; + $viewData=$validator->toArray(); + $this->assertEquals($expected,$viewData); + + } + + public function testGet() { $mockHandler = $this->getMockBuilder('\Proengsoft\JsValidation\Javascript\ValidatorHandler')