From 1a903e8a5aed99d32e7c57421b5778a067e4eb1b Mon Sep 17 00:00:00 2001 From: Muhammad Syifa Date: Sat, 3 Nov 2018 15:23:54 +0700 Subject: [PATCH 1/2] added helper arrayUnset --- src/Helper.php | 32 +++++++++++++++++++++++++++++++- tests/HelperTest.php | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/Helper.php b/src/Helper.php index 77aa788..0596152 100644 --- a/src/Helper.php +++ b/src/Helper.php @@ -158,6 +158,36 @@ public static function arraySet(&$target, $key, $value, $overwrite = true) return $target; } + + /** + * Unset an item on an array or object using dot notation. + * + * @param mixed $target + * @param string|array $key + * @return mixed + */ + public static function arrayUnset(&$target, $key) + { + if (!is_array($target)) { + return $target; + } + + $segments = is_array($key) ? $key : explode('.', $key); + $segment = array_shift($segments); + + if ($segment == '*') { + $target = []; + } elseif ($segments) { + if (array_key_exists($segment, $target)) { + static::arrayUnset($target[$segment], $segments); + } + } elseif (array_key_exists($segment, $target)) { + unset($target[$segment]); + } + + return $target; + } + /** * Get snake_case format from given string * @@ -171,7 +201,7 @@ public static function snakeCase($value, $delimiter = '_') $value = preg_replace('/\s+/u', '', ucwords($value)); $value = strtolower(preg_replace('/(.)(?=[A-Z])/u', '$1'.$delimiter, $value)); } - + return $value; } diff --git a/tests/HelperTest.php b/tests/HelperTest.php index 31684a0..ee22922 100644 --- a/tests/HelperTest.php +++ b/tests/HelperTest.php @@ -42,7 +42,7 @@ public function testArrayGet() $this->assertEquals(Helper::arrayGet($array, 'foo.bar'), $array['foo']['bar']); $this->assertEquals(Helper::arrayGet($array, 'foo.bar.baz'), $array['foo']['bar']['baz']); $this->assertEquals(Helper::arrayGet($array, 'one.two.three'), 123); - + $this->assertNull(Helper::arrayGet($array, 'foo.bar.baz.qux')); $this->assertNull(Helper::arrayGet($array, 'one.two')); } @@ -89,7 +89,7 @@ public function testArraySet() Helper::arraySet($array, 'comments.*.id', null, false); Helper::arraySet($array, 'comments.*.x.y', 1, false); - + $this->assertEquals($array, [ 'comments' => [ ['id' => null, 'text' => 'foo', 'x' => ['y' => 1]], @@ -99,4 +99,34 @@ public function testArraySet() ]); } + public function testArrayUnset() + { + $array = [ + 'users' => [ + 'one' => 'user_one', + 'two' => 'user_two', + ], + 'stuffs' => [1, 'two', ['three'], null, false, true], + 'message' => "lorem ipsum", + ]; + + Helper::arrayUnset($array, 'users.one'); + $this->assertEquals($array, [ + 'users' => [ + 'two' => 'user_two', + ], + 'stuffs' => [1, 'two', ['three'], null, false, true], + 'message' => "lorem ipsum", + ]); + + Helper::arrayUnset($array, 'stuffs.*'); + $this->assertEquals($array, [ + 'users' => [ + 'two' => 'user_two', + ], + 'stuffs' => [], + 'message' => "lorem ipsum", + ]); + } + } From b39e98c2a15fe0920910754f09c22182dce00c33 Mon Sep 17 00:00:00 2001 From: Muhammad Syifa Date: Sat, 3 Nov 2018 15:25:32 +0700 Subject: [PATCH 2/2] fix unexpected result by checking dot notation --- src/Attribute.php | 7 +++++- src/Validation.php | 30 +++++++++++++----------- tests/ValidatorTest.php | 52 +++++++++++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/Attribute.php b/src/Attribute.php index 2faa0f4..4d89162 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -124,6 +124,11 @@ public function isArrayAttribute() return count($this->getKeyIndexes()) > 0; } + public function isUsingDotNotation() + { + return strpos($this->getKey(), '.') !== false; + } + public function resolveSiblingKey($key) { $indexes = $this->getKeyIndexes(); @@ -165,4 +170,4 @@ public function getAlias() return $this->alias; } -} \ No newline at end of file +} diff --git a/src/Validation.php b/src/Validation.php index f4a10f7..51cb4f5 100644 --- a/src/Validation.php +++ b/src/Validation.php @@ -20,7 +20,7 @@ class Validation protected $aliases = []; protected $messageSeparator = ':'; - + protected $validData = []; protected $invalidData = []; @@ -72,7 +72,7 @@ protected function validateAttribute(Attribute $attribute) } $attributeKey = $attribute->getKey(); - $rules = $attribute->getRules(); + $rules = $attribute->getRules(); $value = $this->getValue($attributeKey); $isEmptyValue = $this->isEmptyValue($value); @@ -92,7 +92,7 @@ protected function validateAttribute(Attribute $attribute) if ($isEmptyValue AND $this->ruleIsOptional($attribute, $ruleValidator)) { continue; } - + if (!$valid) { $isValid = false; $this->addError($attribute, $value, $ruleValidator); @@ -254,8 +254,8 @@ protected function isEmptyValue($value) protected function ruleIsOptional(Attribute $attribute, Rule $rule) { - return false === $attribute->isRequired() AND - false === $rule->isImplicit() AND + return false === $attribute->isRequired() AND + false === $rule->isImplicit() AND false === $rule instanceof Required; } @@ -288,14 +288,14 @@ protected function resolveMessage(Attribute $attribute, $value, Rule $validator) ]; if ($primaryAttribute) { - // insert primaryAttribute keys + // insert primaryAttribute keys // $message_keys = [ // $attributeKey.$this->messageSeparator.$ruleKey, // >> here [1] << // $attributeKey, // >> and here [3] << // $ruleKey - // ]; + // ]; $primaryAttributeKey = $primaryAttribute->getKey(); array_splice($message_keys, 1, 0, $primaryAttributeKey.$this->messageSeparator.$ruleKey); array_splice($message_keys, 3, 0, $primaryAttributeKey); @@ -359,7 +359,7 @@ protected function resolveRules($rules) foreach($rules as $i => $rule) { if (empty($rule)) continue; $params = []; - + if (is_string($rule)) { list($rulename, $params) = $this->parseRule($rule); $validator = call_user_func_array($validatorFactory, array_merge([$rulename], $params)); @@ -446,7 +446,7 @@ protected function resolveInputAttributes(array $inputs) $resolvedInputs = []; foreach($inputs as $key => $rules) { $exp = explode(':', $key); - + if (count($exp) > 1) { // set attribute alias $this->aliases[$exp[0]] = $exp[1]; @@ -457,7 +457,7 @@ protected function resolveInputAttributes(array $inputs) return $resolvedInputs; } - + public function getValidatedData() { return array_merge($this->validData, $this->invalidData); } @@ -465,8 +465,9 @@ public function getValidatedData() { protected function setValidData(Attribute $attribute, $value) { $key = $attribute->getKey(); - if ($attribute->isArrayAttribute()) { - Helper::arraySet($this->validData, $key, $value); + if ($attribute->isArrayAttribute() || $attribute->isUsingDotNotation()) { + Helper::arraySet($this->validData, $key, $value); + Helper::arrayUnset($this->invalidData, $key); } else { $this->validData[$key] = $value; } @@ -480,8 +481,9 @@ public function getValidData() protected function setInvalidData(Attribute $attribute, $value) { $key = $attribute->getKey(); - if ($attribute->isArrayAttribute()) { - Helper::arraySet($this->invalidData, $key, $value); + if ($attribute->isArrayAttribute() || $attribute->isUsingDotNotation()) { + Helper::arraySet($this->invalidData, $key, $value); + Helper::arrayUnset($this->validData, $key); } else { $this->invalidData[$key] = $value; } diff --git a/tests/ValidatorTest.php b/tests/ValidatorTest.php index 9a06036..b3546ca 100644 --- a/tests/ValidatorTest.php +++ b/tests/ValidatorTest.php @@ -76,7 +76,7 @@ public function testRequiredUploadedFile() $validation = $this->validator->validate([ 'file' => $empty_file ], [ - 'file' => 'required|uploaded_file' + 'file' => 'required|uploaded_file' ]); $errors = $validation->errors(); @@ -97,20 +97,20 @@ public function testOptionalUploadedFile() $validation = $this->validator->validate([ 'file' => $empty_file ], [ - 'file' => 'uploaded_file' + 'file' => 'uploaded_file' ]); $this->assertTrue($validation->passes()); } /** * @dataProvider getSamplesMissingKeyFromUploadedFileValue - */ + */ public function testMissingKeyUploadedFile($uploaded_file) { $validation = $this->validator->validate([ 'file' => $uploaded_file ], [ - 'file' => 'required|uploaded_file' + 'file' => 'required|uploaded_file' ]); $errors = $validation->errors(); @@ -335,7 +335,7 @@ public function testAfterRule() $this->assertFalse($validator2->passes()); } - + public function testNewValidationRuleCanBeAdded() { @@ -735,7 +735,7 @@ public function testUsingDefaults() 'is_enabled' => '1', 'is_published' => 'invalid-value' ]); - + // Getting only valid data $validData = $validation->getValidData(); $this->assertEquals($validData, [ @@ -914,13 +914,22 @@ public function testGetValidData() 'something', 'foo@blah.com' ], + 'stuffs' => [ + 'one' => '1', + 'two' => '2', + 'three' => 'three', + ], 'thing' => 'exists', ], [ 'thing' => 'required', 'items.*.product_id' => 'required|numeric', 'emails.*' => 'required|email', 'items.*.qty' => 'required|numeric', - 'something' => 'default:on|required|in:on,off' + 'something' => 'default:on|required|in:on,off', + 'stuffs' => 'required|array', + 'stuffs.one' => 'required|numeric', + 'stuffs.two' => 'required|numeric', + 'stuffs.three' => 'required|numeric', ]); $validData = $validation->getValidData(); @@ -936,8 +945,15 @@ public function testGetValidData() 2 => 'foo@blah.com' ], 'thing' => 'exists', - 'something' => 'on' + 'something' => 'on', + 'stuffs' => [ + 'one' => '1', + 'two' => '2', + ] ], $validData); + + $stuffs = $validData['stuffs']; + $this->assertFalse(isset($stuffs['three'])); } public function testGetInvalidData() @@ -954,13 +970,22 @@ public function testGetInvalidData() 'something', 'foo@blah.com' ], + 'stuffs' => [ + 'one' => '1', + 'two' => '2', + 'three' => 'three', + ], 'thing' => 'exists', ], [ 'thing' => 'required', 'items.*.product_id' => 'required|numeric', 'emails.*' => 'required|email', 'items.*.qty' => 'required|numeric', - 'something' => 'required|in:on,off' + 'something' => 'required|in:on,off', + 'stuffs' => 'required|array', + 'stuffs.one' => 'numeric', + 'stuffs.two' => 'numeric', + 'stuffs.three' => 'numeric', ]); $invalidData = $validation->getInvalidData(); @@ -974,8 +999,15 @@ public function testGetInvalidData() 'emails' => [ 1 => 'something' ], - 'something' => null + 'something' => null, + 'stuffs' => [ + 'three' => 'three', + ] ], $invalidData); + + $stuffs = $invalidData['stuffs']; + $this->assertFalse(isset($stuffs['one'])); + $this->assertFalse(isset($stuffs['two'])); } }