Completed
Push — master ( cb0578...28965e )
by Jeroen De
07:11 queued 04:27
created

src/ParamDefinition.php (12 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 = [];
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 = [];
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 = [];
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 36
	public function __construct( $type, $name, $default = null, $message = null, $isList = false ) {
173 36
		$this->type = $type;
174 36
		$this->name = $name;
175 36
		$this->default = $default;
176 36
		$this->message = $message;
177 36
		$this->isList = $isList;
178
179 36
		$this->postConstruct();
180 36
	}
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 36
	protected function postConstruct() {
189
190 36
	}
191
192
	/**
193
	 * @see IParamDefinition::trimDuringClean
194
	 *
195
	 * @since 1.0
196
	 *
197
	 * @return boolean|null
198
	 */
199 64
	public function trimDuringClean() {
200 64
		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 = [];
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
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 = [];
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 1
	public function getDefault() {
285 1
		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 56
	public function shouldManipulateDefault() {
329 56
		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 68
	public function getName() {
364 68
		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 21
	public function isRequired() {
403 21
		return is_null( $this->default );
404
	}
405
406
	/**
407
	 * @see IParamDefinition::isList
408
	 *
409
	 * @since 1.0
410
	 *
411
	 * @return boolean
412
	 */
413 64
	public function isList() {
414 64
		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 36
	public function setArrayValues( array $param ) {
447 36
		if ( array_key_exists( 'aliases', $param ) ) {
448
			$this->addAliases( $param['aliases'] );
449
		}
450
451 36
		if ( array_key_exists( 'dependencies', $param ) ) {
452
			$this->addDependencies( $param['dependencies'] );
453
		}
454
455 36
		if ( array_key_exists( 'trim', $param ) ) {
456
			$this->trimValue = $param['trim'];
457
		}
458
459 36
		if ( array_key_exists( 'delimiter', $param ) ) {
460
			$this->delimiter = $param['delimiter'];
461
		}
462
463 36
		if ( array_key_exists( 'manipulatedefault', $param ) ) {
464
			$this->setDoManipulationOfDefault( $param['manipulatedefault'] );
465
		}
466
467 36
		$this->options = $param;
468 36
	}
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 56
	public function format( IParam $param, array &$definitions, array $params ) {
481 56
		if ( $this->isList() && is_array( $param->getValue() ) ) {
482
			// TODO: if isList returns true, the value should be an array.
483
			// The second check here is to avoid a mysterious error.
484
			// Should have logging that writes down the value whenever this occurs.
485
486
			$values = $param->getValue();
487
488
			foreach ( $values as &$value ) {
489
				$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...
490
			}
491
492
			$param->setValue( $values );
493
			$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...
494
		}
495
		else {
496 56
			$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...
497
		}
498
499
		// deprecated, deriving classes should not add array-definitions to the list
500 56
		$definitions = self::getCleanDefinitions( $definitions );
501
502 56
		if ( array_key_exists( 'post-format', $this->options ) ) {
503
			$param->setValue( call_user_func( $this->options['post-format'], $param->getValue() ) );
504
		}
505 56
	}
506
507
	/**
508
	 * Formats the parameters values to their final result.
509
	 *
510
	 * @since 1.0
511
	 * @deprecated
512
	 *
513
	 * @param $param IParam
514
	 * @param $definitions array of IParamDefinition
515
	 * @param $params array of IParam
516
	 */
517
	protected function formatList( IParam $param, array &$definitions, array $params ) {
0 ignored issues
show
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...
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...
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...
518
		// TODO
519
	}
520
521
	/**
522
	 * Formats the parameter value to it's final result.
523
	 *
524
	 * @since 1.0
525
	 * @deprecated
526
	 *
527
	 * @param mixed $value
528
	 * @param IParam $param
529
	 * @param IParamDefinition[] $definitions
530
	 * @param IParam[] $params
531
	 *
532
	 * @return mixed
533
	 */
534 42
	protected function formatValue( $value, IParam $param, array &$definitions, array $params ) {
0 ignored issues
show
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...
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...
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...
535 42
		return $value;
536
		// No-op
537
	}
538
539
	/**
540
	 * Returns a cleaned version of the list of parameter definitions.
541
	 * This includes having converted all supported definition types to
542
	 * ParamDefinition classes and having all keys set to the names of the
543
	 * corresponding parameters.
544
	 *
545
	 * @since 1.0
546
	 *
547
	 * @param IParamDefinition[] $definitions
548
	 *
549
	 * @return IParamDefinition[]
550
	 * @throws Exception
551
	 */
552 56
	public static function getCleanDefinitions( array $definitions ) {
553 56
		$cleanList = [];
554
555 56
		foreach ( $definitions as $key => $definition ) {
556
			if ( is_array( $definition ) ) {
557
				if ( !array_key_exists( 'name', $definition ) && is_string( $key ) ) {
558
					$definition['name'] = $key;
559
				}
560
561
				$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...
562
			}
563
564
			if ( !( $definition instanceof IParamDefinition ) ) {
565
				throw new Exception( '$definition not an instance of IParamDefinition' );
566
			}
567
568
			$cleanList[$definition->getName()] = $definition;
569
		}
570
571 56
		return $cleanList;
572
	}
573
574
	/**
575
	 * @see IParamDefinition::getType
576
	 *
577
	 * @since 1.0
578
	 *
579
	 * @return string
580
	 */
581 80
	public function getType() {
582 80
		return $this->type;
583
	}
584
585
	/**
586
	 * @see IParamDefinition::getValueParser
587
	 *
588
	 * @since 1.0
589
	 *
590
	 * @return ValueParser
591
	 */
592 64
	public function getValueParser() {
593 64
		if ( $this->parser === null ) {
594 64
			$this->parser = new NullParser();
595
		}
596
597 64
		return $this->parser;
598
	}
599
600
	/**
601
	 * @see IParamDefinition::getValueValidator
602
	 *
603
	 * @since 1.0
604
	 *
605
	 * @return ValueValidator
606
	 */
607 64
	public function getValueValidator() {
608 64
		if ( $this->validator === null ) {
609
			$this->validator = new NullValidator();
610
		}
611
612 64
		return $this->validator;
613
	}
614
615
	/**
616
	 * @see IParamDefinition::setValueParser
617
	 *
618
	 * @since 1.0
619
	 *
620
	 * @param ValueParser $parser
621
	 */
622
	public function setValueParser( ValueParser $parser ) {
623
		$this->parser = $parser;
624
	}
625
626
	/**
627
	 * @see IParamDefinition::setValueValidator
628
	 *
629
	 * @since 1.0
630
	 *
631
	 * @param ValueValidator $validator
632
	 */
633 36
	public function setValueValidator( ValueValidator $validator ) {
634 36
		$this->validator = $validator;
635 36
	}
636
637
	/**
638
	 * @see IParamDefinition::setValidationCallback
639
	 *
640
	 * @since 1.0
641
	 *
642
	 * @param callable $validationFunction
643
	 */
644 36
	public function setValidationCallback( /* callable */ $validationFunction ) {
645 36
		$this->validationFunction = $validationFunction;
646 36
	}
647
648
	/**
649
	 * @see IParamDefinition::getValidationCallback
650
	 *
651
	 * @since 1.0
652
	 *
653
	 * @return callable|null
654
	 */
655 64
	public function getValidationCallback() {
656 64
		return $this->validationFunction;
657
	}
658
659
	/**
660
	 * @since 0.1
661
	 *
662
	 * @return array
663
	 */
664 64
	public function getOptions() {
665 64
		return $this->options;
666
	}
667
668
}
669