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

src/ParamDefinitionFactory.php (2 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
use OutOfBoundsException;
7
8
/**
9
 * Factory for IParamDefinition implementing objects.
10
 *
11
 * @licence GNU GPL v2+
12
 * @author Jeroen De Dauw < [email protected] >
13
 */
14
class ParamDefinitionFactory {
15
16
	/**
17
	 * Maps parameter type to handling IParameterDefinition implementing class.
18
	 *
19
	 * @since 1.0
20
	 *
21
	 * @var array
22
	 */
23
	private $typeToClass = [];
24
25
	/**
26
	 * Maps parameter type to its associated components.
27
	 *
28
	 * @since 1.0
29
	 *
30
	 * @var array
31
	 */
32
	private $typeToComponent = [];
33
34
	/**
35
	 * Singleton.
36
	 *
37
	 * @since 1.0
38
	 * @deprecated since 1.0
39
	 *
40
	 * @return ParamDefinitionFactory
41
	 */
42 64
	public static function singleton() {
43 64
		static $instance = false;
44
45 64
		if ( $instance === false ) {
46
			$instance = new self();
47
			$instance->registerGlobals();
48
		}
49
50 64
		return $instance;
0 ignored issues
show
Bug Compatibility introduced by
The expression return $instance; of type ParamProcessor\ParamDefinitionFactory|false is incompatible with the return type documented by ParamProcessor\ParamDefinitionFactory::singleton of type ParamProcessor\ParamDefinitionFactory as it can also be of type false which is not included in this return type.
Loading history...
51
	}
52
53
	/**
54
	 * Registers the parameter types specified in the global $wgParamDefinitions.
55
	 *
56
	 * @since 1.0
57
	 */
58
	public function registerGlobals() {
0 ignored issues
show
registerGlobals uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
59
		if ( array_key_exists( 'wgParamDefinitions', $GLOBALS ) ) {
60
			foreach ( $GLOBALS['wgParamDefinitions'] as $type => $data ) {
61
				if ( is_string( $data ) ) {
62
					$data = [ 'definition' => $data ];
63
				}
64
65
				$this->registerType( $type, $data );
66
			}
67
		}
68
	}
69
70
	/**
71
	 * Registers a parameter type.
72
	 *
73
	 * The type is specified as a string identifier for the type, ie 'boolean',
74
	 * and an array containing further data. This data currently includes:
75
	 *
76
	 * - string-parser:       the parser to use to transform string values
77
	 *                        This class needs to implement ValueParser. Default: NullParser
78
	 * - typed-parser:        the parser to use to transform typed PHP values
79
	 *                        This class needs to implement ValueParser. Default: NullParser
80
	 * - validator:           the validation object to use
81
	 *                        This class needs to implement ValueValidator. Default: NullValidator
82
	 * - validation-callback  a callback to use for validation, called before the ValueValidator
83
	 *                        This callback needs to return a boolean indicating validity.
84
	 *
85
	 * @since 1.0
86
	 *
87
	 * @param string $type
88
	 * @param array $data
89
	 *
90
	 * @return boolean Indicates if the type was registered
91
	 */
92
	public function registerType( $type, array $data ) {
93
		if ( array_key_exists( $type, $this->typeToClass ) ) {
94
			return false;
95
		}
96
97
		$class = array_key_exists( 'definition', $data ) ? $data['definition'] : 'ParamProcessor\ParamDefinition';
98
		$this->typeToClass[$type] = $class;
99
100
		$defaults = [
101
			'string-parser' => 'ValueParsers\NullParser',
102
			'typed-parser' => 'ValueParsers\NullParser',
103
			'validator' => 'ValueValidators\NullValidator',
104
			'validation-callback' => null,
105
		];
106
107
		$this->typeToComponent[$type] = [];
108
109
		foreach ( $defaults as $component => $default ) {
110
			$this->typeToComponent[$type][$component] = array_key_exists( $component, $data ) ? $data[$component] : $default;
111
		}
112
113
		return true;
114
	}
115
116
	/**
117
	 * Creates a new instance of a IParamDefinition based on the provided type.
118
	 *
119
	 * @since 1.0
120
	 *
121
	 * @param string $type
122
	 * @param string $name
123
	 * @param mixed $default
124
	 * @param string $message
125
	 * @param boolean $isList
126
	 *
127
	 * @return IParamDefinition
128
	 * @throws OutOfBoundsException
129
	 */
130 36
	public function newDefinition( $type, $name, $default, $message, $isList = false ) {
131 36
		if ( !array_key_exists( $type, $this->typeToClass ) ) {
132
			throw new OutOfBoundsException( 'Unknown parameter type "' . $type . '".' );
133
		}
134
135 36
		$class = $this->typeToClass[$type];
136
137
		/**
138
		 * @var IParamDefinition $definition
139
		 */
140 36
		$definition = new $class(
141
			$type,
142
			$name,
143
			$default,
144
			$message,
145
			$isList
146
		);
147
148 36
		$validator = $this->typeToComponent[$type]['validator'];
149
150 36
		if ( $validator !== '\ValueValidators\NullValidator' ) {
151 36
			$definition->setValueValidator( new $validator() );
152
		}
153
154 36
		$validationCallback = $this->typeToComponent[$type]['validation-callback'];
155
156 36
		if ( $validationCallback !== null ) {
157 36
			$definition->setValidationCallback( $validationCallback );
158
		}
159
160 36
		return $definition;
161
	}
162
163
	/**
164
	 * Returns the specified component for the provided parameter type.
165
	 * This method is likely to change in the future in a compat breaking way.
166
	 *
167
	 * @since 1.0
168
	 *
169
	 * @param string $paramType
170
	 * @param string $componentType
171
	 *
172
	 * @throws Exception
173
	 * @return mixed
174
	 */
175 64
	public function getComponentForType( $paramType, $componentType ) {
176 64
		if ( !array_key_exists( $paramType, $this->typeToComponent ) ) {
177
			throw new Exception( 'Unknown parameter type "' . $paramType . '".' );
178
		}
179
180 64
		if ( !array_key_exists( $componentType, $this->typeToComponent[$paramType] ) ) {
181
			throw new Exception( 'Unknown parameter component type "' . $paramType . '".' );
182
		}
183
184 64
		return $this->typeToComponent[$paramType][$componentType];
185
	}
186
187
	/**
188
	 * Construct a new ParamDefinition from an array.
189
	 *
190
	 * @since 1.0
191
	 *
192
	 * @param array $param
193
	 * @param bool $getMad
194
	 *
195
	 * @return IParamDefinition|false
196
	 * @throws Exception
197
	 */
198 36
	public function newDefinitionFromArray( array $param, $getMad = true ) {
199 36
		foreach ( [ 'name', 'message' ] as $requiredElement ) {
200 36
			if ( !array_key_exists( $requiredElement, $param ) ) {
201
				if ( $getMad ) {
202
					throw new Exception( 'Could not construct a ParamDefinition from an array without ' . $requiredElement . ' element' );
203
				}
204
205
				return false;
206
			}
207
		}
208
209 36
		$parameter = $this->newDefinition(
210 36
			array_key_exists( 'type', $param ) ? $param['type'] : 'string',
211 36
			$param['name'],
212 36
			array_key_exists( 'default', $param ) ? $param['default'] : null,
213 36
			$param['message'],
214 36
			array_key_exists( 'islist', $param ) ? $param['islist'] : false
215
		);
216
217 36
		$parameter->setArrayValues( $param );
218
219 36
		return $parameter;
220
	}
221
222
}
223