1<?php
2
3namespace Facebook\WebDriver\Chrome;
4
5use Facebook\WebDriver\Remote\DesiredCapabilities;
6use JsonSerializable;
7use ReturnTypeWillChange;
8
9/**
10 * The class manages the capabilities in ChromeDriver.
11 *
12 * @see https://sites.google.com/a/chromium.org/chromedriver/capabilities
13 */
14class ChromeOptions implements JsonSerializable
15{
16    /**
17     * The key of chromeOptions in desired capabilities (in legacy OSS JsonWire protocol)
18     * @todo Replace value with 'goog:chromeOptions' after JsonWire protocol support is removed
19     */
20    const CAPABILITY = 'chromeOptions';
21    /**
22     * The key of chromeOptions in desired capabilities (in W3C compatible protocol)
23     */
24    const CAPABILITY_W3C = 'goog:chromeOptions';
25    /**
26     * @var array
27     */
28    private $arguments = [];
29    /**
30     * @var string
31     */
32    private $binary = '';
33    /**
34     * @var array
35     */
36    private $extensions = [];
37    /**
38     * @var array
39     */
40    private $experimentalOptions = [];
41
42    /**
43     * Return a version of the class which can JSON serialized.
44     *
45     * @return array
46     */
47    #[ReturnTypeWillChange]
48    public function jsonSerialize()
49    {
50        return $this->toArray();
51    }
52
53    /**
54     * Sets the path of the Chrome executable. The path should be either absolute
55     * or relative to the location running ChromeDriver server.
56     *
57     * @param string $path
58     * @return ChromeOptions
59     */
60    public function setBinary($path)
61    {
62        $this->binary = $path;
63
64        return $this;
65    }
66
67    /**
68     * @param array $arguments
69     * @return ChromeOptions
70     */
71    public function addArguments(array $arguments)
72    {
73        $this->arguments = array_merge($this->arguments, $arguments);
74
75        return $this;
76    }
77
78    /**
79     * Add a Chrome extension to install on browser startup. Each path should be
80     * a packed Chrome extension.
81     *
82     * @param array $paths
83     * @return ChromeOptions
84     */
85    public function addExtensions(array $paths)
86    {
87        foreach ($paths as $path) {
88            $this->addExtension($path);
89        }
90
91        return $this;
92    }
93
94    /**
95     * @param array $encoded_extensions An array of base64 encoded of the extensions.
96     * @return ChromeOptions
97     */
98    public function addEncodedExtensions(array $encoded_extensions)
99    {
100        foreach ($encoded_extensions as $encoded_extension) {
101            $this->addEncodedExtension($encoded_extension);
102        }
103
104        return $this;
105    }
106
107    /**
108     * Sets an experimental option which has not exposed officially.
109     *
110     * @param string $name
111     * @param mixed $value
112     * @return ChromeOptions
113     */
114    public function setExperimentalOption($name, $value)
115    {
116        $this->experimentalOptions[$name] = $value;
117
118        return $this;
119    }
120
121    /**
122     * @return DesiredCapabilities The DesiredCapabilities for Chrome with this options.
123     */
124    public function toCapabilities()
125    {
126        $capabilities = DesiredCapabilities::chrome();
127        $capabilities->setCapability(self::CAPABILITY, $this);
128
129        return $capabilities;
130    }
131
132    /**
133     * @return \ArrayObject|array
134     */
135    public function toArray()
136    {
137        // The selenium server expects a 'dictionary' instead of a 'list' when
138        // reading the chrome option. However, an empty array in PHP will be
139        // converted to a 'list' instead of a 'dictionary'. To fix it, we work
140        // with `ArrayObject`
141        $options = new \ArrayObject($this->experimentalOptions);
142
143        if (!empty($this->binary)) {
144            $options['binary'] = $this->binary;
145        }
146
147        if (!empty($this->arguments)) {
148            $options['args'] = $this->arguments;
149        }
150
151        if (!empty($this->extensions)) {
152            $options['extensions'] = $this->extensions;
153        }
154
155        return $options;
156    }
157
158    /**
159     * Add a Chrome extension to install on browser startup. Each path should be a
160     * packed Chrome extension.
161     *
162     * @param string $path
163     * @return ChromeOptions
164     */
165    private function addExtension($path)
166    {
167        $this->addEncodedExtension(base64_encode(file_get_contents($path)));
168
169        return $this;
170    }
171
172    /**
173     * @param string $encoded_extension Base64 encoded of the extension.
174     * @return ChromeOptions
175     */
176    private function addEncodedExtension($encoded_extension)
177    {
178        $this->extensions[] = $encoded_extension;
179
180        return $this;
181    }
182}
183