Completed
Push — master ( b5c2b5...842562 )
by Jeroen De
02:32
created

ParamDefinition::validate()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 22
rs 8.6737
cc 6
eloc 12
nc 8
nop 4
1
<?php
2
3
namespace ParamProcessor;
4
5
use Exception;
6
7
use ValueParsers\ValueParser;
8
use ValueParsers\NullParser;
9
10
use ValueValidators\ValueValidator;
11
use ValueValidators\NullValidator;
12
13
/**
14
 * Parameter definition.
15
 * Specifies what kind of values are accepted, how they should be validated,
16
 * how they should be formatted, what their dependencies are and how they should be described.
17
 *
18
 * Try to avoid using this interface outside of ParamProcessor for anything else then defining parameters.
19
 * In particular, do not derive from this class to implement methods such as formatValue.
20
 *
21
 * @since 1.0
22
 *
23
 * @licence GNU GPL v2+
24
 * @author Jeroen De Dauw < [email protected] >
25
 */
26
class ParamDefinition implements IParamDefinition {
0 ignored issues
show
Deprecated Code introduced by
The interface ParamProcessor\IParamDefinition has been deprecated with message: since 1.0, use ParamDefinition

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
27
28
	/**
29
	 * Indicates whether parameters that are provided more then once  should be accepted,
30
	 * and use the first provided value, or not, and generate an error.
31
	 *
32
	 * @since 1.0
33
	 *
34
	 * @var boolean
35
	 */
36
	public static $acceptOverriding = false;
37
38
	/**
39
	 * Indicates whether parameters not found in the criteria list
40
	 * should be stored in case they are not accepted. The default is false.
41
	 *
42
	 * @since 1.0
43
	 *
44
	 * @var boolean
45
	 */
46
	public static $accumulateParameterErrors = false;
47
48
	/**
49
	 * Indicates if the parameter value should trimmed during the clean process.
50
	 *
51
	 * @since 1.0
52
	 *
53
	 * @var boolean|null
54
	 */
55
	protected $trimValue = null;
56
57
	/**
58
	 * Indicates if the parameter manipulations should be applied to the default value.
59
	 *
60
	 * @since 1.0
61
	 *
62
	 * @var boolean
63
	 */
64
	protected $applyManipulationsToDefault = true;
65
66
	/**
67
	 * Dependency list containing parameters that need to be handled before this one.
68
	 *
69
	 * @since 1.0
70
	 *
71
	 * @var array
72
	 */
73
	protected $dependencies = array();
74
75
	/**
76
	 * The default value for the parameter, or null when the parameter is required.
77
	 *
78
	 * @since 1.0
79
	 *
80
	 * @var mixed
81
	 */
82
	protected $default;
83
84
	/**
85
	 * The main name of the parameter.
86
	 *
87
	 * @since 1.0
88
	 *
89
	 * @var string
90
	 */
91
	protected $name;
92
93
	/**
94
	 * @since 1.0
95
	 * @var boolean
96
	 */
97
	protected $isList;
98
99
	/**
100
	 * @since 1.0
101
	 * @var string
102
	 */
103
	protected $delimiter = ',';
104
105
	/**
106
	 * List of aliases for the parameter name.
107
	 *
108
	 * @since 1.0
109
	 *
110
	 * @var array
111
	 */
112
	protected $aliases = array();
113
114
	/**
115
	 * A message that acts as description for the parameter or false when there is none.
116
	 * Can be obtained via getMessage and set via setMessage.
117
	 *
118
	 * @since 1.0
119
	 *
120
	 * @var string
121
	 */
122
	protected $message = 'validator-message-nodesc';
123
124
	/**
125
	 * Original array definition of the parameter
126
	 *
127
	 * @since 1.0
128
	 *
129
	 * @var array
130
	 */
131
	protected $options = array();
132
133
	/**
134
	 * @since 1.0
135
	 *
136
	 * @var ValueParser|null
137
	 */
138
	protected $parser = null;
139
140
	/**
141
	 * @since 1.0
142
	 *
143
	 * @var ValueValidator|null
144
	 */
145
	protected $validator = null;
146
147
	/**
148
	 * @since 0.1
149
	 *
150
	 * @var callable|null
151
	 */
152
	protected $validationFunction = null;
153
154
	/**
155
	 * @since 0.1
156
	 *
157
	 * @var string
158
	 */
159
	protected $type;
160
161
	/**
162
	 * Constructor.
163
	 *
164
	 * @since 1.0
165
	 *
166
	 * @param string $type
167
	 * @param string $name
168
	 * @param mixed $default Use null for no default (which makes the parameter required)
169
	 * @param string $message
170
	 * @param boolean $isList
171
	 */
172
	public function __construct( $type, $name, $default = null, $message = null, $isList = false ) {
173
		$this->type = $type;
174
		$this->name = $name;
175
		$this->default = $default;
176
		$this->message = $message;
177
		$this->isList = $isList;
178
179
		$this->postConstruct();
180
	}
181
182
	/**
183
	 * Allows deriving classed to do additional stuff on instance construction
184
	 * without having to get and pass all the constructor arguments.
185
	 *
186
	 * @since 1.0
187
	 */
188
	protected function postConstruct() {
189
190
	}
191
192
	/**
193
	 * @see IParamDefinition::trimDuringClean
194
	 *
195
	 * @since 1.0
196
	 *
197
	 * @return boolean|null
198
	 */
199
	public function trimDuringClean() {
200
		return $this->trimValue;
201
	}
202
203
	/**
204
	 * @see IParamDefinition::getAliases
205
	 *
206
	 * @since 1.0
207
	 *
208
	 * @return array
209
	 */
210
	public function getAliases() {
211
		return $this->aliases;
212
	}
213
214
	/**
215
	 * @see IParamDefinition::hasAlias
216
	 *
217
	 * @since 1.0
218
	 *
219
	 * @param string $alias
220
	 *
221
	 * @return boolean
222
	 */
223
	public function hasAlias( $alias ) {
224
		return in_array( $alias, $this->getAliases() );
225
	}
226
227
	/**
228
	 * @see IParamDefinition::hasDependency
229
	 *
230
	 * @since 1.0
231
	 *
232
	 * @param string $dependency
233
	 *
234
	 * @return boolean
235
	 */
236
	public function hasDependency( $dependency ) {
237
		return in_array( $dependency, $this->getDependencies() );
238
	}
239
240
	/**
241
	 * Returns the list of allowed values, or false if there is no such restriction.
242
	 *
243
	 * @since 1.0
244
	 *
245
	 * @return array|boolean false
246
	 */
247
	public function getAllowedValues() {
248
		$allowedValues = array();
249
250
		if ( $this->validator !== null && method_exists( $this->validator, 'getWhitelistedValues' ) ) {
251
			// TODO: properly implement this
252
			$this->validator->setOptions( $this->options );
253
254
			$allowedValues = $this->validator->getWhitelistedValues();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface ValueValidators\ValueValidator as the method getWhitelistedValues() does only exist in the following implementations of said interface: ValueValidators\DimensionValidator, ValueValidators\ListValidator, ValueValidators\RangeValidator, ValueValidators\StringValidator, ValueValidators\TitleValidator, ValueValidators\ValueValidatorObject.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
255
256
			if ( $allowedValues === false ) {
257
				$allowedValues = array();
258
			}
259
		}
260
261
		return $allowedValues;
262
	}
263
264
	/**
265
	 * @see IParamDefinition::setDefault
266
	 *
267
	 * @since 1.0
268
	 *
269
	 * @param mixed $default
270
	 * @param boolean $manipulate Should the default be manipulated or not? Since 0.4.6.
271
	 */
272
	public function setDefault( $default, $manipulate = true ) {
273
		$this->default = $default;
274
		$this->setDoManipulationOfDefault( $manipulate );
275
	}
276
277
	/**
278
	 * @see IParamDefinition::getDefault
279
	 *
280
	 * @since 1.0
281
	 *
282
	 * @return mixed
283
	 */
284
	public function getDefault() {
285
		return $this->default;
286
	}
287
288
	/**
289
	 * @see IParamDefinition::getMessage
290
	 *
291
	 * @since 1.0
292
	 *
293
	 * @return string
294
	 */
295
	public function getMessage() {
296
		return $this->message;
297
	}
298
299
	/**
300
	 * @see IParamDefinition::setMessage
301
	 *
302
	 * @since 1.0
303
	 *
304
	 * @param string $message
305
	 */
306
	public function setMessage( $message ) {
307
		$this->message = $message;
308
	}
309
310
	/**
311
	 * @see IParamDefinition::setDoManipulationOfDefault
312
	 *
313
	 * @since 1.0
314
	 *
315
	 * @param boolean $doOrDoNotThereIsNoTry
316
	 */
317
	public function setDoManipulationOfDefault( $doOrDoNotThereIsNoTry ) {
318
		$this->applyManipulationsToDefault = $doOrDoNotThereIsNoTry;
319
	}
320
321
	/**
322
	 * @see IParamDefinition::shouldManipulateDefault
323
	 *
324
	 * @since 1.0
325
	 *
326
	 * @return boolean
327
	 */
328
	public function shouldManipulateDefault() {
329
		return $this->applyManipulationsToDefault;
330
	}
331
332
	/**
333
	 * @see IParamDefinition::addAliases
334
	 *
335
	 * @since 1.0
336
	 *
337
	 * @param mixed $aliases string or array of string
338
	 */
339
	public function addAliases( $aliases ) {
340
		$args = func_get_args();
341
		$this->aliases = array_merge( $this->aliases, is_array( $args[0] ) ? $args[0] : $args );
342
	}
343
344
	/**
345
	 * @see IParamDefinition::addDependencies
346
	 *
347
	 * @since 1.0
348
	 *
349
	 * @param mixed $dependencies string or array of string
350
	 */
351
	public function addDependencies( $dependencies ) {
352
		$args = func_get_args();
353
		$this->dependencies = array_merge( $this->dependencies, is_array( $args[0] ) ? $args[0] : $args );
354
	}
355
356
	/**
357
	 * @see IParamDefinition::getName
358
	 *
359
	 * @since 1.0
360
	 *
361
	 * @return string
362
	 */
363
	public function getName() {
364
		return $this->name;
365
	}
366
367
	/**
368
	 * Returns a message key for a message describing the parameter type.
369
	 *
370
	 * @since 1.0
371
	 *
372
	 * @return string
373
	 */
374
	public function getTypeMessage() {
375
		$message = 'validator-type-' . $this->getType();
376
377
		if ( $this->isList() ) {
378
			$message .= '-list';
379
		}
380
381
		return $message;
382
	}
383
384
	/**
385
	 * @see IParamDefinition::getDependencies
386
	 *
387
	 * @since 1.0
388
	 *
389
	 * @return array
390
	 */
391
	public function getDependencies() {
392
		return $this->dependencies;
393
	}
394
395
	/**
396
	 * @see IParamDefinition::isRequired
397
	 *
398
	 * @since 1.0
399
	 *
400
	 * @return boolean
401
	 */
402
	public function isRequired() {
403
		return is_null( $this->default );
404
	}
405
406
	/**
407
	 * @see IParamDefinition::isList
408
	 *
409
	 * @since 1.0
410
	 *
411
	 * @return boolean
412
	 */
413
	public function isList() {
414
		return $this->isList;
415
	}
416
417
	/**
418
	 * @see IParamDefinition::getDelimiter
419
	 *
420
	 * @since 1.0
421
	 *
422
	 * @return string
423
	 */
424
	public function getDelimiter() {
425
		return $this->delimiter;
426
	}
427
428
	/**
429
	 * @see IParamDefinition::setDelimiter
430
	 *
431
	 * @since 1.0
432
	 *
433
	 * @param $delimiter string
434
	 */
435
	public function setDelimiter( $delimiter ) {
436
		$this->delimiter = $delimiter;
437
	}
438
439
	/**
440
	 * @see IParamDefinition::setArrayValues
441
	 *
442
	 * @since 1.0
443
	 *
444
	 * @param array $param
445
	 */
446
	public function setArrayValues( array $param ) {
447
		if ( array_key_exists( 'aliases', $param ) ) {
448
			$this->addAliases( $param['aliases'] );
449
		}
450
451
		if ( array_key_exists( 'dependencies', $param ) ) {
452
			$this->addDependencies( $param['dependencies'] );
453
		}
454
455
		if ( array_key_exists( 'trim', $param ) ) {
456
			$this->trimValue = $param['trim'];
457
		}
458
459
		if ( array_key_exists( 'delimiter', $param ) ) {
460
			$this->delimiter = $param['delimiter'];
461
		}
462
463
		if ( array_key_exists( 'manipulatedefault', $param ) ) {
464
			$this->setDoManipulationOfDefault( $param['manipulatedefault'] );
465
		}
466
467
		$this->options = $param;
468
	}
469
470
	/**
471
	 * @see IParamDefinition::format
472
	 *
473
	 * @since 1.0
474
	 * @deprecated
475
	 *
476
	 * @param IParam $param
477
	 * @param IParamDefinition[] $definitions
478
	 * @param IParam[] $params
479
	 */
480
	public function format( IParam $param, array &$definitions, array $params ) {
481
		if ( $this->isList() ) {
482
			$values = $param->getValue();
483
484
			foreach ( $values as &$value ) {
485
				$value = $this->formatValue( $value, $param, $definitions, $params );
0 ignored issues
show
Deprecated Code introduced by
The method ParamProcessor\ParamDefinition::formatValue() has been deprecated.

This method has been deprecated.

Loading history...
486
			}
487
488
			$param->setValue( $values );
489
			$this->formatList( $param, $definitions, $params );
0 ignored issues
show
Deprecated Code introduced by
The method ParamProcessor\ParamDefinition::formatList() has been deprecated.

This method has been deprecated.

Loading history...
490
		}
491
		else {
492
			$param->setValue( $this->formatValue( $param->getValue(), $param, $definitions, $params ) );
0 ignored issues
show
Deprecated Code introduced by
The method ParamProcessor\ParamDefinition::formatValue() has been deprecated.

This method has been deprecated.

Loading history...
493
		}
494
495
		// deprecated, deriving classes should not add array-definitions to the list
496
		$definitions = self::getCleanDefinitions( $definitions );
497
498
		if ( array_key_exists( 'post-format', $this->options ) ) {
499
			$param->setValue( call_user_func( $this->options['post-format'], $param->getValue() ) );
500
		}
501
	}
502
503
	/**
504
	 * Formats the parameters values to their final result.
505
	 *
506
	 * @since 1.0
507
	 * @deprecated
508
	 *
509
	 * @param $param IParam
510
	 * @param $definitions array of IParamDefinition
511
	 * @param $params array of IParam
512
	 */
513
	protected function formatList( IParam $param, array &$definitions, array $params ) {
0 ignored issues
show
Unused Code introduced by
The parameter $param is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $definitions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
514
		// TODO
515
	}
516
517
	/**
518
	 * Formats the parameter value to it's final result.
519
	 *
520
	 * @since 1.0
521
	 * @deprecated
522
	 *
523
	 * @param mixed $value
524
	 * @param IParam $param
525
	 * @param IParamDefinition[] $definitions
526
	 * @param IParam[] $params
527
	 *
528
	 * @return mixed
529
	 */
530
	protected function formatValue( $value, IParam $param, array &$definitions, array $params ) {
0 ignored issues
show
Unused Code introduced by
The parameter $param is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $definitions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
531
		return $value;
532
		// No-op
533
	}
534
535
	/**
536
	 * Returns a cleaned version of the list of parameter definitions.
537
	 * This includes having converted all supported definition types to
538
	 * ParamDefinition classes and having all keys set to the names of the
539
	 * corresponding parameters.
540
	 *
541
	 * @since 1.0
542
	 *
543
	 * @param IParamDefinition[] $definitions
544
	 *
545
	 * @return IParamDefinition[]
546
	 * @throws Exception
547
	 */
548
	public static function getCleanDefinitions( array $definitions ) {
549
		$cleanList = array();
550
551
		foreach ( $definitions as $key => $definition ) {
552
			if ( is_array( $definition ) ) {
553
				if ( !array_key_exists( 'name', $definition ) && is_string( $key ) ) {
554
					$definition['name'] = $key;
555
				}
556
557
				$definition = ParamDefinitionFactory::singleton()->newDefinitionFromArray( $definition );
0 ignored issues
show
Deprecated Code introduced by
The method ParamProcessor\ParamDefinitionFactory::singleton() has been deprecated with message: since 1.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
558
			}
559
560
			if ( !( $definition instanceof IParamDefinition ) ) {
561
				throw new Exception( '$definition not an instance of IParamDefinition' );
562
			}
563
564
			$cleanList[$definition->getName()] = $definition;
565
		}
566
567
		return $cleanList;
568
	}
569
570
	/**
571
	 * @see IParamDefinition::getType
572
	 *
573
	 * @since 1.0
574
	 *
575
	 * @return string
576
	 */
577
	public function getType() {
578
		return $this->type;
579
	}
580
581
	/**
582
	 * @see IParamDefinition::getValueParser
583
	 *
584
	 * @since 1.0
585
	 *
586
	 * @return ValueParser
587
	 */
588
	public function getValueParser() {
589
		if ( $this->parser === null ) {
590
			$this->parser = new NullParser();
591
		}
592
593
		return $this->parser;
594
	}
595
596
	/**
597
	 * @see IParamDefinition::getValueValidator
598
	 *
599
	 * @since 1.0
600
	 *
601
	 * @return ValueValidator
602
	 */
603
	public function getValueValidator() {
604
		if ( $this->validator === null ) {
605
			$this->validator = new NullValidator();
606
		}
607
608
		return $this->validator;
609
	}
610
611
	/**
612
	 * @see IParamDefinition::setValueParser
613
	 *
614
	 * @since 1.0
615
	 *
616
	 * @param ValueParser $parser
617
	 */
618
	public function setValueParser( ValueParser $parser ) {
619
		$this->parser = $parser;
620
	}
621
622
	/**
623
	 * @see IParamDefinition::setValueValidator
624
	 *
625
	 * @since 1.0
626
	 *
627
	 * @param ValueValidator $validator
628
	 */
629
	public function setValueValidator( ValueValidator $validator ) {
630
		$this->validator = $validator;
631
	}
632
633
	/**
634
	 * @see IParamDefinition::setValidationCallback
635
	 *
636
	 * @since 1.0
637
	 *
638
	 * @param callable $validationFunction
639
	 */
640
	public function setValidationCallback( /* callable */ $validationFunction ) {
641
		$this->validationFunction = $validationFunction;
642
	}
643
644
	/**
645
	 * @see IParamDefinition::getValidationCallback
646
	 *
647
	 * @since 1.0
648
	 *
649
	 * @return callable|null
650
	 */
651
	public function getValidationCallback() {
652
		return $this->validationFunction;
653
	}
654
655
	/**
656
	 * @since 0.1
657
	 *
658
	 * @return array
659
	 */
660
	public function getOptions() {
661
		return $this->options;
662
	}
663
664
}
665