public function getManagedEntities() { // Use hook_civicrm_caseTypes to build a list of OptionValues // In the long run, we may want more specialized logic for this, but // this design is fairly convenient and will allow us to replace it // without changing the hook_civicrm_caseTypes interface. $entities = array(); $caseTypes = array(); CRM_Utils_Hook::caseTypes($caseTypes); $proc = new CRM_Case_XMLProcessor(); $caseTypesGroupId = civicrm_api3('OptionGroup', 'getvalue', array('name' => 'case_type', 'return' => 'id')); if (!is_numeric($caseTypesGroupId)) { throw new CRM_Core_Exception("Found invalid ID for OptionGroup (case_type)"); } foreach ($caseTypes as $name => $caseType) { $xml = $proc->retrieve($name); if (!$xml) { throw new CRM_Core_Exception("Failed to load XML for case type (" . $name . ")"); } if (isset($caseType['module'], $caseType['name'], $caseType['file'])) { $entities[] = array('module' => $caseType['module'], 'name' => $caseType['name'], 'entity' => 'OptionValue', 'params' => array('version' => 3, 'name' => $caseType['name'], 'label' => (string) $xml->name, 'description' => (string) $xml->description, 'option_group_id' => $caseTypesGroupId, 'is_reserved' => 1)); } else { throw new CRM_Core_Exception("Invalid case type"); } } return $entities; }
function retrieve($caseType) { require_once 'CRM/Utils/String.php'; require_once 'CRM/Utils/Array.php'; // trim all spaces from $caseType $caseType = str_replace('_', ' ', $caseType); $caseType = CRM_Utils_String::munge(ucwords($caseType), '', 0); if (!CRM_Utils_Array::value($caseType, self::$_xml)) { if (!self::$_xml) { self::$_xml = array(); } // first check custom templates directory $fileName = null; $config = CRM_Core_Config::singleton(); if (isset($config->customTemplateDir) && $config->customTemplateDir) { // check if the file exists in the custom templates directory $fileName = implode(DIRECTORY_SEPARATOR, array($config->customTemplateDir, 'CRM', 'Case', 'xml', 'configuration', "{$caseType}.xml")); } if (!$fileName || !file_exists($fileName)) { // check if file exists locally $fileName = implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), 'xml', 'configuration', "{$caseType}.xml")); if (!file_exists($fileName)) { return false; } } // read xml file $dom = DomDocument::load($fileName); $dom->xinclude(); self::$_xml[$caseType] = simplexml_import_dom($dom); } return self::$_xml[$caseType]; }
/** * Get a list of managed relationship-types by searching CiviCase XML files * * @return array * @see CRM_Utils_Hook::managed * @throws CRM_Core_Exception */ public static function createManagedRelationshipTypes(CRM_Case_XMLRepository $xmlRepo, CRM_Core_ManagedEntities $me) { $result = array(); $p = new CRM_Case_XMLProcessor(); $validRelTypes = $p->allRelationshipTypes(); $relTypes = $xmlRepo->getAllDeclaredRelationshipTypes(); foreach ($relTypes as $relType) { $managed = array('module' => 'civicrm', 'name' => "civicase:rel:{$relType}", 'entity' => 'RelationshipType', 'update' => 'never', 'cleanup' => 'unused', 'params' => array('version' => 3, 'name_a_b' => "{$relType} is", 'name_b_a' => $relType, 'label_a_b' => "{$relType} is", 'label_b_a' => $relType, 'description' => $relType, 'contact_type_a' => 'Individual', 'contact_type_b' => 'Individual', 'contact_sub_type_a' => NULL, 'contact_sub_type_b' => NULL)); // We'll create managed-entity if this record doesn't exist yet // or if we previously decided to manage this record. if (!in_array($relType, $validRelTypes)) { $result[] = $managed; } elseif ($me->get($managed['module'], $managed['name'])) { $result[] = $managed; } } return $result; }
/** * Get a list of managed-entities representing auto-generated case-types * using hook_civicrm_caseTypes. * * @return array * @see CRM_Utils_Hook::managed * @throws CRM_Core_Exception */ public static function createManagedCaseTypes() { $entities = array(); // Use hook_civicrm_caseTypes to build a list of OptionValues // In the long run, we may want more specialized logic for this, but // this design is fairly convenient and will allow us to replace it // without changing the hook_civicrm_caseTypes interface. $caseTypes = array(); CRM_Utils_Hook::caseTypes($caseTypes); $proc = new CRM_Case_XMLProcessor(); foreach ($caseTypes as $name => $caseType) { $xml = $proc->retrieve($name); if (!$xml) { throw new CRM_Core_Exception("Failed to load XML for case type (" . $name . ")"); } if (isset($caseType['module'], $caseType['name'], $caseType['file'])) { $entities[] = array('module' => $caseType['module'], 'name' => $caseType['name'], 'entity' => 'CaseType', 'params' => array('version' => 3, 'name' => $caseType['name'], 'title' => (string) $xml->name, 'description' => (string) $xml->description, 'is_reserved' => 1, 'is_active' => 1, 'weight' => $xml->weight ? $xml->weight : 1)); } else { throw new CRM_Core_Exception("Invalid case type"); } } return $entities; }
protected function execute(InputInterface $input, OutputInterface $output) { // load Civi to get access to civicrm_api_get_function_name $civicrm_api3 = $this->getContainer()->get('civicrm_api3'); if (!$civicrm_api3 || !$civicrm_api3->local) { $output->writeln("Requires access to local CiviCRM source tree. Configure civicrm_api3_conf_path.</error>"); return; } if (!preg_match('/^[A-Z][A-Za-z0-9_ \\.\\-]*$/', $input->getArgument('<Label>'))) { throw new Exception("Label should be valid"); } if (!$input->getArgument('<Name>')) { // $input->setArgument('<Name>', \CRM_Utils_String::munge(ucwords(str_replace('_', ' ', $input->getArgument('<Label>'))), '', 0)); $input->setArgument('<Name>', \CRM_Case_XMLProcessor::mungeCasetype($input->getArgument('<Label>'))); } if (!preg_match('/^[A-Z][A-Za-z0-9]*$/', $input->getArgument('<Name>'))) { throw new Exception("Name should be valid (alphanumeric beginning with uppercase)"); } $ctx = array(); $ctx['type'] = 'module'; $ctx['basedir'] = rtrim(getcwd(), '/'); $ctx['caseTypeLabel'] = $input->getArgument('<Label>'); $ctx['caseTypeName'] = $input->getArgument('<Name>'); $basedir = new Path($ctx['basedir']); $info = new Info($basedir->string('info.xml')); $info->load($ctx); $attrs = $info->get()->attributes(); if ($attrs['type'] != 'module') { $output->writeln('<error>Wrong extension type: ' . $attrs['type'] . '</error>'); return; } $dirs = new Dirs(array($basedir->string('xml', 'case'))); $dirs->save($ctx, $output); $xmlFile = $basedir->string('xml', 'case', $ctx['caseTypeName'] . '.xml'); if (!file_exists($xmlFile)) { $output->writeln(sprintf('<info>Write %s</info>', $xmlFile)); file_put_contents($xmlFile, $this->getContainer()->get('templating')->render('CRMCivixBundle:Code:case-type.xml.php', $ctx)); } else { $output->writeln(sprintf('<error>Skip %s: file already exists</error>', $xmlFile)); } $module = new Module($this->getContainer()->get('templating')); $module->loadInit($ctx); $module->save($ctx, $output); }
function retrieve($caseType) { $caseType = self::mungeCaseType($caseType); if (!CRM_Utils_Array::value($caseType, self::$_xml)) { if (!self::$_xml) { self::$_xml = array(); } // first check custom templates directory $fileName = NULL; $config = CRM_Core_Config::singleton(); if (isset($config->customTemplateDir) && $config->customTemplateDir) { // check if the file exists in the custom templates directory $fileName = implode(DIRECTORY_SEPARATOR, array($config->customTemplateDir, 'CRM', 'Case', 'xml', 'configuration', "{$caseType}.xml")); } if (!$fileName || !file_exists($fileName)) { // check if file exists locally $fileName = implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), 'xml', 'configuration', "{$caseType}.xml")); if (!file_exists($fileName)) { // check if file exists locally $fileName = implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), 'xml', 'configuration.sample', "{$caseType}.xml")); } if (!file_exists($fileName)) { if (self::$_hookCache === NULL) { self::$_hookCache = array(); CRM_Utils_Hook::caseTypes(self::$_hookCache); } if (isset(self::$_hookCache[$caseType], self::$_hookCache[$caseType]['file'])) { $fileName = self::$_hookCache[$caseType]['file']; } } if (!file_exists($fileName)) { return FALSE; } } // read xml file $dom = new DomDocument(); $dom->load($fileName); $dom->xinclude(); self::$_xml[$caseType] = simplexml_import_dom($dom); } return self::$_xml[$caseType]; }
/** * Check that the case-type names don't rely on double-munging. * * @return array<CRM_Utils_Check_Message> * An empty array, or a list of warnings */ public function checkCaseTypeNameConsistency() { $messages = array(); foreach ($this->caseTypeNames as $caseTypeName) { $normalFile = $this->xmlRepo->findXmlFile($caseTypeName); $mungedFile = $this->xmlRepo->findXmlFile(CRM_Case_XMLProcessor::mungeCaseType($caseTypeName)); if ($normalFile && $mungedFile && $normalFile == $mungedFile) { // ok } elseif ($normalFile && $mungedFile) { $messages[] = new CRM_Utils_Check_Message(__FUNCTION__ . $caseTypeName, ts('Case type "%1" has duplicate XML files ("%2" and "%3")', array(1 => $caseTypeName, 2 => $normalFile, 3 => $mungedFile)) . '<br /><a href="' . CRM_Utils_System::getWikiBaseURL() . __FUNCTION__ . '">' . ts('Read more about this warning') . '</a>', ts('CiviCase'), \Psr\Log\LogLevel::WARNING, 'fa-puzzle-piece'); } elseif ($normalFile && !$mungedFile) { // ok } elseif (!$normalFile && $mungedFile) { $messages[] = new CRM_Utils_Check_Message(__FUNCTION__ . $caseTypeName, ts('Case type "%1" corresponds to XML file ("%2") The XML file should be named "%3".', array(1 => $caseTypeName, 2 => $mungedFile, 3 => "{$caseTypeName}.xml")) . '<br /><a href="' . CRM_Utils_System::getWikiBaseURL() . __FUNCTION__ . '">' . ts('Read more about this warning') . '</a>', ts('CiviCase'), \Psr\Log\LogLevel::WARNING, 'fa-puzzle-piece'); } elseif (!$normalFile && !$mungedFile) { // ok -- probably a new or DB-based CaseType } } return $messages; }
/** * Check that the case-type names don't rely on double-munging. * * @return array<CRM_Utils_Check_Message> an empty array, or a list of warnings */ public function checkCaseTypeNameConsistency() { $messages = array(); foreach ($this->caseTypeNames as $caseTypeName) { $normalFile = $this->xmlRepo->findXmlFile($caseTypeName); $mungedFile = $this->xmlRepo->findXmlFile(CRM_Case_XMLProcessor::mungeCaseType($caseTypeName)); if ($normalFile && $mungedFile && $normalFile == $mungedFile) { // ok } elseif ($normalFile && $mungedFile) { $messages[] = new CRM_Utils_Check_Message(__FUNCTION__, ts('Case type "%2" has duplicate XML files ("%3" and "%4").<br /><a href="%1">Read more about this warning</a>', array(1 => CRM_Utils_System::getWikiBaseURL() . __FUNCTION__, 2 => $caseTypeName, 3 => $normalFile, 4 => $mungedFile)), ts('CiviCase')); } elseif ($normalFile && !$mungedFile) { // ok } elseif (!$normalFile && $mungedFile) { $messages[] = new CRM_Utils_Check_Message(__FUNCTION__, ts('Case type "%2" corresponds to XML file ("%3") The XML file should be named "%4".<br /><a href="%1">Read more about this warning</a>', array(1 => CRM_Utils_System::getWikiBaseURL() . __FUNCTION__, 2 => $caseTypeName, 3 => $mungedFile, 4 => "{$caseTypeName}.xml")), ts('CiviCase')); } elseif (!$normalFile && !$mungedFile) { // ok -- probably a new or DB-based CaseType } } return $messages; }
public function setUp() { parent::setUp(); /** @var $hooks \CRM_Utils_Hook_UnitTests */ $hooks = \CRM_Utils_Hook::singleton(); $hooks->setHook('civicrm_caseTypes', array($this, 'hook_caseTypes')); \CRM_Case_XMLRepository::singleton(TRUE); \CRM_Case_XMLProcessor::flushStaticCaches(); // CRM-9404 - set-up is a bit cumbersome but had to put something in place to set up activity types & case types //. Using XML was causing breakage as id numbers were changing over time // & was really hard to troubleshoot as involved truncating option_value table to mitigate this & not leaving DB in a // state where tests could run afterwards without re-loading. $this->caseStatusGroup = $this->callAPISuccess('option_group', 'get', array('name' => 'case_status', 'format.only_id' => 1)); $optionValues = array('Medical evaluation' => 'Medical evaluation', 'Mental health evaluation' => "Mental health evaluation", 'Secure temporary housing' => 'Secure temporary housing', 'Long-term housing plan' => 'Long-term housing plan', 'ADC referral' => 'ADC referral', 'Income and benefits stabilization' => 'Income and benefits stabilization'); foreach ($optionValues as $name => $label) { $activityTypes = $this->callAPISuccess('option_value', 'Create', array('option_group_id' => 2, 'name' => $name, 'label' => $label, 'component_id' => 7)); // store for cleanup $this->optionValues[] = $activityTypes['id']; } // We used to be inconsistent about "HousingSupport" vs "housing_support". // Now, the rule is simply: use the "name" from "civicrm_case_type.name". $this->caseType = 'housing_support'; $this->caseTypeId = 1; $this->tablesToTruncate = array('civicrm_activity', 'civicrm_contact', 'civicrm_custom_group', 'civicrm_custom_field', 'civicrm_case', 'civicrm_case_contact', 'civicrm_case_activity', 'civicrm_case_type', 'civicrm_activity_contact', 'civicrm_managed', 'civicrm_relationship', 'civicrm_relationship_type'); $this->quickCleanup($this->tablesToTruncate); $this->loadAllFixtures(); // enable the default custom templates for the case type xml files $this->customDirectories(array('template_path' => TRUE)); // case is not enabled by default $enableResult = CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase'); $this->assertTrue($enableResult, 'Cannot enable CiviCase in line ' . __LINE__); // create a logged in USER since the code references it for source_contact_id $this->createLoggedInUser(); $session = CRM_Core_Session::singleton(); $this->_loggedInUser = $session->get('userID'); /// note that activityType options are cached by the FULL set of options you pass in // ie. because Activity api includes campaign in it's call cache is not flushed unless // included in this call. Also note flush function doesn't work on this property as it sets to null not empty array CRM_Core_PseudoConstant::activityType(TRUE, TRUE, TRUE, 'name', TRUE); }
function retrieve($caseType) { require_once 'CRM/Utils/String.php'; require_once 'CRM/Utils/Array.php'; // trim all spaces from $caseType $caseType = str_replace('_', ' ', $caseType); $caseType = CRM_Utils_String::munge(ucwords($caseType), '', 0); if (!CRM_Utils_Array::value($caseType, self::$_xml)) { if (!self::$_xml) { self::$_xml = array(); } // ensure that the file exists $fileName = implode(DIRECTORY_SEPARATOR, array(dirname(__FILE__), 'xml', 'configuration', "{$caseType}.xml")); if (!file_exists($fileName)) { return false; } // read xml file $dom = DomDocument::load($fileName); $dom->xinclude(); self::$_xml[$caseType] = simplexml_import_dom($dom); } return self::$_xml[$caseType]; }
/** * (Delegated) Implements hook_civicrm_caseTypes(). * * Find any and return any files matching "xml/case/*.xml" * * Note: This hook only runs in CiviCRM 4.4+. * * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes */ function _api4_civix_civicrm_caseTypes(&$caseTypes) { if (!is_dir(__DIR__ . '/xml/case')) { return; } foreach (_api4_civix_glob(__DIR__ . '/xml/case/*.xml') as $file) { $name = preg_replace('/\\.xml$/', '', basename($file)); if ($name != CRM_Case_XMLProcessor::mungeCaseType($name)) { $errorMessage = sprintf("Case-type file name is malformed (%s vs %s)", $name, CRM_Case_XMLProcessor::mungeCaseType($name)); CRM_Core_Error::fatal($errorMessage); // throw new CRM_Core_Exception($errorMessage); } $caseTypes[$name] = array('module' => 'org.civicrm.api4', 'name' => $name, 'file' => $file); } }
function getCaseReport($clientID, $caseID, $activitySetName, $params, $form) { $template = CRM_Core_Smarty::singleton(); $template->assign('caseId', $caseID); $template->assign('clientID', $clientID); $template->assign('activitySetName', $activitySetName); if (!empty($params['is_redact'])) { $form->_isRedact = TRUE; $template->assign('_isRedact', 'true'); } else { $form->_isRedact = FALSE; $template->assign('_isRedact', 'false'); } // first get all case information $case = $form->caseInfo($clientID, $caseID); $template->assign_by_ref('case', $case); if ($params['include_activities'] == 1) { $template->assign('includeActivities', 'All'); } else { $template->assign('includeActivities', 'Missing activities only'); } $xml = $form->retrieve($case['caseTypeName']); $activitySetNames = CRM_Case_XMLProcessor_Process::activitySets($xml->ActivitySets); $pageTitle = CRM_Utils_Array::value($activitySetName, $activitySetNames); $template->assign('pageTitle', $pageTitle); if ($activitySetName) { $activityTypes = $form->getActivityTypes($xml, $activitySetName); } else { $activityTypes = CRM_Case_XMLProcessor::allActivityTypes(); } if (!$activityTypes) { return FALSE; } // next get activity set Informtion $activitySet = array('label' => $form->getActivitySetLabel($xml, $activitySetName), 'includeActivities' => 'All', 'redact' => 'false'); $template->assign_by_ref('activitySet', $activitySet); //now collect all the information about activities $activities = array(); $form->getActivities($clientID, $caseID, $activityTypes, $activities); $template->assign_by_ref('activities', $activities); // now run the template $contents = $template->fetch('CRM/Case/XMLProcessor/Report.tpl'); return $contents; }
/** * Add the relationship type in the db. * * @param array $params * (reference ) an assoc array of name/value pairs. * @param array $ids * The array that holds all the db ids. * * @return CRM_Contact_DAO_RelationshipType */ public static function add(&$params, &$ids) { //to change name, CRM-3336 if (empty($params['label_a_b']) && !empty($params['name_a_b'])) { $params['label_a_b'] = $params['name_a_b']; } if (empty($params['label_b_a']) && !empty($params['name_b_a'])) { $params['label_b_a'] = $params['name_b_a']; } // set label to name if it's not set - but *only* for // ADD action. CRM-3336 as part from (CRM-3522) if (empty($ids['relationshipType'])) { if (empty($params['name_a_b']) && !empty($params['label_a_b'])) { $params['name_a_b'] = $params['label_a_b']; } if (empty($params['name_b_a']) && !empty($params['label_b_a'])) { $params['name_b_a'] = $params['label_b_a']; } } // action is taken depending upon the mode $relationshipType = new CRM_Contact_DAO_RelationshipType(); $relationshipType->copyValues($params); // if label B to A is blank, insert the value label A to B for it if (!strlen(trim($strName = CRM_Utils_Array::value('name_b_a', $params)))) { $relationshipType->name_b_a = CRM_Utils_Array::value('name_a_b', $params); } if (!strlen(trim($strName = CRM_Utils_Array::value('label_b_a', $params)))) { $relationshipType->label_b_a = CRM_Utils_Array::value('label_a_b', $params); } $relationshipType->id = CRM_Utils_Array::value('relationshipType', $ids); $result = $relationshipType->save(); CRM_Core_PseudoConstant::relationshipType('label', TRUE); CRM_Core_PseudoConstant::relationshipType('name', TRUE); CRM_Case_XMLProcessor::flushStaticCaches(); return $result; }
/** * @param string $caseType * @return SimpleXMLElement|FALSE */ public function retrieveFile($caseType) { $fileName = NULL; $fileXml = NULL; if (CRM_Case_BAO_CaseType::isValidName($caseType)) { // Search for a file based directly on the $caseType name $fileName = $this->findXmlFile($caseType); } // For backward compatibility, also search for double-munged file names // TODO In 4.6 or 5.0, remove support for loading double-munged file names if (!$fileName || !file_exists($fileName)) { $fileName = $this->findXmlFile(CRM_Case_XMLProcessor::mungeCaseType($caseType)); } if ($fileName && file_exists($fileName)) { // read xml file $dom = new DomDocument(); $dom->load($fileName); $dom->xinclude(); $fileXml = simplexml_import_dom($dom); } return $fileXml; }
/** * FIXME: This should not exist */ public static function flushStaticCaches() { self::$activityTypes = NULL; self::$relationshipTypes = NULL; }
/** * (Delegated) Implementation of hook_civicrm_caseTypes * * Find any and return any files matching "xml/case/*.xml" * * Note: This hook only runs in CiviCRM 4.4+. * * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_caseTypes */ function _recurringcontributioncustomsearches_civix_civicrm_caseTypes(&$caseTypes) { if (!is_dir(__DIR__ . '/xml/case')) { return; } foreach (_recurringcontributioncustomsearches_civix_glob(__DIR__ . '/xml/case/*.xml') as $file) { $name = preg_replace('/\\.xml$/', '', basename($file)); if ($name != CRM_Case_XMLProcessor::mungeCaseType($name)) { $errorMessage = sprintf("Case-type file name is malformed (%s vs %s)", $name, CRM_Case_XMLProcessor::mungeCaseType($name)); CRM_Core_Error::fatal($errorMessage); // throw new CRM_Core_Exception($errorMessage); } $caseTypes[$name] = array('module' => 'uk.co.vedaconsulting.module.recurringcontributioncustomsearches', 'name' => $name, 'file' => $file); } }