1: <?php
2: namespace Azalea\Selenium\Toolkit;
3:
4: use Azalea\Selenium\Toolkit\NestedHashMap;
5: use Azalea\Selenium\Toolkit\Validation\WebDriverValidator;
6:
7: class View
8: {
9: public $el = "";
10:
11: protected $view = array();
12: protected $parent = null;
13: protected $dom = null;
14:
15: protected $cachedProperties = array();
16:
17: 18: 19: 20: 21:
22: public function __construct($driver, $config, $args = array())
23: {
24: if (!$driver) {
25: throw new \InvalidArgumentException("WebDriver is required.");
26: }
27: if (!$config) {
28: throw new \InvalidArgumentException("View config is required.");
29: }
30:
31: $this->driver = $driver;
32: $this->dom = new Dom($driver);
33: $this->args = $args;
34:
35: if (is_string($config)) {
36: $config = ResourceLoader::parse($config);
37: }
38: if (!is_array($config)) {
39: throw new \InvalidArgumentException("View config is required.");
40: }
41:
42: $this->parseViewConfig($config);
43:
44:
45: if (!isset($this->view['config'])) {
46: $this->view['config'] = array();
47: }
48: $this->config = new NestedHashMap($this->view['config']);
49: }
50:
51: 52: 53: 54: 55:
56: public function getName()
57: {
58: return $this->view['name'];
59: }
60:
61: 62: 63: 64: 65:
66: public function getParent()
67: {
68: return $this->parent;
69: }
70:
71: 72: 73: 74: 75:
76: public function getArgs()
77: {
78: return $this->args;
79: }
80:
81: 82: 83: 84: 85: 86:
87: public function setArgs($args)
88: {
89: $this->args = $args;
90: $this->el = $this->root = $this->replaceStringWithKeys($this->el, $args);
91:
92: $this->dom->setRoot($this->el);
93:
94: if ($this->parent) {
95: $this->parent->setArgs($args);
96: }
97: return $this;
98: }
99:
100: 101: 102: 103: 104:
105: public function getScope()
106: {
107: return $this->view['scope'];
108: }
109:
110: 111: 112: 113: 114: 115:
116: public function setScope($selector)
117: {
118: $this->el = $this->root = $this->replaceStringWithKeys($selector." ".$this->view['el'], $this->args);
119: $this->dom->setRoot($this->el);
120: }
121:
122: 123: 124: 125: 126: 127: 128:
129: public function clearCache()
130: {
131: $this->cachedProperties = array();
132: return $this;
133: }
134:
135: 136: 137:
138:
139: 140: 141: 142: 143:
144: public function getUrl()
145: {
146: return $this->view['url'];
147: }
148:
149: 150: 151: 152: 153: 154:
155: public function getHash($args = array())
156: {
157: return $this->replaceStringWithKeys($this->view['hash'], $args);
158: }
159:
160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171:
172: public function navigate()
173: {
174: if ($this->view['url']) {
175: $this->driver->url($this->view['url']);
176: return $this->verifyAndWait();
177: }
178: if (!empty($this->view['hash'])) {
179: $this->driver->updateHash(
180: $this->getHash($this->args)
181: );
182: }
183: return $this;
184: }
185:
186:
187: 188: 189:
190:
191: 192: 193: 194: 195:
196: public function isVisible()
197: {
198: if (!$this->driver->hasElement($css) || !$this->driver->querySelector($css)->displayed()) {
199: return false;
200: }
201: return true;
202: }
203:
204:
205: public function within($callback)
206: {
207: return $this->driver->within($this->el, $callback);
208: }
209:
210: 211: 212:
213:
214: 215: 216: 217: 218:
219: public function verify()
220: {
221:
222: if ($this->parent) {
223: if (!$this->parent->verify()) {
224: return false;
225: }
226: }
227:
228:
229: if (isset($this->view['title'])) {
230: if ($this->driver->title() != $this->view['title']) {
231: return false;
232: }
233: }
234:
235:
236: if ($this->el != "body" && !$this->driver->hasElement($this->el)) {
237: return false;
238: }
239:
240:
241: return WebDriverValidator::verify($this, $this->view['rules']);
242: }
243:
244: 245: 246: 247: 248: 249:
250: public function verifyAndWait($timeout = 30)
251: {
252: $this->driver->spinWait(array($this, "verify"), $timeout);
253: return $this;
254: }
255:
256: 257: 258:
259:
260: 261: 262: 263: 264: 265:
266: protected function parseViewConfig($config)
267: {
268: $this->view = $config;
269:
270: if (!isset($this->view['name'])) {
271: $this->view['name'] = "";
272: }
273:
274: if (!isset($this->view['el'])) {
275: $this->view['el'] = "body";
276: }
277: $this->el = $this->root = $this->replaceStringWithKeys($this->view['el'], $this->args);
278:
279:
280: $this->dom->setRoot($this->el);
281:
282: if (!isset($this->view['url'])) {
283: $this->view['url'] = null;
284: }
285:
286: if (!isset($this->view['hash'])) {
287: $this->view['hash'] = "";
288: }
289:
290: if (!isset($this->view['rules'])) {
291: $this->view['rules'] = array();
292: }
293:
294: if (isset($this->view['extends'])) {
295: $this->extend($this->view['extends']);
296: }
297:
298: if (!isset($this->view['scope'])) {
299: $this->view['scope'] = "auto";
300: }
301: }
302:
303: 304: 305:
306: protected function extend($extend)
307: {
308: $this->parent = $this->driver->getView($extend, $this->args);
309: }
310:
311: 312: 313: 314: 315: 316: 317:
318: private function replaceStringWithKeys($string = '', $args = array())
319: {
320: foreach ($args as $key => $val) {
321: if (strpos($string, "{" . $key . "}") !== false) {
322: $string = str_replace("{" . $key . "}", $val, $string);
323: }
324: }
325: return $string;
326: }
327:
328: 329: 330:
331:
332: 333: 334: 335: 336: 337:
338: public function __get($name)
339: {
340: if (isset($this->view[$name])) {
341: if (isset($this->cachedProperties[$name])) {
342: return $this->cachedProperties[$name];
343: }
344:
345: $value = $this->view[$name];
346:
347: if (is_string($value)) {
348: if (stripos($value, ".json") !== false) {
349:
350: $view = ResourceLoader::load($value, $this->driver, $this->args);
351:
352: if ($view->getScope() == "inherit") {
353: $view->setScope($this->el);
354: }
355: $this->cachedProperties[$name] = $view;
356: return $view;
357: } else {
358:
359: return $value;
360: }
361: }
362:
363: $view = ResourceLoader::create($value, $this->driver, $this->args);
364:
365: if ($view->getScope() == "inherit") {
366: $view->setScope($this->el);
367: }
368: $this->cachedProperties[$name] = $view;
369: return $view;
370: }
371:
372: return null;
373: }
374:
375: 376: 377: 378: 379: 380: 381:
382: public function __call($method, $args)
383: {
384: if ($this->dom) {
385: if (is_callable(array($this->dom, $method))) {
386: return call_user_func_array(array($this->dom, $method), $args);
387: }
388: }
389:
390: if (isset($this->view[$method])) {
391: $view = $this->__get($method);
392: $view->setArgs($args);
393: return $view;
394: }
395:
396: if ($this->driver) {
397: if (is_callable(array($this->driver, $method))) {
398: return call_user_func_array(array($this->driver, $method), $args);
399: }
400: }
401:
402: throw new \RuntimeException("Method ".$method." is not callable in View.");
403: }
404: }
405:
406: ?>