Skip to content

Commit 69b2995

Browse files
author
Craig Manley
committed
Overhauled the validate_pos() method and added many more validate_pos() unit tests.
1 parent d1c170a commit 69b2995

File tree

2 files changed

+198
-92
lines changed

2 files changed

+198
-92
lines changed

src/Validator.php

+41-18
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* @author Craig Manley
1212
* @copyright Copyright © 2016, Craig Manley (www.craigmanley.com)
1313
* @license http://www.opensource.org/licenses/mit-license.php Licensed under MIT
14-
* @version $Id: Validator.php,v 1.4 2018/05/26 22:55:49 cmanley Exp $
14+
* @version $Id: Validator.php,v 1.5 2018/07/01 18:41:02 cmanley Exp $
1515
* @package Validate
1616
*/
1717
namespace Validate;
@@ -94,7 +94,7 @@
9494
class Validator {
9595

9696
protected $allow_extra = null;
97-
protected $empty_delete = true; # odd one out - normally defaults are false
97+
protected $empty_delete = true; # odd one out - normally defaults are false/negative/null
9898
protected $empty_null = null;
9999
protected $prefix = '';
100100
protected $remove_extra = false;
@@ -185,7 +185,8 @@ public function specs() {
185185

186186

187187
/**
188-
* Validates the given associative array.
188+
* Validates the given associative array and returns the validated result.
189+
* The result may be mutated depending on the options and specs used.
189190
*
190191
* @param array $args associative array
191192
* @return array
@@ -254,7 +255,8 @@ public function validate(array $args) {
254255

255256

256257
/**
257-
* Validates a plain positional array of arguments.
258+
* Validates a plain positional array of arguments and returns the validated result.
259+
* The result may be mutated depending on the options and specs used.
258260
* Since all PHP arrays are really associative, this function reindexes the args and the specs.
259261
* Because of this, you can use still use strings for keys in either the args or the specs.
260262
*
@@ -263,28 +265,49 @@ public function validate(array $args) {
263265
* @throws ValidationException
264266
*/
265267
public function validate_pos(array $args) {
268+
$args = array_values($args); # this make sure that args is a sequential numerically indexed array.
266269
$specs = $this->specs();
267270
if ($specs) {
268271
$specs = array_values($this->specs()->toArray()); # make sure that specs is a sequential numerically indexed array.
269-
}
270-
$args = array_values($args); # this make sure that args is a sequential numerically indexed array.
271-
foreach ($args as $k => &$v) {
272-
if ($this->empty_null && is_string($v) && !strlen($v)) {
273-
$v = null;
272+
$count_args = count($args);
273+
$count_specs = count($specs);
274+
275+
# Handle too many arguments
276+
if ($count_args > $count_specs) {
277+
if (!$this->allow_extra && !$this->remove_extra) {
278+
throw new ValidationException('Too many arguments given (' . $count_args . ') for the number of specs (' . $count_specs . ')');
279+
#throw new ValidationException('Unexpected parameter at index ' . $this->prefix . $k);
280+
}
281+
if ($this->remove_extra) {
282+
array_splice($args, $count_specs);
283+
}
274284
}
275-
$spec = $specs && (is_array($specs) ? array_key_exists($k, $specs) : $specs->offsetExists($k)) ? $specs[$k] : null; # array_key_exists does not work with ArrayAccess objects yet. Perhaps in the future it will.
276-
if (!$spec) {
277-
# note: remove_extra doesn't apply to positional arrays
278-
if (!$this->allow_extra) {
279-
throw new ValidationException('Unexpected parameter at index ' . $this->prefix . $k);
285+
}
286+
287+
# Convert empty strings to null values if so wanted.
288+
if ($this->empty_null) {
289+
foreach ($args as $k => &$v) {
290+
if (is_string($v) && !strlen($v)) {
291+
$v = null;
280292
}
281-
continue;
293+
unset($v);
282294
}
283-
if (!$spec->validate($v)) { # also applies before/after mutators to $v reference
284-
throw new ValidationNamedCheckException($this->prefix . $k, $spec->getLastFailure(), $v);
295+
}
296+
297+
# Validate
298+
if ($specs) {
299+
foreach ($specs as $i => $spec) {
300+
$v = null;
301+
if ($i < $count_args) {
302+
$v =& $args[$i];
303+
}
304+
if (!$spec->validate($v)) { # also applies before/after mutators to $v reference
305+
throw new ValidationNamedCheckException($this->prefix . $i, $spec->getLastFailure(), $v);
306+
}
307+
unset($v);
285308
}
286-
unset($v);
287309
}
310+
288311
return $args;
289312
}
290313
}

t/Validator.t.php

+157-74
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ public function testValidate() {
167167
}
168168
}
169169

170-
public function testValidatePosNamedSpecs() {
170+
public function testValidatePosSpecs() {
171171
$specs = array(
172-
'name' => array(
172+
array(
173173
'type' => 'string',
174174
'max_length' => 2,
175175
'max_length' => 30,
@@ -179,91 +179,174 @@ public function testValidatePosNamedSpecs() {
179179
}
180180
},
181181
),
182-
'score' => array(
182+
'score' => array( # string keys are allowed too.
183183
'types' => array('float', 'integer'),
184184
'max_value' => 10,
185185
'min_value' => 0,
186186
),
187187
);
188-
$validator = new Validate\Validator(array(
189-
'specs' => $specs,
190-
));
188+
$inputs = array(
189+
'normal' => array('Jane', 7),
190+
'too few params' => array('Jane'),
191+
'too many params' => array('Jane', 7, '', 'bla'),
192+
'invalid 2nd param (index 1)' => array('Mike', 'high'),
193+
'no params' => array(),
194+
);
191195
$tests = array(
192-
array(
193-
'input' => array('Jane', 7),
194-
'expect' => array('JANE', 7),
195-
'expect_exception' => null,
196-
),
197-
array(
198-
'input' => array('Mike', 'high'),
199-
'expect' => null,
200-
'expect_exception' => 'Parameter "1" validation check "types" failed for string value "high"',
196+
'no options' => array(
197+
'options' => array(),
198+
'expects' => array(
199+
'normal' => array(
200+
'expect' => array('JANE', 7),
201+
'expect_exception' => null,
202+
),
203+
'too few params' => array(
204+
'expect' => null,
205+
'expect_exception' => 'Parameter "1" validation check "mandatory" failed for NULL value',
206+
),
207+
'too many params' => array(
208+
'expect' => null,
209+
'expect_exception' => 'Too many arguments given (4) for the number of specs (2)',
210+
),
211+
'invalid 2nd param (index 1)' => array(
212+
'expect' => null,
213+
'expect_exception' => 'Parameter "1" validation check "types" failed for string value "high"',
214+
),
215+
'no params' => array(
216+
'expect' => null,
217+
'expect_exception' => 'Parameter "0" validation check "mandatory" failed for NULL value',
218+
),
219+
),
201220
),
202-
);
203-
foreach ($tests as $i => $test) {
204-
$input = $test['input'];
205-
$expect = $test['expect'];
206-
$expect_exception = $test['expect_exception'];
207-
$got_exception = null;
208-
$validated_input = null;
209-
try {
210-
$validated_input = $validator->validate_pos($input);
211-
}
212-
catch (Validate\ValidationException $e) {
213-
$got_exception = $e->getMessage();
214-
}
215-
$this->assertEquals($expect, $validated_input, "Test $i validate() returns expected result.");
216-
$this->assertEquals($expect_exception, $got_exception, "Test $i throws the expected exception.");
217-
}
218-
}
219-
220-
public function testValidatePosUnnamedSpecs() {
221-
$specs = array(
222-
array(
223-
'type' => 'string',
224-
'max_length' => 2,
225-
'max_length' => 30,
226-
'after' => function(&$value) {
227-
if (is_string($value)) {
228-
$value = strtoupper($value);
229-
}
230-
},
221+
'allow_extra is true' => array(
222+
'options' => array(
223+
'allow_extra' => true,
224+
),
225+
'expects' => array(
226+
'normal' => array(
227+
'expect' => array('JANE', 7),
228+
'expect_exception' => null,
229+
),
230+
'too few params' => array(
231+
'expect' => null,
232+
'expect_exception' => 'Parameter "1" validation check "mandatory" failed for NULL value',
233+
),
234+
'too many params' => array(
235+
'expect' => array('JANE', 7, '', 'bla'),
236+
'expect_exception' => null,
237+
),
238+
'invalid 2nd param (index 1)' => array(
239+
'expect' => null,
240+
'expect_exception' => 'Parameter "1" validation check "types" failed for string value "high"',
241+
),
242+
'no params' => array(
243+
'expect' => null,
244+
'expect_exception' => 'Parameter "0" validation check "mandatory" failed for NULL value',
245+
),
246+
),
231247
),
232-
array(
233-
'types' => array('float', 'integer'),
234-
'max_value' => 10,
235-
'min_value' => 0,
248+
'remove_extra is true' => array(
249+
'options' => array(
250+
'remove_extra' => true,
251+
),
252+
'expects' => array(
253+
'normal' => array(
254+
'expect' => array('JANE', 7),
255+
'expect_exception' => null,
256+
),
257+
'too few params' => array(
258+
'expect' => null,
259+
'expect_exception' => 'Parameter "1" validation check "mandatory" failed for NULL value',
260+
),
261+
'too many params' => array(
262+
'expect' => array('JANE', 7),
263+
'expect_exception' => null,
264+
),
265+
'invalid 2nd param (index 1)' => array(
266+
'expect' => null,
267+
'expect_exception' => 'Parameter "1" validation check "types" failed for string value "high"',
268+
),
269+
'no params' => array(
270+
'expect' => null,
271+
'expect_exception' => 'Parameter "0" validation check "mandatory" failed for NULL value',
272+
),
273+
),
236274
),
237-
);
238-
$validator = new Validate\Validator(array(
239-
'specs' => $specs,
240-
));
241-
$tests = array(
242-
array(
243-
'input' => array('Jane', 7),
244-
'expect' => array('JANE', 7),
245-
'expect_exception' => null,
275+
'allow_extra is true and remove_extra is true' => array(
276+
'options' => array(
277+
'allow_extra' => true,
278+
'remove_extra' => true,
279+
),
280+
'expects' => array(
281+
'normal' => array(
282+
'expect' => array('JANE', 7),
283+
'expect_exception' => null,
284+
),
285+
'too few params' => array(
286+
'expect' => null,
287+
'expect_exception' => 'Parameter "1" validation check "mandatory" failed for NULL value',
288+
),
289+
'too many params' => array(
290+
'expect' => array('JANE', 7),
291+
'expect_exception' => null,
292+
),
293+
'invalid 2nd param (index 1)' => array(
294+
'expect' => null,
295+
'expect_exception' => 'Parameter "1" validation check "types" failed for string value "high"',
296+
),
297+
'no params' => array(
298+
'expect' => null,
299+
'expect_exception' => 'Parameter "0" validation check "mandatory" failed for NULL value',
300+
),
301+
),
246302
),
247-
array(
248-
'input' => array('Mike', 'high'),
249-
'expect' => null,
250-
'expect_exception' => 'Parameter "1" validation check "types" failed for string value "high"',
303+
'allow_extra is true and empty_null is true' => array(
304+
'options' => array(
305+
'allow_extra' => true,
306+
'empty_null' => true,
307+
),
308+
'expects' => array(
309+
'normal' => array(
310+
'expect' => array('JANE', 7),
311+
'expect_exception' => null,
312+
),
313+
'too few params' => array(
314+
'expect' => null,
315+
'expect_exception' => 'Parameter "1" validation check "mandatory" failed for NULL value',
316+
),
317+
'too many params' => array(
318+
'expect' => array('JANE', 7, null, 'bla'),
319+
'expect_exception' => null,
320+
),
321+
'invalid 2nd param (index 1)' => array(
322+
'expect' => null,
323+
'expect_exception' => 'Parameter "1" validation check "types" failed for string value "high"',
324+
),
325+
'no params' => array(
326+
'expect' => null,
327+
'expect_exception' => 'Parameter "0" validation check "mandatory" failed for NULL value',
328+
),
329+
),
251330
),
252331
);
253-
foreach ($tests as $i => $test) {
254-
$input = $test['input'];
255-
$expect = $test['expect'];
256-
$expect_exception = $test['expect_exception'];
257-
$got_exception = null;
258-
$validated_input = null;
259-
try {
260-
$validated_input = $validator->validate_pos($input);
261-
}
262-
catch (Validate\ValidationException $e) {
263-
$got_exception = $e->getMessage();
332+
foreach ($tests as $name => $test) {
333+
$args = $test['options'];
334+
$args['specs'] = $specs;
335+
$validator = new Validate\Validator($args);
336+
foreach ($inputs as $input_name => $input) {
337+
$expect = $test['expects'][$input_name]['expect'];
338+
$expect_exception = $test['expects'][$input_name]['expect_exception'];
339+
$got_exception = null;
340+
$validated_input = null;
341+
try {
342+
$validated_input = $validator->validate_pos($input);
343+
}
344+
catch (Validate\ValidationException $e) {
345+
$got_exception = $e->getMessage();
346+
}
347+
$this->assertEquals($expect, $validated_input, "Test \"$name\"->\"$input_name\" validate() returns expected result.");
348+
$this->assertEquals($expect_exception, $got_exception, "Test \"$name\"->\"$input_name\" throws the expected exception.");
264349
}
265-
$this->assertEquals($expect, $validated_input, "Test $i validate() returns expected result.");
266-
$this->assertEquals($expect_exception, $got_exception, "Test $i throws the expected exception.");
267350
}
268351
}
269352

0 commit comments

Comments
 (0)