2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
40 * source is the parent class of any source object.
43 abstract class source{
45 * The name of an wrapper to use if the class wants to provide an override
50 protected $_field_defs;
53 * @var bool enable_in_wizard Boolean value marking whether or not the connector may appear in the wizard (Get Data) views
55 protected $_enable_in_wizard = true;
58 * @var bool enable_in_hover Boolean value marking whether or not a hover link could be applied to the connector
60 protected $_enable_in_hover = false;
63 * @var bool enable_in_admin_mapping Boolean value marking whether or not this connector should be shown in the Modify Mapping view
65 protected $_enable_in_admin_mapping = true;
68 * @var bool enable_in_admin_properties Boolean value marking whether or not this connector should appear in the Set Connector Properties view
70 protected $_enable_in_admin_properties = true;
73 * @var bool enable_in_admin_display Boolean value marking whether or not this connector should appear in the Enable Connectors view
75 protected $_enable_in_admin_display = true;
78 * @var bool enable_in_admin_search Boolean value marking whether or not this connector should appear in the Manage Connector Search view
80 protected $_enable_in_admin_search = true;
83 * @var bool has_testing_enabled Boolean value marking whether or not the connector should display the test button in administration view
85 protected $_has_testing_enabled = false;
87 protected $_required_config_fields = array();
88 protected $_required_config_fields_for_button = array();
89 protected $config_decrypted = false;
92 * The ExternalAPI Base that instantiated this connector.
95 protected $_eapm = null;
97 public function __construct(){
100 $this->loadVardefs();
103 public function init(){}
105 //////// CALLED FROM component.php ///////
106 public function loadMapping() {
108 $dir = str_replace('_','/',get_class($this));
109 if(file_exists("custom/modules/Connectors/connectors/sources/{$dir}/mapping.php")) {
110 require("custom/modules/Connectors/connectors/sources/{$dir}/mapping.php");
111 } else if(file_exists("modules/Connectors/connectors/sources/{$dir}/mapping.php")){
112 require("modules/Connectors/connectors/sources/{$dir}/mapping.php");
114 $this->_mapping = $mapping;
117 public function saveMappingHook($mapping) {
118 // Most classes don't care that the mapping has changed, but this is here if they do.
123 * Load source's vardef file
125 public function loadVardefs() {
126 $class = get_class($this);
127 $dir = str_replace('_','/',$class);
128 if(file_exists("custom/modules/Connectors/connectors/sources/{$dir}/vardefs.php")) {
129 require("custom/modules/Connectors/connectors/sources/{$dir}/vardefs.php");
130 } else if(file_exists("modules/Connectors/connectors/sources/{$dir}/vardefs.php")){
131 require("modules/Connectors/connectors/sources/{$dir}/vardefs.php");
134 $this->_field_defs = !empty($dictionary[$class]['fields']) ? $dictionary[$class]['fields'] : array();
138 * Given a parameter in a vardef field, return the list of fields that match the param and value
140 * @param string $param_name
141 * @param string $param_value
144 public function getFieldsWithParams($param_name, $param_value)
146 if(empty($this->_field_defs)){
147 $this->loadVardefs();
149 $fields_with_param = array();
150 foreach($this->_field_defs as $key => $def){
151 if(!empty($def[$param_name]) && ($def[$param_name] == $param_value)){
152 $fields_with_param[$key] = $def;
155 return $fields_with_param;
159 * Save source's config to custom directory
161 public function saveConfig()
163 $config_str = "<?php\n/***CONNECTOR SOURCE***/\n";
166 if(!empty($this->_config['encrypt_properties']) && is_array($this->_config['encrypt_properties']) && !empty($this->_config['properties'])){
167 require_once('include/utils/encryption_utils.php');
168 foreach($this->_config['encrypt_properties'] as $name) {
169 if(!empty($this->_config['properties'][$name])) {
170 $this->_config['properties'][$name] = blowfishEncode(blowfishGetKey('encrypt_field'),$this->_config['properties'][$name]);
176 foreach($this->_config as $key => $val) {
178 $config_str .= override_value_to_string_recursive2('config', $key, $val, false);
181 $dir = str_replace('_', '/', get_class($this));
183 if(!file_exists("custom/modules/Connectors/connectors/sources/{$dir}")) {
184 mkdir_recursive("custom/modules/Connectors/connectors/sources/{$dir}");
186 file_put_contents("custom/modules/Connectors/connectors/sources/{$dir}/config.php", $config_str);
190 * Initialize config - decrypt encrypted fields
192 public function initConfig()
194 if($this->config_decrypted) return;
196 require_once('include/utils/encryption_utils.php');
197 if(!empty($this->_config['encrypt_properties']) && is_array($this->_config['encrypt_properties']) && !empty($this->_config['properties'])){
198 foreach($this->_config['encrypt_properties'] as $name) {
199 if(!empty($this->_config['properties'][$name])) {
200 $this->_config['properties'][$name] = blowfishDecode(blowfishGetKey('encrypt_field'),$this->_config['properties'][$name]);
204 $this->config_decrypted = true;
208 * Load config.php for this source
210 public function loadConfig()
213 $dir = str_replace('_','/',get_class($this));
214 if(file_exists("modules/Connectors/connectors/sources/{$dir}/config.php")){
215 require("modules/Connectors/connectors/sources/{$dir}/config.php");
217 if(file_exists("custom/modules/Connectors/connectors/sources/{$dir}/config.php")) {
218 require("custom/modules/Connectors/connectors/sources/{$dir}/config.php");
220 $this->_config = $config;
222 //If there are no required config fields specified, we will default them to all be required
223 if(empty($this->_required_config_fields)) {
224 foreach($this->_config['properties'] as $id=>$value) {
225 $this->_required_config_fields[] = $id;
230 // Helper function for the settings panels
232 * Filter which modules are allowed to connect
233 * @param array $moduleList
234 * @return array Allowed modules
236 public function filterAllowedModules( $moduleList )
238 // Most modules can connect to everything, no further filtering necessary
242 ////////////// GETTERS and SETTERS ////////////////////
243 public function getMapping()
245 return $this->_mapping;
248 public function getOriginalMapping() {
250 $dir = str_replace('_','/',get_class($this));
251 if(file_exists("modules/Connectors/connectors/sources/{$dir}/mapping.php")) {
252 require("modules/Connectors/connectors/sources/{$dir}/mapping.php");
253 } else if(file_exists("custom/modules/Connectors/connectors/sources/{$dir}/mapping.php")){
254 require("custom/modules/Connectors/connectors/sources/{$dir}/mapping.php");
259 public function setMapping($mapping)
261 $this->_mapping = $mapping;
264 public function getFieldDefs()
266 return $this->_field_defs;
269 public function getConfig()
271 if(!$this->config_decrypted) $this->initConfig();
272 return $this->_config;
275 public function setConfig($config)
277 $this->_config = $config;
278 $this->config_decrypted = true; // Don't decrypt external configs
281 public function setEAPM(ExternalAPIBase $eapm)
283 $this->_eapm = $eapm;
286 public function getEAPM()
291 public function setProperties($properties=array())
293 if(!empty($this->_config) && isset($this->_config['properties'])) {
294 $this->_config['properties'] = $properties;
295 $this->config_decrypted = true; // Don't decrypt external configs
299 public function getProperties()
301 if(!empty($this->_config) && isset($this->_config['properties'])) {
302 if(!$this->config_decrypted) $this->initConfig();
303 return $this->_config['properties'];
309 * Check if certain property contains non-empty value
310 * @param string $name
313 public function propertyExists($name)
315 return !empty($this->_config['properties'][$name]);
318 public function getProperty($name)
320 if(!empty($this->_config) && isset($this->_config['properties'][$name])) {
321 // check if we're asking for encrypted property and we didn't decrypt yet
322 if(!$this->config_decrypted && !empty($this->_config['encrypt_properties']) && in_array($name, $this->_config['encrypt_properties']) && !empty($this->_config['properties'][$name])) {
325 return $this->_config['properties'][$name];
333 * This method is used to indicate whether or not a data source has testing enabled so that
334 * the administration interface may call the test method on the data source instance
336 * @return enabled boolean value indicating whether or not testing is enabled
338 public function hasTestingEnabled() {
339 return $this->_has_testing_enabled;
344 * This method is called from the administration interface to run a test of the service
345 * It is up to subclasses to implement a test and set _has_testing_enabled to true so that
346 * a test button is rendered in the administration interface
348 * @return result boolean result of the test function
350 public function test() {
357 * This method indicates whether or not the connector should be enabled in the wizard
358 * Connectors that do not support the getList/getItem methods via API calls should
359 * set the protected class variable _enable_in_wizard to false.
361 * @return $enabled boolean variable indicating whether or not the connector is enabled for the wizard
363 public function isEnabledInWizard() {
364 return $this->_enable_in_wizard;
370 * This method indicates whether or not the connector should be enabled for the hover links
371 * Connectors that do not provide a formatter implementation should not
372 * set the protected class variable _enable_in_hover to true.
374 * @return $enabled boolean variable indicating whether or not the connector is enabled for the hover links
377 public function isEnabledInHover() {
378 return $this->_enable_in_hover;
382 * isEnabledInAdminProperties
383 * This method indicates whether or not the connector should be shown in the Set Connector Properties view.
384 * The Admin views call each source's isEnabledInAdminProperties method to verify whether or not the connector should be
385 * displayed. Connectors that do not have any administrative properties should set the protected class variable
386 * _enable_in_admin_properties to false.
388 * @return boolean value indicating whether or not the connector is enabled for admin views
390 public function isEnabledInAdminProperties()
392 return $this->_enable_in_admin_properties;
396 * isEnabledInAdminMapping
397 * This method indicates whether or not the connector should be shown in the Map Connector Fields view.
398 * The Admin views call each source's isEnabledInAdminMapping method to verify whether or not the connector should be
399 * displayed. Connectors that do not have any administrative mapping properties should set the protected class variable
400 * _enable_in_admin_mapping to false.
402 * @return boolean value indicating whether or not the connector is enabled for admin views
404 public function isEnabledInAdminMapping()
406 return $this->_enable_in_admin_mapping;
410 * isEnabledInAdminDisplay
411 * This method indicates whether or not the connector should be shown in the Enable Connectors view.
412 * The Admin views call each source's isEnabledInAdminDisplay method to verify whether or not the connector should be
413 * displayed. Connectors that do not have any administrative display settings should set the protected class variable
414 * _enable_in_admin_display to false.
416 * @return boolean value indicating whether or not the connector is enabled for admin views
418 public function isEnabledInAdminDisplay()
420 return $this->_enable_in_admin_display;
424 * isEnabledInAdminSearch
425 * This method indicates whether or not the connector should be shown in the Manage Connectors Search view.
426 * The Admin views call each source's isEnabledInAdminSearch method to verify whether or not the connector should be
427 * displayed. Connectors that do not have any administrative search settings should set the protected class variable
428 * _enable_in_admin_search to false.
430 * @return boolean value indicating whether or not the connector is enabled for admin views
432 public function isEnabledInAdminSearch()
434 return $this->_enable_in_admin_search;
438 * getRequiredConfigFields
439 * This method returns an Array of the configuration keys that are required for the Connector.
440 * Subclasses should set the class variable _required_config_fields to
441 * return an Array of keys as specified in the Connector's config.php that are required.
443 * @return $fields Array of Connector config fields that are required
445 public function getRequiredConfigFields() {
446 return $this->_required_config_fields;
451 * isRequiredConfigFieldsSet
452 * This method checks the configuration parameters against the required config fields
453 * to see if they are set
455 * @return $set boolean value indicating whether or not the required config fields are set
457 public function isRequiredConfigFieldsSet() {
458 //Check if required fields are set
459 foreach($this->_required_config_fields as $field) {
460 if(empty($this->_config['properties'][$field])) {
469 * getRequiredConfigFieldsForButton
470 * This method returns an Array of the configuration keys that are required before the
471 * "Get Data" button will include the Connector. We use it as a subset of the
472 * $this->_required_config_fields Array.
474 * @return $fields Array of Connector config fields that are required to be set for the "Get Data" button to appear
476 public function getRequiredConfigFieldsForButton() {
477 return $this->_required_config_fields_for_button;
482 * isRequiredConfigFieldsForButtonSet
483 * This method checks the configuration parameters against the required config fields
484 * for the "Get Button" to see if they are set
486 * @return $set boolean value indicating whether or not the required config fields are set
488 public function isRequiredConfigFieldsForButtonSet() {
489 //Check if required fields for button are set
490 foreach($this->_required_config_fields_for_button as $field) {
491 if(empty($this->_config['properties'][$field])) {
500 * Allow data sources to log information
502 * @param string $log_data
504 protected function log($log_data){
505 $name = get_class($this);
506 $property_name = $this->getProperty('name');
507 if(!empty($property_name)){
508 $name = $property_name;
510 $GLOBALS['log']->info($name. ': '.$log_data);
515 * Returns an array containing a key/value pair(s) of a connector record. To be overridden by the implementation
518 * @param $args Array of arguments to search/filter by
519 * @param $module String optional value of the module that the connector framework is attempting to map to
520 * @return Array of key/value pair(s) of connector record; empty Array if no results are found
522 public abstract function getItem($args=array(), $module=null);
527 * Returns a nested array containing a key/value pair(s) of a connector record. To be overridden by the
528 * implementation source.
530 * @param $args Array of arguments to search/filter by
531 * @param $module String optional value of the module that the connector framework is attempting to map to
532 * @return Array of key/value pair(s) of connector record; empty Array if no results are found
534 public abstract function getList($args=array(), $module=null);
540 public function __destruct(){
541 // Bug # 47233 - This desctructor was originally removed by bug # 44533.
542 // We have to add this destructor back in
543 // because there are customers who upgrade from 61x to 623
544 // who have the Jigsaw connector enabled, and the jigsaw connector
545 // makes a call to this destructor.