1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeaunamespace Facebook\WebDriver\Remote; 4*04fd306cSNickeau 5*04fd306cSNickeauuse Exception; 6*04fd306cSNickeauuse Facebook\WebDriver\Chrome\ChromeOptions; 7*04fd306cSNickeauuse Facebook\WebDriver\Firefox\FirefoxDriver; 8*04fd306cSNickeauuse Facebook\WebDriver\Firefox\FirefoxOptions; 9*04fd306cSNickeauuse Facebook\WebDriver\Firefox\FirefoxProfile; 10*04fd306cSNickeauuse Facebook\WebDriver\WebDriverCapabilities; 11*04fd306cSNickeauuse Facebook\WebDriver\WebDriverPlatform; 12*04fd306cSNickeau 13*04fd306cSNickeauclass DesiredCapabilities implements WebDriverCapabilities 14*04fd306cSNickeau{ 15*04fd306cSNickeau /** @var array */ 16*04fd306cSNickeau private $capabilities; 17*04fd306cSNickeau 18*04fd306cSNickeau /** @var array */ 19*04fd306cSNickeau private static $ossToW3c = [ 20*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => 'platformName', 21*04fd306cSNickeau WebDriverCapabilityType::VERSION => 'browserVersion', 22*04fd306cSNickeau WebDriverCapabilityType::ACCEPT_SSL_CERTS => 'acceptInsecureCerts', 23*04fd306cSNickeau ChromeOptions::CAPABILITY => ChromeOptions::CAPABILITY_W3C, 24*04fd306cSNickeau ]; 25*04fd306cSNickeau 26*04fd306cSNickeau public function __construct(array $capabilities = []) 27*04fd306cSNickeau { 28*04fd306cSNickeau $this->capabilities = $capabilities; 29*04fd306cSNickeau } 30*04fd306cSNickeau 31*04fd306cSNickeau public static function createFromW3cCapabilities(array $capabilities = []) 32*04fd306cSNickeau { 33*04fd306cSNickeau $w3cToOss = array_flip(self::$ossToW3c); 34*04fd306cSNickeau 35*04fd306cSNickeau foreach ($w3cToOss as $w3cCapability => $ossCapability) { 36*04fd306cSNickeau // Copy W3C capabilities to OSS ones 37*04fd306cSNickeau if (array_key_exists($w3cCapability, $capabilities)) { 38*04fd306cSNickeau $capabilities[$ossCapability] = $capabilities[$w3cCapability]; 39*04fd306cSNickeau } 40*04fd306cSNickeau } 41*04fd306cSNickeau 42*04fd306cSNickeau return new self($capabilities); 43*04fd306cSNickeau } 44*04fd306cSNickeau 45*04fd306cSNickeau /** 46*04fd306cSNickeau * @return string The name of the browser. 47*04fd306cSNickeau */ 48*04fd306cSNickeau public function getBrowserName() 49*04fd306cSNickeau { 50*04fd306cSNickeau return $this->get(WebDriverCapabilityType::BROWSER_NAME, ''); 51*04fd306cSNickeau } 52*04fd306cSNickeau 53*04fd306cSNickeau /** 54*04fd306cSNickeau * @param string $browser_name 55*04fd306cSNickeau * @return DesiredCapabilities 56*04fd306cSNickeau */ 57*04fd306cSNickeau public function setBrowserName($browser_name) 58*04fd306cSNickeau { 59*04fd306cSNickeau $this->set(WebDriverCapabilityType::BROWSER_NAME, $browser_name); 60*04fd306cSNickeau 61*04fd306cSNickeau return $this; 62*04fd306cSNickeau } 63*04fd306cSNickeau 64*04fd306cSNickeau /** 65*04fd306cSNickeau * @return string The version of the browser. 66*04fd306cSNickeau */ 67*04fd306cSNickeau public function getVersion() 68*04fd306cSNickeau { 69*04fd306cSNickeau return $this->get(WebDriverCapabilityType::VERSION, ''); 70*04fd306cSNickeau } 71*04fd306cSNickeau 72*04fd306cSNickeau /** 73*04fd306cSNickeau * @param string $version 74*04fd306cSNickeau * @return DesiredCapabilities 75*04fd306cSNickeau */ 76*04fd306cSNickeau public function setVersion($version) 77*04fd306cSNickeau { 78*04fd306cSNickeau $this->set(WebDriverCapabilityType::VERSION, $version); 79*04fd306cSNickeau 80*04fd306cSNickeau return $this; 81*04fd306cSNickeau } 82*04fd306cSNickeau 83*04fd306cSNickeau /** 84*04fd306cSNickeau * @param string $name 85*04fd306cSNickeau * @return mixed The value of a capability. 86*04fd306cSNickeau */ 87*04fd306cSNickeau public function getCapability($name) 88*04fd306cSNickeau { 89*04fd306cSNickeau return $this->get($name); 90*04fd306cSNickeau } 91*04fd306cSNickeau 92*04fd306cSNickeau /** 93*04fd306cSNickeau * @param string $name 94*04fd306cSNickeau * @param mixed $value 95*04fd306cSNickeau * @return DesiredCapabilities 96*04fd306cSNickeau */ 97*04fd306cSNickeau public function setCapability($name, $value) 98*04fd306cSNickeau { 99*04fd306cSNickeau // When setting 'moz:firefoxOptions' from an array and not from instance of FirefoxOptions, we must merge 100*04fd306cSNickeau // it with default FirefoxOptions to keep previous behavior (where the default preferences were added 101*04fd306cSNickeau // using FirefoxProfile, thus not overwritten by adding 'moz:firefoxOptions') 102*04fd306cSNickeau // TODO: remove in next major version, once FirefoxOptions are only accepted as object instance and not as array 103*04fd306cSNickeau if ($name === FirefoxOptions::CAPABILITY && is_array($value)) { 104*04fd306cSNickeau $defaultOptions = (new FirefoxOptions())->toArray(); 105*04fd306cSNickeau $value = array_merge($defaultOptions, $value); 106*04fd306cSNickeau } 107*04fd306cSNickeau 108*04fd306cSNickeau $this->set($name, $value); 109*04fd306cSNickeau 110*04fd306cSNickeau return $this; 111*04fd306cSNickeau } 112*04fd306cSNickeau 113*04fd306cSNickeau /** 114*04fd306cSNickeau * @return string The name of the platform. 115*04fd306cSNickeau */ 116*04fd306cSNickeau public function getPlatform() 117*04fd306cSNickeau { 118*04fd306cSNickeau return $this->get(WebDriverCapabilityType::PLATFORM, ''); 119*04fd306cSNickeau } 120*04fd306cSNickeau 121*04fd306cSNickeau /** 122*04fd306cSNickeau * @param string $platform 123*04fd306cSNickeau * @return DesiredCapabilities 124*04fd306cSNickeau */ 125*04fd306cSNickeau public function setPlatform($platform) 126*04fd306cSNickeau { 127*04fd306cSNickeau $this->set(WebDriverCapabilityType::PLATFORM, $platform); 128*04fd306cSNickeau 129*04fd306cSNickeau return $this; 130*04fd306cSNickeau } 131*04fd306cSNickeau 132*04fd306cSNickeau /** 133*04fd306cSNickeau * @param string $capability_name 134*04fd306cSNickeau * @return bool Whether the value is not null and not false. 135*04fd306cSNickeau */ 136*04fd306cSNickeau public function is($capability_name) 137*04fd306cSNickeau { 138*04fd306cSNickeau return (bool) $this->get($capability_name); 139*04fd306cSNickeau } 140*04fd306cSNickeau 141*04fd306cSNickeau /** 142*04fd306cSNickeau * @todo Remove in next major release (BC) 143*04fd306cSNickeau * @deprecated All browsers are always JS enabled except HtmlUnit and it's not meaningful to disable JS execution. 144*04fd306cSNickeau * @return bool Whether javascript is enabled. 145*04fd306cSNickeau */ 146*04fd306cSNickeau public function isJavascriptEnabled() 147*04fd306cSNickeau { 148*04fd306cSNickeau return $this->get(WebDriverCapabilityType::JAVASCRIPT_ENABLED, false); 149*04fd306cSNickeau } 150*04fd306cSNickeau 151*04fd306cSNickeau /** 152*04fd306cSNickeau * This is a htmlUnit-only option. 153*04fd306cSNickeau * 154*04fd306cSNickeau * @param bool $enabled 155*04fd306cSNickeau * @throws Exception 156*04fd306cSNickeau * @return DesiredCapabilities 157*04fd306cSNickeau * @see https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities 158*04fd306cSNickeau */ 159*04fd306cSNickeau public function setJavascriptEnabled($enabled) 160*04fd306cSNickeau { 161*04fd306cSNickeau $browser = $this->getBrowserName(); 162*04fd306cSNickeau if ($browser && $browser !== WebDriverBrowserType::HTMLUNIT) { 163*04fd306cSNickeau throw new Exception( 164*04fd306cSNickeau 'isJavascriptEnabled() is a htmlunit-only option. ' . 165*04fd306cSNickeau 'See https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities#read-write-capabilities.' 166*04fd306cSNickeau ); 167*04fd306cSNickeau } 168*04fd306cSNickeau 169*04fd306cSNickeau $this->set(WebDriverCapabilityType::JAVASCRIPT_ENABLED, $enabled); 170*04fd306cSNickeau 171*04fd306cSNickeau return $this; 172*04fd306cSNickeau } 173*04fd306cSNickeau 174*04fd306cSNickeau /** 175*04fd306cSNickeau * @todo Remove side-effects - not change eg. ChromeOptions::CAPABILITY from instance of ChromeOptions to an array 176*04fd306cSNickeau * @return array 177*04fd306cSNickeau */ 178*04fd306cSNickeau public function toArray() 179*04fd306cSNickeau { 180*04fd306cSNickeau if (isset($this->capabilities[ChromeOptions::CAPABILITY]) && 181*04fd306cSNickeau $this->capabilities[ChromeOptions::CAPABILITY] instanceof ChromeOptions 182*04fd306cSNickeau ) { 183*04fd306cSNickeau $this->capabilities[ChromeOptions::CAPABILITY] = 184*04fd306cSNickeau $this->capabilities[ChromeOptions::CAPABILITY]->toArray(); 185*04fd306cSNickeau } 186*04fd306cSNickeau 187*04fd306cSNickeau if (isset($this->capabilities[FirefoxOptions::CAPABILITY]) && 188*04fd306cSNickeau $this->capabilities[FirefoxOptions::CAPABILITY] instanceof FirefoxOptions 189*04fd306cSNickeau ) { 190*04fd306cSNickeau $this->capabilities[FirefoxOptions::CAPABILITY] = 191*04fd306cSNickeau $this->capabilities[FirefoxOptions::CAPABILITY]->toArray(); 192*04fd306cSNickeau } 193*04fd306cSNickeau 194*04fd306cSNickeau if (isset($this->capabilities[FirefoxDriver::PROFILE]) && 195*04fd306cSNickeau $this->capabilities[FirefoxDriver::PROFILE] instanceof FirefoxProfile 196*04fd306cSNickeau ) { 197*04fd306cSNickeau $this->capabilities[FirefoxDriver::PROFILE] = 198*04fd306cSNickeau $this->capabilities[FirefoxDriver::PROFILE]->encode(); 199*04fd306cSNickeau } 200*04fd306cSNickeau 201*04fd306cSNickeau return $this->capabilities; 202*04fd306cSNickeau } 203*04fd306cSNickeau 204*04fd306cSNickeau /** 205*04fd306cSNickeau * @return array 206*04fd306cSNickeau */ 207*04fd306cSNickeau public function toW3cCompatibleArray() 208*04fd306cSNickeau { 209*04fd306cSNickeau $allowedW3cCapabilities = [ 210*04fd306cSNickeau 'browserName', 211*04fd306cSNickeau 'browserVersion', 212*04fd306cSNickeau 'platformName', 213*04fd306cSNickeau 'acceptInsecureCerts', 214*04fd306cSNickeau 'pageLoadStrategy', 215*04fd306cSNickeau 'proxy', 216*04fd306cSNickeau 'setWindowRect', 217*04fd306cSNickeau 'timeouts', 218*04fd306cSNickeau 'strictFileInteractability', 219*04fd306cSNickeau 'unhandledPromptBehavior', 220*04fd306cSNickeau ]; 221*04fd306cSNickeau 222*04fd306cSNickeau $ossCapabilities = $this->toArray(); 223*04fd306cSNickeau $w3cCapabilities = []; 224*04fd306cSNickeau 225*04fd306cSNickeau foreach ($ossCapabilities as $capabilityKey => $capabilityValue) { 226*04fd306cSNickeau // Copy already W3C compatible capabilities 227*04fd306cSNickeau if (in_array($capabilityKey, $allowedW3cCapabilities, true)) { 228*04fd306cSNickeau $w3cCapabilities[$capabilityKey] = $capabilityValue; 229*04fd306cSNickeau } 230*04fd306cSNickeau 231*04fd306cSNickeau // Convert capabilities with changed name 232*04fd306cSNickeau if (array_key_exists($capabilityKey, self::$ossToW3c)) { 233*04fd306cSNickeau if ($capabilityKey === WebDriverCapabilityType::PLATFORM) { 234*04fd306cSNickeau $w3cCapabilities[self::$ossToW3c[$capabilityKey]] = mb_strtolower($capabilityValue); 235*04fd306cSNickeau 236*04fd306cSNickeau // Remove platformName if it is set to "any" 237*04fd306cSNickeau if ($w3cCapabilities[self::$ossToW3c[$capabilityKey]] === 'any') { 238*04fd306cSNickeau unset($w3cCapabilities[self::$ossToW3c[$capabilityKey]]); 239*04fd306cSNickeau } 240*04fd306cSNickeau } else { 241*04fd306cSNickeau $w3cCapabilities[self::$ossToW3c[$capabilityKey]] = $capabilityValue; 242*04fd306cSNickeau } 243*04fd306cSNickeau } 244*04fd306cSNickeau 245*04fd306cSNickeau // Copy vendor extensions 246*04fd306cSNickeau if (mb_strpos($capabilityKey, ':') !== false) { 247*04fd306cSNickeau $w3cCapabilities[$capabilityKey] = $capabilityValue; 248*04fd306cSNickeau } 249*04fd306cSNickeau } 250*04fd306cSNickeau 251*04fd306cSNickeau // Convert ChromeOptions 252*04fd306cSNickeau if (array_key_exists(ChromeOptions::CAPABILITY, $ossCapabilities)) { 253*04fd306cSNickeau if (array_key_exists(ChromeOptions::CAPABILITY_W3C, $ossCapabilities)) { 254*04fd306cSNickeau $w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = new \ArrayObject( 255*04fd306cSNickeau array_merge_recursive( 256*04fd306cSNickeau (array) $ossCapabilities[ChromeOptions::CAPABILITY], 257*04fd306cSNickeau (array) $ossCapabilities[ChromeOptions::CAPABILITY_W3C] 258*04fd306cSNickeau ) 259*04fd306cSNickeau ); 260*04fd306cSNickeau } else { 261*04fd306cSNickeau $w3cCapabilities[ChromeOptions::CAPABILITY_W3C] = $ossCapabilities[ChromeOptions::CAPABILITY]; 262*04fd306cSNickeau } 263*04fd306cSNickeau } 264*04fd306cSNickeau 265*04fd306cSNickeau // Convert Firefox profile 266*04fd306cSNickeau if (array_key_exists(FirefoxDriver::PROFILE, $ossCapabilities)) { 267*04fd306cSNickeau // Convert profile only if not already set in moz:firefoxOptions 268*04fd306cSNickeau if (!array_key_exists(FirefoxOptions::CAPABILITY, $ossCapabilities) 269*04fd306cSNickeau || !array_key_exists('profile', $ossCapabilities[FirefoxOptions::CAPABILITY])) { 270*04fd306cSNickeau $w3cCapabilities[FirefoxOptions::CAPABILITY]['profile'] = $ossCapabilities[FirefoxDriver::PROFILE]; 271*04fd306cSNickeau } 272*04fd306cSNickeau } 273*04fd306cSNickeau 274*04fd306cSNickeau return $w3cCapabilities; 275*04fd306cSNickeau } 276*04fd306cSNickeau 277*04fd306cSNickeau /** 278*04fd306cSNickeau * @return static 279*04fd306cSNickeau */ 280*04fd306cSNickeau public static function android() 281*04fd306cSNickeau { 282*04fd306cSNickeau return new static([ 283*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::ANDROID, 284*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANDROID, 285*04fd306cSNickeau ]); 286*04fd306cSNickeau } 287*04fd306cSNickeau 288*04fd306cSNickeau /** 289*04fd306cSNickeau * @return static 290*04fd306cSNickeau */ 291*04fd306cSNickeau public static function chrome() 292*04fd306cSNickeau { 293*04fd306cSNickeau return new static([ 294*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::CHROME, 295*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, 296*04fd306cSNickeau ]); 297*04fd306cSNickeau } 298*04fd306cSNickeau 299*04fd306cSNickeau /** 300*04fd306cSNickeau * @return static 301*04fd306cSNickeau */ 302*04fd306cSNickeau public static function firefox() 303*04fd306cSNickeau { 304*04fd306cSNickeau $caps = new static([ 305*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::FIREFOX, 306*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, 307*04fd306cSNickeau ]); 308*04fd306cSNickeau 309*04fd306cSNickeau $caps->setCapability(FirefoxOptions::CAPABILITY, new FirefoxOptions()); // to add default options 310*04fd306cSNickeau 311*04fd306cSNickeau return $caps; 312*04fd306cSNickeau } 313*04fd306cSNickeau 314*04fd306cSNickeau /** 315*04fd306cSNickeau * @return static 316*04fd306cSNickeau */ 317*04fd306cSNickeau public static function htmlUnit() 318*04fd306cSNickeau { 319*04fd306cSNickeau return new static([ 320*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, 321*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, 322*04fd306cSNickeau ]); 323*04fd306cSNickeau } 324*04fd306cSNickeau 325*04fd306cSNickeau /** 326*04fd306cSNickeau * @return static 327*04fd306cSNickeau */ 328*04fd306cSNickeau public static function htmlUnitWithJS() 329*04fd306cSNickeau { 330*04fd306cSNickeau $caps = new static([ 331*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::HTMLUNIT, 332*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, 333*04fd306cSNickeau ]); 334*04fd306cSNickeau 335*04fd306cSNickeau return $caps->setJavascriptEnabled(true); 336*04fd306cSNickeau } 337*04fd306cSNickeau 338*04fd306cSNickeau /** 339*04fd306cSNickeau * @return static 340*04fd306cSNickeau */ 341*04fd306cSNickeau public static function internetExplorer() 342*04fd306cSNickeau { 343*04fd306cSNickeau return new static([ 344*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IE, 345*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, 346*04fd306cSNickeau ]); 347*04fd306cSNickeau } 348*04fd306cSNickeau 349*04fd306cSNickeau /** 350*04fd306cSNickeau * @return static 351*04fd306cSNickeau */ 352*04fd306cSNickeau public static function microsoftEdge() 353*04fd306cSNickeau { 354*04fd306cSNickeau return new static([ 355*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::MICROSOFT_EDGE, 356*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::WINDOWS, 357*04fd306cSNickeau ]); 358*04fd306cSNickeau } 359*04fd306cSNickeau 360*04fd306cSNickeau /** 361*04fd306cSNickeau * @return static 362*04fd306cSNickeau */ 363*04fd306cSNickeau public static function iphone() 364*04fd306cSNickeau { 365*04fd306cSNickeau return new static([ 366*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPHONE, 367*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, 368*04fd306cSNickeau ]); 369*04fd306cSNickeau } 370*04fd306cSNickeau 371*04fd306cSNickeau /** 372*04fd306cSNickeau * @return static 373*04fd306cSNickeau */ 374*04fd306cSNickeau public static function ipad() 375*04fd306cSNickeau { 376*04fd306cSNickeau return new static([ 377*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::IPAD, 378*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::MAC, 379*04fd306cSNickeau ]); 380*04fd306cSNickeau } 381*04fd306cSNickeau 382*04fd306cSNickeau /** 383*04fd306cSNickeau * @return static 384*04fd306cSNickeau */ 385*04fd306cSNickeau public static function opera() 386*04fd306cSNickeau { 387*04fd306cSNickeau return new static([ 388*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::OPERA, 389*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, 390*04fd306cSNickeau ]); 391*04fd306cSNickeau } 392*04fd306cSNickeau 393*04fd306cSNickeau /** 394*04fd306cSNickeau * @return static 395*04fd306cSNickeau */ 396*04fd306cSNickeau public static function safari() 397*04fd306cSNickeau { 398*04fd306cSNickeau return new static([ 399*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::SAFARI, 400*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, 401*04fd306cSNickeau ]); 402*04fd306cSNickeau } 403*04fd306cSNickeau 404*04fd306cSNickeau /** 405*04fd306cSNickeau * @deprecated PhantomJS is no longer developed and its support will be removed in next major version. 406*04fd306cSNickeau * Use headless Chrome or Firefox instead. 407*04fd306cSNickeau * @return static 408*04fd306cSNickeau */ 409*04fd306cSNickeau public static function phantomjs() 410*04fd306cSNickeau { 411*04fd306cSNickeau return new static([ 412*04fd306cSNickeau WebDriverCapabilityType::BROWSER_NAME => WebDriverBrowserType::PHANTOMJS, 413*04fd306cSNickeau WebDriverCapabilityType::PLATFORM => WebDriverPlatform::ANY, 414*04fd306cSNickeau ]); 415*04fd306cSNickeau } 416*04fd306cSNickeau 417*04fd306cSNickeau /** 418*04fd306cSNickeau * @param string $key 419*04fd306cSNickeau * @param mixed $value 420*04fd306cSNickeau * @return DesiredCapabilities 421*04fd306cSNickeau */ 422*04fd306cSNickeau private function set($key, $value) 423*04fd306cSNickeau { 424*04fd306cSNickeau $this->capabilities[$key] = $value; 425*04fd306cSNickeau 426*04fd306cSNickeau return $this; 427*04fd306cSNickeau } 428*04fd306cSNickeau 429*04fd306cSNickeau /** 430*04fd306cSNickeau * @param string $key 431*04fd306cSNickeau * @param mixed $default 432*04fd306cSNickeau * @return mixed 433*04fd306cSNickeau */ 434*04fd306cSNickeau private function get($key, $default = null) 435*04fd306cSNickeau { 436*04fd306cSNickeau return isset($this->capabilities[$key]) 437*04fd306cSNickeau ? $this->capabilities[$key] 438*04fd306cSNickeau : $default; 439*04fd306cSNickeau } 440*04fd306cSNickeau} 441