1 | <?php |
||
47 | class RawTqContext extends RawPageContext implements TqContextInterface |
||
48 | { |
||
49 | use JavaScript; |
||
50 | use Debugger; |
||
51 | use Tags; |
||
52 | |||
53 | /** |
||
54 | * Parameters of TqExtension. |
||
55 | * |
||
56 | * @var array |
||
57 | */ |
||
58 | private $parameters = []; |
||
59 | /** |
||
60 | * @var string |
||
61 | */ |
||
62 | protected static $pageUrl = ''; |
||
63 | |||
64 | /** |
||
65 | * @param string $method |
||
66 | * @param array $arguments |
||
67 | * |
||
68 | * @throws \Exception |
||
69 | * @throws ContextNotFoundException |
||
70 | * When context class cannot be loaded. |
||
71 | * |
||
72 | * @return SnippetAcceptingContext |
||
73 | */ |
||
74 | public function __call($method, array $arguments) |
||
75 | { |
||
76 | $environment = $this->getEnvironment(); |
||
77 | // @example |
||
78 | // The "getFormContext" method is not declared and his name will be split by capital |
||
79 | // letters, creating an array with three items: "get", "Form" and "Context". |
||
80 | list(, $base, $context) = preg_split('/(?=[A-Z])/', $method); |
||
81 | |||
82 | $namespace = [$this->getTqParameter('namespace'), 'Context']; |
||
83 | |||
84 | // Provide a possibility to use "getTqContext()" method. Otherwise class will be looked |
||
85 | // up into "\Drupal\TqExtension\Context\Tq\TqContext" namespace which does not exists. |
||
86 | if ('Tq' !== $base) { |
||
87 | $namespace[] = $base; |
||
88 | } |
||
89 | |||
90 | foreach ([$namespace, ['Drupal', 'DrupalExtension', 'Context']] as $class) { |
||
91 | $class[] = "$base$context"; |
||
92 | $class = implode('\\', $class); |
||
93 | |||
94 | if ($environment->hasContextClass($class)) { |
||
95 | return $environment->getContext($class); |
||
96 | } |
||
97 | } |
||
98 | |||
99 | throw new \Exception(sprintf('Method "%s" does not exist', $method)); |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * Get selector by name. |
||
104 | * |
||
105 | * @param string $name |
||
106 | * Selector name from the configuration file. |
||
107 | * |
||
108 | * @return string |
||
109 | * CSS selector. |
||
110 | * |
||
111 | * @throws \Exception |
||
112 | * If selector does not exits. |
||
113 | */ |
||
114 | public function getDrupalSelector($name) |
||
115 | { |
||
116 | $selectors = $this->getDrupalParameter('selectors'); |
||
117 | |||
118 | if (!isset($selectors[$name])) { |
||
119 | throw new \Exception(sprintf('No such selector configured: %s', $name)); |
||
120 | } |
||
121 | |||
122 | return $selectors[$name]; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * {@inheritdoc} |
||
127 | */ |
||
128 | public function getDrupalText($name) |
||
129 | { |
||
130 | // Make text selectors translatable. |
||
131 | return DrupalKernelPlaceholder::t(parent::getDrupalText($name)); |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * @param string $site |
||
136 | * Drupal site folder. |
||
137 | * |
||
138 | * @return string |
||
139 | * URL to files directory. |
||
140 | */ |
||
141 | public function getFilesUrl($site = 'default') |
||
142 | { |
||
143 | return $this->locatePath("sites/$site/files"); |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * @return Environment|InitializedContextEnvironment |
||
148 | */ |
||
149 | public function getEnvironment() |
||
153 | |||
154 | /** |
||
155 | * @return SessionDriverInterface|Selenium2Driver|GoutteDriver |
||
156 | */ |
||
157 | public function getSessionDriver() |
||
161 | |||
162 | /** |
||
163 | * @return Session |
||
164 | */ |
||
165 | public function getWebDriverSession() |
||
169 | |||
170 | /** |
||
171 | * @todo Remove this when DrupalExtension will be used Mink >=1.6 and use $this->getSession->getWindowNames(); |
||
172 | * |
||
173 | * @return string[] |
||
174 | */ |
||
175 | public function getWindowNames() |
||
179 | |||
180 | /** |
||
181 | * @param NodeElement $element |
||
182 | * @param string $script |
||
183 | * |
||
184 | * @example |
||
185 | * $this->executeJsOnElement($this->element('*', 'Meta tags'), 'return jQuery({{ELEMENT}}).text();'); |
||
186 | * $this->executeJsOnElement($this->element('*', '#menu'), '{{ELEMENT}}.focus();'); |
||
187 | * |
||
188 | * @throws \Exception |
||
189 | * |
||
190 | * @return mixed |
||
191 | */ |
||
192 | public function executeJsOnElement(NodeElement $element, $script) |
||
205 | |||
206 | /** |
||
207 | * @param string $javascript |
||
208 | * JS code for execution. |
||
209 | * @param array $args |
||
210 | * Placeholder declarations. |
||
211 | * |
||
212 | * @return mixed |
||
213 | */ |
||
214 | public function executeJs($javascript, array $args = []) |
||
222 | |||
223 | /** |
||
224 | * Check JS events in step definition. |
||
225 | * |
||
226 | * @param StepScope $event |
||
227 | * |
||
228 | * @return int |
||
229 | */ |
||
230 | public static function isStepImpliesJsEvent(StepScope $event) |
||
234 | |||
235 | /** |
||
236 | * @return DrupalDriverInterface|DrushDriver |
||
237 | */ |
||
238 | public function getDrushDriver() |
||
242 | |||
243 | /** |
||
244 | * Wait for all AJAX requests and jQuery animations. |
||
245 | */ |
||
246 | public function waitAjaxAndAnimations() |
||
254 | |||
255 | /** |
||
256 | * {@inheritdoc} |
||
257 | */ |
||
258 | public function setTqParameters(array $parameters) |
||
264 | |||
265 | /** |
||
266 | * {@inheritdoc} |
||
267 | */ |
||
268 | public function getTqParameter($name) |
||
272 | |||
273 | /** |
||
274 | * {@inheritdoc} |
||
275 | */ |
||
276 | public function locatePath($path = '') |
||
280 | |||
281 | /** |
||
282 | * @return string |
||
283 | * Absolute URL. |
||
284 | */ |
||
285 | public function getCurrentUrl() |
||
289 | } |
||
290 |
Let’s take a look at an example:
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
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: