1 <?php
2 /**
3 * @file
4 * Generic class for hosting / PaaS Providers.
5 */
6
7 namespace Fluxsauce\Switchboard;
8
9 /**
10 * Generic class for hosting / PaaS Providers.
11 * @package Fluxsauce\Switchboard
12 */
13 abstract class Provider {
14 /**
15 * @var string Machine name of the Provider.
16 */
17 protected $name;
18
19 /**
20 * @var string Human readable label for the Provider.
21 */
22 protected $label;
23
24 /**
25 * @var string Homepage URL for the provider.
26 */
27 protected $homepage;
28
29 /**
30 * @var string Endpoint URL for the provider.
31 */
32 protected $endpoint;
33
34 /**
35 * @var array Contains instances of Fluxsauce\Switchboard\Site
36 */
37 protected $sites;
38
39 /**
40 * Returns a singleton Provider.
41 *
42 * @param string $provider_name
43 * The machine name of a Provider.
44 *
45 * @return mixed
46 * A Provider subclass.
47 */
48 static public function getInstance($provider_name) {
49 static $instance = array();
50 if (!isset($instance[$provider_name])) {
51 $class_name = '\Fluxsauce\Switchboard\Provider' . ucfirst($provider_name);
52 $instance[$provider_name] = new $class_name();
53 }
54 return $instance[$provider_name];
55 }
56
57 /**
58 * Protected constructor; use getInstance.
59 */
60 protected function __construct() {
61 // Ensure implementing classes have necessary properties.
62 if (!$this->name) {
63 throw new \Exception('Missing name from ' . __CLASS__);
64 }
65 if (!$this->label) {
66 throw new \Exception('Missing label from ' . __CLASS__);
67 }
68 if (!filter_var($this->homepage, FILTER_VALIDATE_URL)) {
69 throw new \Exception('Missing valid homepage from ' . __CLASS__);
70 }
71 if (!filter_var($this->endpoint, FILTER_VALIDATE_URL)) {
72 throw new \Exception('Missing valid endpoint from ' . __CLASS__);
73 }
74
75 $pdo = Sqlite::get();
76 $this->sites = array();
77
78 try {
79 $sql_query = 'SELECT name ';
80 $sql_query .= 'FROM sites ';
81 $sql_query .= 'WHERE provider = :provider ';
82 $stmt = $pdo->prepare($sql_query);
83 $stmt->bindParam(':provider', $this->name);
84 $stmt->execute();
85 while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
86 $site = new Site($this->name, $row['name']);
87 $this->sites[$row['name']] = $site;
88 }
89 }
90 catch (\PDOException $e) {
91 switchboard_pdo_exception_debug($e);
92 }
93
94 if (drush_get_option('refresh')) {
95 $this->apiGetSites();
96 foreach ($this->sites as $site) {
97 $site->update();
98 }
99 }
100 }
101
102 /**
103 * Prevent cloning of the Provider Singleton.
104 */
105 private function __clone() {}
106
107 /**
108 * Prevent unserializing of the Provider Singleton.
109 */
110 private function __wakeup() {}
111
112 /**
113 * Magic __get.
114 *
115 * @param string $name
116 * The name of the property to get.
117 *
118 * @return mixed
119 * Value of set property.
120 * @throws \Exception
121 */
122 public function __get($name) {
123 if (!property_exists($this, $name)) {
124 drush_print_r(debug_backtrace());
125 throw new \Exception(__CLASS__ . ' property ' . $name . ' does not exist, cannot get.');
126 }
127 return $this->$name;
128 }
129
130 /**
131 * Perform an API call to get site information from a Provider.
132 *
133 * @param string $site_name
134 * The name of the site in question.
135 */
136 abstract public function apiGetSite($site_name);
137
138 /**
139 * Destroy a site associated with a Provider.
140 *
141 * @param string $site_name
142 * The machine name of the Site to destroy.
143 *
144 * @throws \Exception
145 */
146 public function siteDestroy($site_name) {
147 if (!isset($this->sites[$site_name])) {
148 throw new \Exception(__CLASS__ . ' site ' . $site_name . ' does not exist, cannot destroy.');
149 }
150 $this->sites[$site_name]->destroy();
151 unset($this->sites[$site_name]);
152 }
153
154 /**
155 * Delete all Sites associated with a Provider.
156 */
157 public function sitesDestroy() {
158 $this->sites = array();
159 $pdo = Sqlite::get();
160 try {
161 $stmt = $pdo->prepare('DELETE FROM sites WHERE provider = :provider');
162 $stmt->bindParam(':provider', $this->name, PDO::PARAM_STR);
163 $stmt->execute();
164 }
165 catch (\PDOException $e) {
166 switchboard_pdo_exception_debug($e);
167 }
168 }
169
170 /**
171 * Determine if a Site exists within a Provider.
172 *
173 * @param string $site_name
174 * The machine name of the Site to check.
175 *
176 * @return bool
177 * TRUE if Site exists within a provider, FALSE if it does not.
178 */
179 public function siteExists($site_name) {
180 if (!$site_name) {
181 return FALSE;
182 }
183 if (empty($this->sites)) {
184 $this->apiGetSites();
185 }
186 return array_key_exists($site_name, $this->sites);
187 }
188
189 /**
190 * A mapping function that calls the appropriate API to populate a field.
191 *
192 * @param string $site_name
193 * Machine name of the site in question.
194 * @param string $field
195 * Name of the field to populate.
196 *
197 * @return string
198 * The value of the field.
199 * @throws \Exception
200 * Unknown field name.
201 */
202 abstract public function siteGetField($site_name, $field);
203
204 /**
205 * Populate available Sites from a Provider.
206 */
207 abstract public function apiGetSites();
208
209 /**
210 * Populate available Site Environments from a Provider.
211 *
212 * @param string $site_name
213 * The machine name of the site in question.
214 */
215 abstract public function apiGetSiteEnvironments($site_name);
216
217 /**
218 * Get and populate list of Databases for a particular Environment.
219 *
220 * @param string $site_name
221 * The machine name of the Site.
222 * @param string $env_name
223 * The machine name of the Site Environment.
224 */
225 abstract public function apiGetSiteEnvDbs($site_name, $env_name);
226
227 /**
228 * Provider specific options for Requests.
229 *
230 * @return array
231 * Options for the request; see Requests::request for details.
232 */
233 abstract public function requestsOptionsCustom();
234
235 /**
236 * Log in to target Provider.
237 *
238 * @param string $email
239 * The email address of the user.
240 * @param string $password
241 * The password of the user.
242 *
243 * @return bool
244 * Indicates success.
245 */
246 abstract public function authLogin($email, $password);
247
248 /**
249 * Get a list of database backups for a particular Site Environment.
250 *
251 * @param string $site_name
252 * The machine name of the Site.
253 * @param string $env_name
254 * The machine name of the Site Environment.
255 *
256 * @return array
257 * An array of Backup arrays keyed by the timestamp. Each Backup
258 * array has the following keys:
259 * - 'filename'
260 * - 'url'
261 * - 'timestamp'
262 */
263 abstract public function apiGetSiteEnvDbBackups($site_name, $env_name);
264
265 /**
266 * Download a backup.
267 *
268 * @param array $backup
269 * An array from apiGetSiteEnvDbBackups().
270 * @param string $destination
271 * The path to the destination.
272 *
273 * @return string
274 * The full path to the downloaded backup.
275 */
276 abstract public function apiDownloadBackup($backup, $destination);
277
278 /**
279 * Helper function to get the latest database backup.
280 *
281 * @param string $site_name
282 * The machine name of the Site in question.
283 * @param string $env_name
284 * The machine name of the Site Environment in question.
285 *
286 * @return array
287 * A backup array as defined in apiGetSiteEnvDbBackups().
288 */
289 public function getSiteEnvDbBackupLatest($site_name, $env_name) {
290 $backups = $this->apiGetSiteEnvDbBackups($site_name, $env_name);
291 return array_pop($backups);
292 }
293
294 /**
295 * Get the name of the Drush cache bin for a particular Provider.
296 *
297 * @return string
298 * The name of the drush cache bin.
299 */
300 public function drushCacheBinAuthName() {
301 return 'switchboard-auth-' . $this->name;
302 }
303
304 /**
305 * Log out of target provider.
306 */
307 public function authLogout() {
308 drush_cache_clear_all('*', $this->drushCacheBinAuthName(), TRUE);
309 }
310
311 /**
312 * Determine whether a user is logged-in to a Provider.
313 *
314 * @return bool
315 * TRUE if they are.
316 */
317 abstract public function authIsLoggedIn();
318
319 /**
320 * Get the remote path to files for a particular Site Environment.
321 *
322 * @param string $site_name
323 * The machine name of the Site in question.
324 * @param string $env_name
325 * The machine name of the Site Environment in question.
326 *
327 * @return string
328 * The full path of the files directory.
329 */
330 abstract public function getFilesPath($site_name, $env_name);
331
332 /**
333 * Get all Provider specific and custom options for the Requests library.
334 *
335 * @param array $options
336 * Optional overriding options.
337 *
338 * @return array
339 * Options for the request; see Requests::request for details.
340 */
341 public function requestsOptions($options = array()) {
342 $defaults = array(
343 'timeout' => 30,
344 );
345
346 // Provider specific options.
347 $provider_options = $this->requestsOptionsCustom();
348 if (!empty($provider_options)) {
349 $defaults += $provider_options;
350 }
351
352 // Custom options.
353 if (!empty($options)) {
354 $defaults += $options;
355 }
356
357 return $defaults;
358 }
359 }
360