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