1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Kolyunya\Codeception\Module; |
4
|
|
|
|
5
|
|
|
use Exception; |
6
|
|
|
use ReflectionClass; |
7
|
|
|
use Codeception\Lib\ModuleContainer; |
8
|
|
|
use Codeception\Module; |
9
|
|
|
use Kolyunya\Codeception\Lib\Base\ComponentInterface; |
10
|
|
|
use Kolyunya\Codeception\Lib\MarkupValidator\MarkupProviderInterface; |
11
|
|
|
use Kolyunya\Codeception\Lib\MarkupValidator\MarkupReporterInterface; |
12
|
|
|
use Kolyunya\Codeception\Lib\MarkupValidator\MarkupValidatorInterface; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* A module which validates page markup via a markup validator. |
16
|
|
|
*/ |
17
|
|
|
class MarkupValidator extends Module |
18
|
|
|
{ |
19
|
|
|
|
20
|
|
|
const COMPONENT_CLASS_CONFIG_KEY = 'class'; |
21
|
|
|
|
22
|
|
|
const COMPONENT_CONFIG_CONFIG_KEY = 'config'; |
23
|
|
|
|
24
|
|
|
const PROVIDER_INTERFACE = 'Kolyunya\Codeception\Lib\MarkupValidator\MarkupProviderInterface'; |
25
|
|
|
const PROVIDER_CONFIG_KEY = 'provider'; |
26
|
|
|
|
27
|
|
|
const VALIDATOR_INTERFACE = 'Kolyunya\Codeception\Lib\MarkupValidator\MarkupValidatorInterface'; |
28
|
|
|
const VALIDATOR_CONFIG_KEY = 'validator'; |
29
|
|
|
|
30
|
|
|
const REPORTER_INTERFACE = 'Kolyunya\Codeception\Lib\MarkupValidator\MarkupReporterInterface'; |
31
|
|
|
const REPORTER_CONFIG_KEY = 'reporter'; |
32
|
|
|
|
33
|
|
|
const PRINTER_INTERFACE = 'Kolyunya\Codeception\Lib\MarkupValidator\MessagePrinterInterface'; |
34
|
|
|
const PRINTER_CONFIG_KEY = 'printer'; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* {@inheritDoc} |
38
|
|
|
*/ |
39
|
|
|
protected $config = array( |
40
|
|
|
self::PROVIDER_CONFIG_KEY => array( |
41
|
|
|
self::COMPONENT_CLASS_CONFIG_KEY => 'Kolyunya\Codeception\Lib\MarkupValidator\DefaultMarkupProvider', |
42
|
|
|
), |
43
|
|
|
self::VALIDATOR_CONFIG_KEY => array( |
44
|
|
|
self::COMPONENT_CLASS_CONFIG_KEY => 'Kolyunya\Codeception\Lib\MarkupValidator\W3CMarkupValidator', |
45
|
|
|
), |
46
|
|
|
self::REPORTER_CONFIG_KEY => array( |
47
|
|
|
self::COMPONENT_CLASS_CONFIG_KEY => 'Kolyunya\Codeception\Lib\MarkupValidator\DefaultMarkupReporter', |
48
|
|
|
), |
49
|
|
|
); |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Markup provider. |
53
|
|
|
* |
54
|
|
|
* @var MarkupProviderInterface |
55
|
|
|
*/ |
56
|
|
|
private $provider; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Markup validator. |
60
|
|
|
* |
61
|
|
|
* @var MarkupValidatorInterface |
62
|
|
|
*/ |
63
|
|
|
private $validator; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Markup validation message reporter. |
67
|
|
|
* |
68
|
|
|
* @var MarkupReporterInterface |
69
|
|
|
*/ |
70
|
|
|
private $reporter; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* {@inheritDoc} |
74
|
|
|
*/ |
75
|
|
|
public function __construct(ModuleContainer $moduleContainer, $config = null) |
76
|
|
|
{ |
77
|
|
|
parent::__construct($moduleContainer, $config); |
78
|
|
|
|
79
|
|
|
$this->initializeProvider(); |
80
|
|
|
$this->initializeValidator(); |
81
|
|
|
$this->initializeReporter(); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Validates page markup via a markup validator. |
86
|
|
|
* Allows to recongigure reporter component. |
87
|
|
|
* |
88
|
|
|
* @param array $reporterConfiguration Reporter configuration. |
89
|
|
|
*/ |
90
|
|
|
public function validateMarkup(array $reporterConfiguration = array()) |
91
|
|
|
{ |
92
|
|
|
$markup = $this->provider->getMarkup(); |
93
|
|
|
$messages = $this->validator->validate($markup); |
94
|
|
|
|
95
|
|
|
$this->reporter->setConfiguration($reporterConfiguration); |
96
|
|
|
$this->reporter->report($messages); |
97
|
|
|
|
98
|
|
|
// Validation succeeded. |
99
|
|
|
$this->assertTrue(true); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Initializes markup provider. |
104
|
|
|
*/ |
105
|
|
|
private function initializeProvider() |
106
|
|
|
{ |
107
|
|
|
$this->provider = $this->instantiateComponent( |
108
|
|
|
self::PROVIDER_CONFIG_KEY, |
109
|
|
|
self::PROVIDER_INTERFACE, |
110
|
|
|
array( |
111
|
|
|
$this->moduleContainer, |
112
|
|
|
) |
113
|
|
|
); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Initializes markup validator. |
118
|
|
|
*/ |
119
|
|
|
private function initializeValidator() |
120
|
|
|
{ |
121
|
|
|
$this->validator = $this->instantiateComponent( |
122
|
|
|
self::VALIDATOR_CONFIG_KEY, |
123
|
|
|
self::VALIDATOR_INTERFACE |
124
|
|
|
); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Initializes markup reporter. |
129
|
|
|
*/ |
130
|
|
|
private function initializeReporter() |
131
|
|
|
{ |
132
|
|
|
$this->reporter = $this->instantiateComponent( |
133
|
|
|
self::REPORTER_CONFIG_KEY, |
134
|
|
|
self::REPORTER_INTERFACE |
135
|
|
|
); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Instantiates and returns a module component. |
140
|
|
|
* |
141
|
|
|
* @param string $componentName Component name. |
142
|
|
|
* @param string $interface An interface component must implement. |
143
|
|
|
* @param array $arguments Component's constructor arguments. |
144
|
|
|
* |
145
|
|
|
* @throws Exception When component does not implement expected interface. |
146
|
|
|
* |
147
|
|
|
* @return object Instance of a module component. |
148
|
|
|
*/ |
149
|
|
|
private function instantiateComponent($componentName, $interface, array $arguments = array()) |
150
|
|
|
{ |
151
|
|
|
$componentClass = $this->getComponentClass($componentName); |
152
|
|
|
$componentReflectionClass = new ReflectionClass($componentClass); |
153
|
|
|
if ($componentReflectionClass->implementsInterface($interface) === false) { |
154
|
|
|
$errorMessageTemplate = 'Invalid class «%s» provided for component «%s». It must implement «%s».'; |
155
|
|
|
$errorMessage = sprintf($errorMessageTemplate, $componentClass, $componentName, $interface); |
156
|
|
|
throw new Exception($errorMessage); |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/* @var $component ComponentInterface */ |
160
|
|
|
$component = $componentReflectionClass->newInstanceArgs($arguments); |
161
|
|
|
$componentConfiguration = $this->getComponentConfiguration($componentName); |
162
|
|
|
$component->setConfiguration($componentConfiguration); |
163
|
|
|
|
164
|
|
|
return $component; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Returns component class name. |
169
|
|
|
* |
170
|
|
|
* @param string $componentName Component name. |
171
|
|
|
* |
172
|
|
|
* @return string Component class name. |
173
|
|
|
*/ |
174
|
|
View Code Duplication |
private function getComponentClass($componentName) |
|
|
|
|
175
|
|
|
{ |
176
|
|
|
$componentClassKey = self::COMPONENT_CLASS_CONFIG_KEY; |
177
|
|
|
if (isset($this->config[$componentName][$componentClassKey]) === false || |
178
|
|
|
is_string($this->config[$componentName][$componentClassKey]) === false |
179
|
|
|
) { |
180
|
|
|
$errorMessage = sprintf('Invalid class configuration of component «%s».', $componentName); |
181
|
|
|
throw new Exception($errorMessage); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
$componentClass = $this->config[$componentName][$componentClassKey]; |
185
|
|
|
|
186
|
|
|
return $componentClass; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Returns component configuration parameters. |
191
|
|
|
* |
192
|
|
|
* @param string $componentName Component name. |
193
|
|
|
* |
194
|
|
|
* @return array Component configuration parameters. |
195
|
|
|
*/ |
196
|
|
View Code Duplication |
private function getComponentConfiguration($componentName) |
|
|
|
|
197
|
|
|
{ |
198
|
|
|
$componentConfig = array(); |
199
|
|
|
|
200
|
|
|
$componentConfigKey = self::COMPONENT_CONFIG_CONFIG_KEY; |
201
|
|
|
if (isset($this->config[$componentName][$componentConfigKey]) === true) { |
202
|
|
|
if (is_array($this->config[$componentName][$componentConfigKey]) === true) { |
203
|
|
|
$componentConfig = $this->config[$componentName][$componentConfigKey]; |
204
|
|
|
} else { |
205
|
|
|
$errorMessage = sprintf('Invalid configuration of component «%s».', $componentName); |
206
|
|
|
throw new Exception($errorMessage); |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
return $componentConfig; |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.