Merge pull request #10486 from mickadoo/CRM-20710_get-valid-types-function
[civicrm-core.git] / api / v3 / Extension.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
81621fee 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
1f4ea726 6 | Copyright CiviCRM LLC (c) 2004-2017 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
c490a46a
CW
28define('API_V3_EXTENSION_DELIMITER', ',');
29
30
6a488035 31/**
244bbdd8 32 * This provides an api interface for CiviCRM extension management.
6a488035
TO
33 *
34 * @package CiviCRM_APIv3
6a488035
TO
35 */
36
37/**
dc64d047 38 * Install an extension.
6a488035 39 *
cf470720
TO
40 * @param array $params
41 * Input parameters.
e5f24f02
CW
42 * - key: string, eg "com.example.myextension"
43 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
3b3f6d23 44 * - path: string, e.g. "/var/www/extensions/*"
e5f24f02
CW
45 *
46 * Using 'keys' should be more performant than making multiple API calls with 'key'
6a488035 47 *
a6c01b45 48 * @return array
6a488035
TO
49 */
50function civicrm_api3_extension_install($params) {
82b474af 51 $keys = _civicrm_api3_getKeys($params);
dbb0dbe6 52 if (!$keys) {
6a488035
TO
53 return civicrm_api3_create_success();
54 }
55
56 try {
4827c43c
TO
57 $manager = CRM_Extension_System::singleton()->getManager();
58 $manager->install($manager->findInstallRequirements($keys));
0db6c3e1
TO
59 }
60 catch (CRM_Extension_Exception $e) {
6a488035
TO
61 return civicrm_api3_create_error($e->getMessage());
62 }
63
64 return civicrm_api3_create_success();
65}
66
e5f24f02
CW
67/**
68 * Spec function for getfields
69 * @param $fields
70 */
71function _civicrm_api3_extension_install_spec(&$fields) {
72 $fields['keys'] = array(
73 'title' => 'Extension Key(s)',
e5f24f02
CW
74 'api.aliases' => array('key'),
75 'type' => CRM_Utils_Type::T_STRING,
76 'description' => 'Fully qualified name of one or more extensions',
77 );
3b3f6d23
TO
78 $fields['path'] = array(
79 'title' => 'Extension Path',
80 'type' => CRM_Utils_Type::T_STRING,
81 'description' => 'The path to the extension. May use wildcard ("*").',
82 );
e5f24f02
CW
83}
84
9a477d10 85/**
d1b0d05e 86 * Upgrade an extension - runs upgrade_N hooks and system.flush.
9a477d10 87 *
a6c01b45 88 * @return array
72b3a70c 89 * API result
9a477d10
FG
90 */
91function civicrm_api3_extension_upgrade() {
92 CRM_Core_Invoke::rebuildMenuAndCaches(TRUE);
93 $queue = CRM_Extension_Upgrades::createQueue();
94 $runner = new CRM_Queue_Runner(array(
95 'title' => 'Extension Upgrades',
96 'queue' => $queue,
97 'errorMode' => CRM_Queue_Runner::ERROR_ABORT,
98 ));
99
100 try {
101 $result = $runner->runAll();
0db6c3e1
TO
102 }
103 catch (CRM_Extension_Exception $e) {
9a477d10
FG
104 return civicrm_api3_create_error($e->getMessage());
105 }
106
107 if ($result === TRUE) {
108 return civicrm_api3_create_success();
0db6c3e1
TO
109 }
110 else {
9a477d10
FG
111 return $result;
112 }
113}
114
6a488035 115/**
dc64d047 116 * Enable an extension.
6a488035 117 *
cf470720
TO
118 * @param array $params
119 * Input parameters.
e5f24f02
CW
120 * - key: string, eg "com.example.myextension"
121 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
3b3f6d23 122 * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*"
e5f24f02
CW
123 *
124 * Using 'keys' should be more performant than making multiple API calls with 'key'
6a488035 125 *
a6c01b45 126 * @return array
6a488035
TO
127 */
128function civicrm_api3_extension_enable($params) {
82b474af 129 $keys = _civicrm_api3_getKeys($params);
6a488035
TO
130 if (count($keys) == 0) {
131 return civicrm_api3_create_success();
132 }
133
4827c43c
TO
134 $manager = CRM_Extension_System::singleton()->getManager();
135 $manager->enable($manager->findInstallRequirements($keys));
6a488035
TO
136 return civicrm_api3_create_success();
137}
138
e5f24f02
CW
139/**
140 * Spec function for getfields
141 * @param $fields
142 */
143function _civicrm_api3_extension_enable_spec(&$fields) {
144 _civicrm_api3_extension_install_spec($fields);
145}
146
6a488035 147/**
9d32e6f7 148 * Disable an extension.
6a488035 149 *
cf470720
TO
150 * @param array $params
151 * Input parameters.
e5f24f02
CW
152 * - key: string, eg "com.example.myextension"
153 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
3b3f6d23 154 * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*"
e5f24f02
CW
155 *
156 * Using 'keys' should be more performant than making multiple API calls with 'key'
6a488035 157 *
a6c01b45 158 * @return array
6a488035
TO
159 */
160function civicrm_api3_extension_disable($params) {
82b474af 161 $keys = _civicrm_api3_getKeys($params);
6a488035
TO
162 if (count($keys) == 0) {
163 return civicrm_api3_create_success();
164 }
165
166 CRM_Extension_System::singleton()->getManager()->disable($keys);
167 return civicrm_api3_create_success();
168}
169
e5f24f02
CW
170/**
171 * Spec function for getfields
172 * @param $fields
173 */
174function _civicrm_api3_extension_disable_spec(&$fields) {
175 _civicrm_api3_extension_install_spec($fields);
176}
177
6a488035 178/**
dc64d047 179 * Uninstall an extension.
6a488035 180 *
cf470720
TO
181 * @param array $params
182 * Input parameters.
e5f24f02
CW
183 * - key: string, eg "com.example.myextension"
184 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
3b3f6d23 185 * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*"
e5f24f02
CW
186 *
187 * Using 'keys' should be more performant than making multiple API calls with 'key'
188 *
189 * @todo: removeFiles as optional param
6a488035 190 *
a6c01b45 191 * @return array
6a488035
TO
192 */
193function civicrm_api3_extension_uninstall($params) {
82b474af 194 $keys = _civicrm_api3_getKeys($params);
6a488035
TO
195 if (count($keys) == 0) {
196 return civicrm_api3_create_success();
197 }
198
6a488035
TO
199 CRM_Extension_System::singleton()->getManager()->uninstall($keys);
200 return civicrm_api3_create_success();
201}
202
e5f24f02
CW
203/**
204 * Spec function for getfields
205 * @param $fields
206 */
207function _civicrm_api3_extension_uninstall_spec(&$fields) {
208 _civicrm_api3_extension_install_spec($fields);
209 //$fields['removeFiles'] = array(
210 // 'title' => 'Remove files',
211 // 'description' => 'Whether to remove the source tree. Default FALSE.',
212 // 'type' => CRM_Utils_Type::T_BOOLEAN,
213 //);
214}
215
6a488035 216/**
dc64d047 217 * Download and install an extension.
6a488035 218 *
cf470720
TO
219 * @param array $params
220 * Input parameters.
244bbdd8
CW
221 * - key: string, eg "com.example.myextension"
222 * - url: string eg "http://repo.com/myextension-1.0.zip"
6a488035 223 *
77b97be7 224 * @throws API_Exception
a6c01b45 225 * @return array
72b3a70c 226 * API result
6a488035
TO
227 */
228function civicrm_api3_extension_download($params) {
6c552737
TO
229 if (!array_key_exists('url', $params)) {
230 if (!CRM_Extension_System::singleton()->getBrowser()->isEnabled()) {
e5f24f02 231 throw new API_Exception('Automatic downloading is disabled. Try adding parameter "url"');
6a488035
TO
232 }
233 if ($reqs = CRM_Extension_System::singleton()->getBrowser()->checkRequirements()) {
234 $first = array_shift($reqs);
235 throw new API_Exception($first['message']);
236 }
237 if ($info = CRM_Extension_System::singleton()->getBrowser()->getExtension($params['key'])) {
238 if ($info->downloadUrl) {
239 $params['url'] = $info->downloadUrl;
240 }
241 }
242 }
243
6c552737 244 if (!array_key_exists('url', $params)) {
6a488035
TO
245 throw new API_Exception('Cannot resolve download url for extension. Try adding parameter "url"');
246 }
247
248 foreach (CRM_Extension_System::singleton()->getDownloader()->checkRequirements() as $requirement) {
249 return civicrm_api3_create_error($requirement['message']);
250 }
251
6c552737 252 if (!CRM_Extension_System::singleton()->getDownloader()->download($params['key'], $params['url'])) {
6a488035
TO
253 return civicrm_api3_create_error('Download failed - ZIP file is unavailable or malformed');
254 }
255 CRM_Extension_System::singleton()->getCache()->flush();
256 CRM_Extension_System::singleton(TRUE);
c62449ca
TO
257 if (CRM_Utils_Array::value('install', $params, TRUE)) {
258 CRM_Extension_System::singleton()->getManager()->install(array($params['key']));
259 }
6a488035
TO
260
261 return civicrm_api3_create_success();
262}
263
e5f24f02
CW
264/**
265 * Spec function for getfields
266 * @param $fields
267 */
268function _civicrm_api3_extension_download_spec(&$fields) {
269 $fields['key'] = array(
270 'title' => 'Extension Key',
271 'api.required' => 1,
272 'type' => CRM_Utils_Type::T_STRING,
273 'description' => 'Fully qualified name of the extension',
274 );
275 $fields['url'] = array(
276 'title' => 'Download URL',
277 'type' => CRM_Utils_Type::T_STRING,
278 'description' => 'Optional as the system can determine the url automatically for public extensions',
279 );
c62449ca
TO
280 $fields['install'] = array(
281 'title' => 'Auto-install',
282 'type' => CRM_Utils_Type::T_STRING,
283 'description' => 'Automatically install the downloaded extension',
284 'api.default' => TRUE,
285 );
e5f24f02
CW
286}
287
6a488035 288/**
dc64d047 289 * Download and install an extension.
6a488035 290 *
cf470720
TO
291 * @param array $params
292 * Input parameters.
244bbdd8
CW
293 * - local: bool, whether to rescan local filesystem (default: TRUE)
294 * - remote: bool, whether to rescan remote repository (default: TRUE)
6a488035 295 *
a6c01b45 296 * @return array
72b3a70c 297 * API result
6a488035
TO
298 */
299function civicrm_api3_extension_refresh($params) {
6a488035
TO
300 $system = CRM_Extension_System::singleton(TRUE);
301
302 if ($params['local']) {
303 $system->getManager()->refresh();
304 $system->getManager()->getStatuses(); // force immediate scan
305 }
306
307 if ($params['remote']) {
308 if ($system->getBrowser()->isEnabled() && empty($system->getBrowser()->checkRequirements)) {
309 $system->getBrowser()->refresh();
310 $system->getBrowser()->getExtensions(); // force immediate download
311 }
312 }
313
314 return civicrm_api3_create_success();
315}
316
e5f24f02
CW
317/**
318 * Spec function for getfields
319 * @param $fields
320 */
321function _civicrm_api3_extension_refresh_spec(&$fields) {
322 $fields['local'] = array(
323 'title' => 'Rescan Local',
324 'api.default' => 1,
325 'type' => CRM_Utils_Type::T_BOOLEAN,
326 'description' => 'Whether to rescan the local filesystem (default TRUE)',
327 );
328 $fields['remote'] = array(
329 'title' => 'Rescan Remote',
330 'api.default' => 1,
331 'type' => CRM_Utils_Type::T_BOOLEAN,
332 'description' => 'Whether to rescan the remote repository (default TRUE)',
333 );
334}
335
6a488035 336/**
d1b0d05e 337 * Get a list of available extensions.
6a488035 338 *
c490a46a 339 * @param array $params
77b97be7 340 *
a6c01b45 341 * @return array
72b3a70c 342 * API result
6a488035
TO
343 */
344function civicrm_api3_extension_get($params) {
df4848b8
TS
345 $full_names = _civicrm_api3_getKeys($params, 'full_name');
346 $keys = _civicrm_api3_getKeys($params, 'key');
347 $keys = array_merge($full_names, $keys);
6a488035 348 $statuses = CRM_Extension_System::singleton()->getManager()->getStatuses();
517dfba8 349 $mapper = CRM_Extension_System::singleton()->getMapper();
6a488035 350 $result = array();
c36fe5b0 351 $id = 0;
6a488035 352 foreach ($statuses as $key => $status) {
517dfba8
AS
353 try {
354 $obj = $mapper->keyToInfo($key);
355 }
356 catch (CRM_Extension_Exception $ex) {
357 CRM_Core_Session::setStatus(ts('Failed to read extension (%1). Please refresh the extension list.', array(1 => $key)));
358 continue;
359 }
360 $info = CRM_Extension_System::createExtendedInfo($obj);
c36fe5b0 361 $info['id'] = $id++; // backward compatibility with indexing scheme
df4848b8 362 if (!empty($keys)) {
d4c44c70
SL
363 if (in_array($key, $keys)) {
364 $result[] = $info;
365 }
366 }
367 else {
368 $result[] = $info;
369 }
6a488035 370 }
9776f417 371 $options = _civicrm_api3_get_options_from_params($params);
525ccb68
TS
372 $returnFields = !empty($options['return']) ? $options['return'] : array();
373 if (!in_array('id', $returnFields)) {
374 $returnFields = array_merge($returnFields, array('id'));
375 }
d4c44c70 376 return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', $returnFields);
6a488035
TO
377}
378
c74a6c8f
AS
379/**
380 * Get a list of remotely available extensions.
381 *
382 * @param array $params
383 *
384 * @return array
385 * API result
386 */
387function civicrm_api3_extension_getremote($params) {
388 $extensions = CRM_Extension_System::singleton()->getBrowser()->getExtensions();
389 $result = array();
390 $id = 0;
391 foreach ($extensions as $key => $obj) {
392 $info = array();
393 $info['id'] = $id++; // backward compatibility with indexing scheme
394 $info = array_merge($info, (array) $obj);
395 $result[] = $info;
396 }
397 return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', CRM_Utils_Array::value('return', $params, array()));
398}
399
6a488035 400/**
d1b0d05e 401 * Determine the list of extension keys.
6a488035 402 *
cf470720 403 * @param array $params
df4848b8 404 * @param string $key
3b3f6d23
TO
405 * API request params with 'keys' or 'path'.
406 * - keys: A comma-delimited list of extension names
407 * - path: An absolute directory path. May append '*' to match all sub-directories.
d1b0d05e 408 *
a6c01b45 409 * @return array
6a488035 410 */
82b474af 411function _civicrm_api3_getKeys($params, $key = 'keys') {
3b3f6d23
TO
412 if ($key == 'path') {
413 return CRM_Extension_System::singleton()->getMapper()->getKeysByPath($params['path']);
414 }
83f51f6a
TS
415 if (isset($params[$key])) {
416 if (is_array($params[$key])) {
417 return $params[$key];
418 }
419 if ($params[$key] == '') {
420 return array();
421 }
422 return explode(API_V3_EXTENSION_DELIMITER, $params[$key]);
6f59c19b 423 }
97488fea
JK
424 else {
425 return array();
426 }
6a488035 427}