3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
28 define('API_V3_EXTENSION_DELIMITER', ',');
32 * This provides an api interface for CiviCRM extension management.
34 * @package CiviCRM_APIv3
38 * Install an extension.
40 * @param array $params
42 * - key: string, eg "com.example.myextension"
43 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
44 * - path: string, e.g. "/var/www/extensions/*"
46 * Using 'keys' should be more performant than making multiple API calls with 'key'
50 function civicrm_api3_extension_install($params) {
51 $keys = _civicrm_api3_getKeys($params);
53 return civicrm_api3_create_success();
57 $manager = CRM_Extension_System
::singleton()->getManager();
58 $manager->install($manager->findInstallRequirements($keys));
60 catch (CRM_Extension_Exception
$e) {
61 return civicrm_api3_create_error($e->getMessage());
64 return civicrm_api3_create_success();
68 * Spec function for getfields
71 function _civicrm_api3_extension_install_spec(&$fields) {
72 $fields['keys'] = array(
73 'title' => 'Extension Key(s)',
74 'api.aliases' => array('key'),
75 'type' => CRM_Utils_Type
::T_STRING
,
76 'description' => 'Fully qualified name of one or more extensions',
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 ("*").',
86 * Upgrade an extension - runs upgrade_N hooks and system.flush.
91 function 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',
97 'errorMode' => CRM_Queue_Runner
::ERROR_ABORT
,
101 $result = $runner->runAll();
103 catch (CRM_Extension_Exception
$e) {
104 return civicrm_api3_create_error($e->getMessage());
107 if ($result === TRUE) {
108 return civicrm_api3_create_success();
116 * Enable an extension.
118 * @param array $params
120 * - key: string, eg "com.example.myextension"
121 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
122 * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*"
124 * Using 'keys' should be more performant than making multiple API calls with 'key'
128 function civicrm_api3_extension_enable($params) {
129 $keys = _civicrm_api3_getKeys($params);
130 if (count($keys) == 0) {
131 return civicrm_api3_create_success();
134 $manager = CRM_Extension_System
::singleton()->getManager();
135 $manager->enable($manager->findInstallRequirements($keys));
136 return civicrm_api3_create_success();
140 * Spec function for getfields
143 function _civicrm_api3_extension_enable_spec(&$fields) {
144 _civicrm_api3_extension_install_spec($fields);
148 * Disable an extension.
150 * @param array $params
152 * - key: string, eg "com.example.myextension"
153 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
154 * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*"
156 * Using 'keys' should be more performant than making multiple API calls with 'key'
160 function civicrm_api3_extension_disable($params) {
161 $keys = _civicrm_api3_getKeys($params);
162 if (count($keys) == 0) {
163 return civicrm_api3_create_success();
166 CRM_Extension_System
::singleton()->getManager()->disable($keys);
167 return civicrm_api3_create_success();
171 * Spec function for getfields
174 function _civicrm_api3_extension_disable_spec(&$fields) {
175 _civicrm_api3_extension_install_spec($fields);
179 * Uninstall an extension.
181 * @param array $params
183 * - key: string, eg "com.example.myextension"
184 * - keys: array of string, eg array("com.example.myextension1", "com.example.myextension2")
185 * - path: string, e.g. "/var/www/vendor/foo/myext" or "/var/www/vendor/*"
187 * Using 'keys' should be more performant than making multiple API calls with 'key'
189 * @todo: removeFiles as optional param
193 function civicrm_api3_extension_uninstall($params) {
194 $keys = _civicrm_api3_getKeys($params);
195 if (count($keys) == 0) {
196 return civicrm_api3_create_success();
199 CRM_Extension_System
::singleton()->getManager()->uninstall($keys);
200 return civicrm_api3_create_success();
204 * Spec function for getfields
207 function _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,
217 * Download and install an extension.
219 * @param array $params
221 * - key: string, eg "com.example.myextension"
222 * - url: string eg "http://repo.com/myextension-1.0.zip"
224 * @throws API_Exception
228 function civicrm_api3_extension_download($params) {
229 if (!array_key_exists('url', $params)) {
230 if (!CRM_Extension_System
::singleton()->getBrowser()->isEnabled()) {
231 throw new API_Exception('Automatic downloading is disabled. Try adding parameter "url"');
233 if ($reqs = CRM_Extension_System
::singleton()->getBrowser()->checkRequirements()) {
234 $first = array_shift($reqs);
235 throw new API_Exception($first['message']);
237 if ($info = CRM_Extension_System
::singleton()->getBrowser()->getExtension($params['key'])) {
238 if ($info->downloadUrl
) {
239 $params['url'] = $info->downloadUrl
;
244 if (!array_key_exists('url', $params)) {
245 throw new API_Exception('Cannot resolve download url for extension. Try adding parameter "url"');
248 foreach (CRM_Extension_System
::singleton()->getDownloader()->checkRequirements() as $requirement) {
249 return civicrm_api3_create_error($requirement['message']);
252 if (!CRM_Extension_System
::singleton()->getDownloader()->download($params['key'], $params['url'])) {
253 return civicrm_api3_create_error('Download failed - ZIP file is unavailable or malformed');
255 CRM_Extension_System
::singleton()->getCache()->flush();
256 CRM_Extension_System
::singleton(TRUE);
257 if (CRM_Utils_Array
::value('install', $params, TRUE)) {
258 CRM_Extension_System
::singleton()->getManager()->install(array($params['key']));
261 return civicrm_api3_create_success();
265 * Spec function for getfields
268 function _civicrm_api3_extension_download_spec(&$fields) {
269 $fields['key'] = array(
270 'title' => 'Extension Key',
272 'type' => CRM_Utils_Type
::T_STRING
,
273 'description' => 'Fully qualified name of the extension',
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',
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,
289 * Download and install an extension.
291 * @param array $params
293 * - local: bool, whether to rescan local filesystem (default: TRUE)
294 * - remote: bool, whether to rescan remote repository (default: TRUE)
299 function civicrm_api3_extension_refresh($params) {
300 $system = CRM_Extension_System
::singleton(TRUE);
302 if ($params['local']) {
303 $system->getManager()->refresh();
304 $system->getManager()->getStatuses(); // force immediate scan
307 if ($params['remote']) {
308 if ($system->getBrowser()->isEnabled() && empty($system->getBrowser()->checkRequirements
)) {
309 $system->getBrowser()->refresh();
310 $system->getBrowser()->getExtensions(); // force immediate download
314 return civicrm_api3_create_success();
318 * Spec function for getfields
321 function _civicrm_api3_extension_refresh_spec(&$fields) {
322 $fields['local'] = array(
323 'title' => 'Rescan Local',
325 'type' => CRM_Utils_Type
::T_BOOLEAN
,
326 'description' => 'Whether to rescan the local filesystem (default TRUE)',
328 $fields['remote'] = array(
329 'title' => 'Rescan Remote',
331 'type' => CRM_Utils_Type
::T_BOOLEAN
,
332 'description' => 'Whether to rescan the remote repository (default TRUE)',
337 * Get a list of available extensions.
339 * @param array $params
344 function civicrm_api3_extension_get($params) {
345 $full_names = _civicrm_api3_getKeys($params, 'full_name');
346 $keys = _civicrm_api3_getKeys($params, 'key');
347 $keys = array_merge($full_names, $keys);
348 $statuses = CRM_Extension_System
::singleton()->getManager()->getStatuses();
349 $mapper = CRM_Extension_System
::singleton()->getMapper();
352 foreach ($statuses as $key => $status) {
354 $obj = $mapper->keyToInfo($key);
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)));
360 $info = CRM_Extension_System
::createExtendedInfo($obj);
361 $info['id'] = $id++
; // backward compatibility with indexing scheme
363 if (in_array($key, $keys)) {
372 // These fields have been filtered already, and they have special semantics.
373 unset($params['key']);
374 unset($params['keys']);
375 unset($params['full_name']);
377 $filterableFields = array('id', 'type', 'status', 'path');
378 return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', $filterableFields);
382 * Get a list of remotely available extensions.
384 * @param array $params
389 function civicrm_api3_extension_getremote($params) {
390 $extensions = CRM_Extension_System
::singleton()->getBrowser()->getExtensions();
393 foreach ($extensions as $key => $obj) {
395 $info['id'] = $id++
; // backward compatibility with indexing scheme
396 $info = array_merge($info, (array) $obj);
399 return _civicrm_api3_basic_array_get('Extension', $params, $result, 'id', CRM_Utils_Array
::value('return', $params, array()));
403 * Determine the list of extension keys.
405 * @param array $params
407 * API request params with 'keys' or 'path'.
408 * - keys: A comma-delimited list of extension names
409 * - path: An absolute directory path. May append '*' to match all sub-directories.
413 function _civicrm_api3_getKeys($params, $key = 'keys') {
414 if ($key == 'path') {
415 return CRM_Extension_System
::singleton()->getMapper()->getKeysByPath($params['path']);
417 if (isset($params[$key])) {
418 if (is_array($params[$key])) {
419 return $params[$key];
421 if ($params[$key] == '') {
424 return explode(API_V3_EXTENSION_DELIMITER
, $params[$key]);