/** * Validate & convert settings input * * @value mixed value of the setting to be set * @fieldSpec array Metadata for given field (drawn from the xml) */ public static function validateSetting(&$value, $fieldSpec) { if ($fieldSpec['type'] == 'String' && is_array($value)) { $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $value) . CRM_Core_DAO::VALUE_SEPARATOR; } if (empty($fieldSpec['validate_callback'])) { return TRUE; } else { $cb = Civi\Core\Resolver::singleton()->get($fieldSpec['validate_callback']); if (!call_user_func_array($cb, array(&$value, $fieldSpec))) { throw new api_Exception("validation failed for {$fieldSpec['name']} = {$value} based on callback {$fieldSpec['validate_callback']}"); } } }
/** * Construct a new mailing object, along with job and mailing_group * objects, from the form values of the create mailing wizard. * * This function is a bit evil. It not only merges $params and saves * the mailing -- it also schedules the mailing and chooses the recipients. * Since it merges $params, it's also the only place to correctly trigger * multi-field validation. It should be broken up. * * In the mean time, use-cases which break under the weight of this * evil may find reprieve in these extra evil params: * * - _skip_evil_bao_auto_recipients_: bool * - _skip_evil_bao_auto_schedule_: bool * - _evil_bao_validator_: string|callable * * </twowrongsmakesaright> * * @params array $params * Form values. * * @param array $params * @param array $ids * * @return object * $mailing The new mailing object * @throws \Exception */ public static function create(&$params, $ids = array()) { // WTH $ids if (empty($ids) && isset($params['id'])) { $ids['mailing_id'] = $ids['id'] = $params['id']; } // CRM-12430 // Do the below only for an insert // for an update, we should not set the defaults if (!isset($ids['id']) && !isset($ids['mailing_id'])) { // Retrieve domain email and name for default sender $domain = civicrm_api('Domain', 'getsingle', array('version' => 3, 'current_domain' => 1, 'sequential' => 1)); if (isset($domain['from_email'])) { $domain_email = $domain['from_email']; $domain_name = $domain['from_name']; } else { $domain_email = '*****@*****.**'; $domain_name = 'EXAMPLE.ORG'; } if (!isset($params['created_id'])) { $session =& CRM_Core_Session::singleton(); $params['created_id'] = $session->get('userID'); } $defaults = array('override_verp' => TRUE, 'forward_replies' => FALSE, 'open_tracking' => TRUE, 'url_tracking' => TRUE, 'visibility' => 'Public Pages', 'replyto_email' => $domain_email, 'header_id' => CRM_Mailing_PseudoConstant::defaultComponent('header_id', ''), 'footer_id' => CRM_Mailing_PseudoConstant::defaultComponent('footer_id', ''), 'from_email' => $domain_email, 'from_name' => $domain_name, 'msg_template_id' => NULL, 'created_id' => $params['created_id'], 'approver_id' => NULL, 'auto_responder' => 0, 'created_date' => date('YmdHis'), 'scheduled_date' => NULL, 'approval_date' => NULL); // Get the default from email address, if not provided. if (empty($defaults['from_email'])) { $defaultAddress = CRM_Core_OptionGroup::values('from_email_address', NULL, NULL, NULL, ' AND is_default = 1'); foreach ($defaultAddress as $id => $value) { if (preg_match('/"(.*)" <(.*)>/', $value, $match)) { $defaults['from_email'] = $match[2]; $defaults['from_name'] = $match[1]; } } } $params = array_merge($defaults, $params); } /** * Could check and warn for the following cases: * * - groups OR mailings should be populated. * - body html OR body text should be populated. */ $transaction = new CRM_Core_Transaction(); $mailing = self::add($params, $ids); if (is_a($mailing, 'CRM_Core_Error')) { $transaction->rollback(); return $mailing; } // update mailings with hash values CRM_Contact_BAO_Contact_Utils::generateChecksum($mailing->id, NULL, NULL, NULL, 'mailing', 16); $groupTableName = CRM_Contact_BAO_Group::getTableName(); $mailingTableName = CRM_Mailing_BAO_Mailing::getTableName(); /* Create the mailing group record */ $mg = new CRM_Mailing_DAO_MailingGroup(); $groupTypes = array('include' => 'Include', 'exclude' => 'Exclude', 'base' => 'Base'); foreach (array('groups', 'mailings') as $entity) { foreach (array('include', 'exclude', 'base') as $type) { if (isset($params[$entity][$type])) { self::replaceGroups($mailing->id, $groupTypes[$type], $entity, $params[$entity][$type]); } } } if (!empty($params['search_id']) && !empty($params['group_id'])) { $mg->reset(); $mg->mailing_id = $mailing->id; $mg->entity_table = $groupTableName; $mg->entity_id = $params['group_id']; $mg->search_id = $params['search_id']; $mg->search_args = $params['search_args']; $mg->group_type = 'Include'; $mg->save(); } // check and attach and files as needed CRM_Core_BAO_File::processAttachment($params, 'civicrm_mailing', $mailing->id); // If we're going to autosend, then check validity before saving. if (!empty($params['scheduled_date']) && $params['scheduled_date'] != 'null' && !empty($params['_evil_bao_validator_'])) { $cb = Civi\Core\Resolver::singleton()->get($params['_evil_bao_validator_']); $errors = call_user_func($cb, $mailing); if (!empty($errors)) { $fields = implode(',', array_keys($errors)); throw new CRM_Core_Exception("Mailing cannot be sent. There are missing or invalid fields ({$fields}).", 'cannot-send', $errors); } } $transaction->commit(); // Create parent job if not yet created. // Condition on the existence of a scheduled date. if (!empty($params['scheduled_date']) && $params['scheduled_date'] != 'null' && empty($params['_skip_evil_bao_auto_schedule_'])) { $job = new CRM_Mailing_BAO_MailingJob(); $job->mailing_id = $mailing->id; $job->status = 'Scheduled'; $job->is_test = 0; if (!$job->find(TRUE)) { $job->scheduled_date = $params['scheduled_date']; $job->save(); } // Populate the recipients. if (empty($params['_skip_evil_bao_auto_recipients_'])) { self::getRecipients($job->id, $mailing->id, TRUE, $mailing->dedupe_email); } } return $mailing; }
/** * Given a menu item, call the appropriate controller and return the response * * @param array $item * See CRM_Core_Menu. * @return string, HTML */ public static function runItem($item) { $config = CRM_Core_Config::singleton(); if ($config->userFramework == 'Joomla' && $item) { $config->userFrameworkURLVar = 'task'; // joomla 1.5RC1 seems to push this in the POST variable, which messes // QF and checkboxes unset($_POST['option']); CRM_Core_Joomla::sidebarLeft(); } // set active Component $template = CRM_Core_Smarty::singleton(); $template->assign('activeComponent', 'CiviCRM'); $template->assign('formTpl', 'default'); if ($item) { // CRM-7656 - make sure we send a clean sanitized path to create printer friendly url $printerFriendly = CRM_Utils_System::makeURL('snippet', FALSE, FALSE, CRM_Utils_Array::value('path', $item)) . '2'; $template->assign('printerFriendly', $printerFriendly); if (!array_key_exists('page_callback', $item)) { CRM_Core_Error::debug('Bad item', $item); CRM_Core_Error::fatal(ts('Bad menu record in database')); } // check that we are permissioned to access this page if (!CRM_Core_Permission::checkMenuItem($item)) { CRM_Utils_System::permissionDenied(); return NULL; } // check if ssl is set if (!empty($item['is_ssl'])) { CRM_Utils_System::redirectToSSL(); } if (isset($item['title'])) { CRM_Utils_System::setTitle($item['title']); } if (isset($item['breadcrumb']) && !isset($item['is_public'])) { CRM_Utils_System::appendBreadCrumb($item['breadcrumb']); } $pageArgs = NULL; if (!empty($item['page_arguments'])) { $pageArgs = CRM_Core_Menu::getArrayForPathArgs($item['page_arguments']); } $template = CRM_Core_Smarty::singleton(); if (!empty($item['is_public'])) { $template->assign('urlIsPublic', TRUE); } else { $template->assign('urlIsPublic', FALSE); self::statusCheck($template); } if (isset($item['return_url'])) { $session = CRM_Core_Session::singleton(); $args = CRM_Utils_Array::value('return_url_args', $item, 'reset=1'); $session->pushUserContext(CRM_Utils_System::url($item['return_url'], $args)); } $result = NULL; // WISHLIST: Refactor this. Instead of pattern-matching on page_callback, lookup // page_callback via Civi\Core\Resolver and check the implemented interfaces. This // would require rethinking the default constructor. if (is_array($item['page_callback']) || strpos($item['page_callback'], ':')) { $result = call_user_func(Civi\Core\Resolver::singleton()->get($item['page_callback'])); } elseif (strstr($item['page_callback'], '_Form')) { $wrapper = new CRM_Utils_Wrapper(); $result = $wrapper->run(CRM_Utils_Array::value('page_callback', $item), CRM_Utils_Array::value('title', $item), isset($pageArgs) ? $pageArgs : NULL); } else { $newArgs = explode('/', $_GET[$config->userFrameworkURLVar]); $mode = 'null'; if (isset($pageArgs['mode'])) { $mode = $pageArgs['mode']; unset($pageArgs['mode']); } $title = CRM_Utils_Array::value('title', $item); if (strstr($item['page_callback'], '_Page') || strstr($item['page_callback'], '\\Page\\')) { $object = new $item['page_callback']($title, $mode); $object->urlPath = explode('/', $_GET[$config->userFrameworkURLVar]); } elseif (strstr($item['page_callback'], '_Controller') || strstr($item['page_callback'], '\\Controller\\')) { $addSequence = 'false'; if (isset($pageArgs['addSequence'])) { $addSequence = $pageArgs['addSequence']; $addSequence = $addSequence ? 'true' : 'false'; unset($pageArgs['addSequence']); } $object = new $item['page_callback']($title, TRUE, $mode, NULL, $addSequence); } else { CRM_Core_Error::fatal(); } $result = $object->run($newArgs, $pageArgs); } CRM_Core_Session::storeSessionObjects(); return $result; } CRM_Core_Menu::store(); CRM_Core_Session::setStatus(ts('Menu has been rebuilt'), ts('Complete'), 'success'); return CRM_Utils_System::redirect(); }
/** * Get options for settings. * * @param array $params * * @return array * @throws \API_Exception */ function civicrm_api3_setting_getoptions($params) { $specs = CRM_Core_BAO_Setting::getSettingSpecification(); if (empty($specs[$params['field']]) || empty($specs[$params['field']]['pseudoconstant'])) { throw new API_Exception("The field '" . $params['field'] . "' has no associated option list."); } $pseudoconstant = $specs[$params['field']]['pseudoconstant']; // It would be nice if we could leverage CRM_Core_PseudoConstant::get() somehow, // but it's tightly coupled to DAO/field. However, if you really need to support // more pseudoconstant types, then probably best to refactor it. For now, KISS. if (!empty($pseudoconstant['callback'])) { $values = Civi\Core\Resolver::singleton()->call($pseudoconstant['callback'], array()); return civicrm_api3_create_success($values, $params, 'Setting', 'getoptions'); } throw new API_Exception("The field '" . $params['field'] . "' uses an unsupported option list."); }
/** * Low-level option getter, rarely accessed directly. * NOTE: Rather than calling this function directly use CRM_*_BAO_*::buildOptions() * @see http://wiki.civicrm.org/confluence/display/CRMDOC/Pseudoconstant+%28option+list%29+Reference * * @param string $daoName * @param string $fieldName * @param array $params * - name string name of the option group * - flip boolean results are return in id => label format if false * if true, the results are reversed * - grouping boolean if true, return the value in 'grouping' column (currently unsupported for tables other than option_value) * - localize boolean if true, localize the results before returning * - condition string|array add condition(s) to the sql query - will be concatenated using 'AND' * - keyColumn string the column to use for 'id' * - labelColumn string the column to use for 'label' * - orderColumn string the column to use for sorting, defaults to 'weight' column if one exists, else defaults to labelColumn * - onlyActive boolean return only the action option values * - fresh boolean ignore cache entries and go back to DB * @param string $context : Context string * * @return array|bool * array on success, FALSE on error. * */ public static function get($daoName, $fieldName, $params = array(), $context = NULL) { CRM_Core_DAO::buildOptionsContext($context); $flip = !empty($params['flip']); // Merge params with defaults $params += array('grouping' => FALSE, 'localize' => FALSE, 'onlyActive' => $context == 'validate' || $context == 'get' ? FALSE : TRUE, 'fresh' => FALSE); // Custom fields are not in the schema if (strpos($fieldName, 'custom_') === 0 && is_numeric($fieldName[7])) { $customField = new CRM_Core_DAO_CustomField(); $customField->id = (int) substr($fieldName, 7); $customField->find(TRUE); $options = FALSE; if (!empty($customField->option_group_id)) { $options = CRM_Core_OptionGroup::valuesByID($customField->option_group_id, FALSE, $params['grouping'], $params['localize'], CRM_Utils_Array::value('labelColumn', $params, 'label'), $params['onlyActive'], $params['fresh']); } else { if ($customField->data_type === 'StateProvince') { $options = self::stateProvince(); } elseif ($customField->data_type === 'Country') { $options = $context == 'validate' ? self::countryIsoCode() : self::country(); } elseif ($customField->data_type === 'Boolean') { $options = $context == 'validate' ? array(0, 1) : CRM_Core_SelectValues::boolean(); } } CRM_Utils_Hook::customFieldOptions($customField->id, $options, FALSE); if ($options && $flip) { $options = array_flip($options); } $customField->free(); return $options; } // Core field: load schema $dao = new $daoName(); $fieldSpec = $dao->getFieldSpec($fieldName); $dao->free(); // If neither worked then this field doesn't exist. Return false. if (empty($fieldSpec)) { return FALSE; } elseif (!empty($fieldSpec['pseudoconstant'])) { $pseudoconstant = $fieldSpec['pseudoconstant']; // if callback is specified.. if (!empty($pseudoconstant['callback'])) { return call_user_func(Civi\Core\Resolver::singleton()->get($pseudoconstant['callback'])); } // Merge params with schema defaults $params += array('condition' => CRM_Utils_Array::value('condition', $pseudoconstant, array()), 'keyColumn' => CRM_Utils_Array::value('keyColumn', $pseudoconstant), 'labelColumn' => CRM_Utils_Array::value('labelColumn', $pseudoconstant)); if ($context == 'abbreviate') { switch ($fieldName) { case 'state_province_id': $params['labelColumn'] = 'abbreviation'; break; case 'country_id': $params['labelColumn'] = 'iso_code'; break; default: } } // Fetch option group from option_value table if (!empty($pseudoconstant['optionGroupName'])) { if ($context == 'validate') { $params['labelColumn'] = 'name'; } if ($context == 'match') { $params['keyColumn'] = 'name'; } // Call our generic fn for retrieving from the option_value table return CRM_Core_OptionGroup::values($pseudoconstant['optionGroupName'], $flip, $params['grouping'], $params['localize'], $params['condition'] ? ' AND ' . implode(' AND ', (array) $params['condition']) : NULL, $params['labelColumn'] ? $params['labelColumn'] : 'label', $params['onlyActive'], $params['fresh'], $params['keyColumn'] ? $params['keyColumn'] : 'value'); } // Fetch options from other tables if (!empty($pseudoconstant['table'])) { // Normalize params so the serialized cache string will be consistent. CRM_Utils_Array::remove($params, 'flip', 'fresh'); ksort($params); $cacheKey = $daoName . $fieldName . serialize($params); // Retrieve cached options if (isset(self::$cache[$cacheKey]) && empty($params['fresh'])) { $output = self::$cache[$cacheKey]; } else { $daoName = CRM_Core_DAO_AllCoreTables::getClassForTable($pseudoconstant['table']); if (!class_exists($daoName)) { return FALSE; } // Get list of fields for the option table $dao = new $daoName(); $availableFields = array_keys($dao->fieldKeys()); $dao->free(); $select = "SELECT %1 AS id, %2 AS label"; $from = "FROM %3"; $wheres = array(); $order = "ORDER BY %2"; // Use machine name in certain contexts if ($context == 'validate' || $context == 'match') { $nameField = $context == 'validate' ? 'labelColumn' : 'keyColumn'; if (!empty($pseudoconstant['nameColumn'])) { $params[$nameField] = $pseudoconstant['nameColumn']; } elseif (in_array('name', $availableFields)) { $params[$nameField] = 'name'; } } // Condition param can be passed as an sql clause string or an array of clauses if (!empty($params['condition'])) { $wheres[] = implode(' AND ', (array) $params['condition']); } // onlyActive param will automatically filter on common flags if (!empty($params['onlyActive'])) { foreach (array('is_active' => 1, 'is_deleted' => 0, 'is_test' => 0, 'is_hidden' => 0) as $flag => $val) { if (in_array($flag, $availableFields)) { $wheres[] = "{$flag} = {$val}"; } } } // Filter domain specific options if (in_array('domain_id', $availableFields)) { $wheres[] = 'domain_id = ' . CRM_Core_Config::domainID(); } $queryParams = array(1 => array($params['keyColumn'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES), 2 => array($params['labelColumn'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES), 3 => array($pseudoconstant['table'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES)); // Add orderColumn param if (!empty($params['orderColumn'])) { $queryParams[4] = array($params['orderColumn'], 'String', CRM_Core_DAO::QUERY_FORMAT_NO_QUOTES); $order = "ORDER BY %4"; } elseif (isset($params['orderColumn']) && $params['orderColumn'] === FALSE) { $order = ''; } elseif (in_array('weight', $availableFields)) { $order = "ORDER BY weight"; } $output = array(); $query = "{$select} {$from}"; if ($wheres) { $query .= " WHERE " . implode($wheres, ' AND '); } $query .= ' ' . $order; $dao = CRM_Core_DAO::executeQuery($query, $queryParams); while ($dao->fetch()) { $output[$dao->id] = $dao->label; } $dao->free(); // Localize results if (!empty($params['localize']) || $pseudoconstant['table'] == 'civicrm_country' || $pseudoconstant['table'] == 'civicrm_state_province') { $I18nParams = array(); if ($pseudoconstant['table'] == 'civicrm_country') { $I18nParams['context'] = 'country'; } if ($pseudoconstant['table'] == 'civicrm_state_province') { $I18nParams['context'] = 'province'; } $i18n = CRM_Core_I18n::singleton(); $i18n->localizeArray($output, $I18nParams); // Maintain sort by label if ($order == "ORDER BY %2") { CRM_Utils_Array::asort($output); } } self::$cache[$cacheKey] = $output; } return $flip ? array_flip($output) : $output; } } elseif (CRM_Utils_Array::value('type', $fieldSpec) === CRM_Utils_Type::T_BOOLEAN) { $output = $context == 'validate' ? array(0, 1) : array(1 => ts('Yes'), 0 => ts('No')); return $flip ? array_flip($output) : $output; } // If we're still here, it's an error. Return FALSE. return FALSE; }