*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2015
- * $Id$
- *
*/
class CRM_Core_BAO_Navigation extends CRM_Core_DAO_Navigation {
}
}
+ /**
+ * Rebuild reports menu.
+ *
+ * All Contact reports will become sub-items of 'Contact Reports' and so on.
+ *
+ * @param int $domain_id
+ */
+ public static function rebuildReportsNavigation($domain_id) {
+ $component_to_nav_name = array(
+ 'CiviContact' => 'Contact Reports',
+ 'CiviContribute' => 'Contribution Reports',
+ 'CiviMember' => 'Membership Reports',
+ 'CiviEvent' => 'Event Reports',
+ 'CiviPledge' => 'Pledge Reports',
+ 'CiviGrant' => 'Grant Reports',
+ 'CiviMail' => 'Mailing Reports',
+ 'CiviCampaign' => 'Campaign Reports',
+ );
+
+ // Create or update the top level Reports link.
+ $reports_nav = self::createOrUpdateTopLevelReportsNavItem($domain_id);
+
+ // Get all active report instances grouped by component.
+ $components = self::getAllActiveReportsByComponent($domain_id);
+ foreach ($components as $component_id => $component) {
+ // Create or update the per component reports links.
+ $component_nav_name = $component['name'];
+ if (isset($component_to_nav_name[$component_nav_name])) {
+ $component_nav_name = $component_to_nav_name[$component_nav_name];
+ }
+ $permission = "access {$component['name']}";
+ if ($component['name'] === 'CiviContact') {
+ $permission = "administer CiviCRM";
+ }
+ elseif ($component['name'] === 'CiviCampaign') {
+ $permission = "access CiviReport";
+ }
+ $component_nav = self::createOrUpdateReportNavItem($component_nav_name, 'civicrm/report/list', "compid={$component_id}&reset=1", $reports_nav->id, $permission, $domain_id);
+ foreach ($component['reports'] as $report_id => $report) {
+ // Create or update the report instance links.
+ $report_nav = self::createOrUpdateReportNavItem($report['title'], $report['url'], 'reset=1', $component_nav->id, $report['permission'], $domain_id);
+ // Update the report instance to include the navigation id.
+ $query = "UPDATE civicrm_report_instance SET navigation_id = %1 WHERE id = %2";
+ $params = array(
+ 1 => array($report_nav->id, 'Integer'),
+ 2 => array($report_id, 'Integer'),
+ );
+ CRM_Core_DAO::executeQuery($query, $params);
+ }
+ }
+
+ // Create or update the All Reports link.
+ self::createOrUpdateReportNavItem('All Reports', 'civicrm/report/list', 'reset=1', $reports_nav->id, 'access CiviReport', $domain_id);
+ }
+
+ /**
+ * Create the top level 'Reports' item in the navigation tree.
+ *
+ * @param int $domain_id
+ *
+ * @return bool|\CRM_Core_DAO
+ */
+ static public function createOrUpdateTopLevelReportsNavItem($domain_id) {
+ $id = NULL;
+
+ $dao = new CRM_Core_BAO_Navigation();
+ $dao->name = 'Reports';
+ $dao->domain_id = $domain_id;
+ // The first selectAdd clears it - so that we only retrieve the one field.
+ $dao->selectAdd();
+ $dao->selectAdd('id');
+ if ($dao->find(TRUE)) {
+ $id = $dao->id;
+ }
+
+ $nav = self::createReportNavItem('Reports', NULL, NULL, NULL, 'access CiviReport', $id, $domain_id);
+ return $nav;
+ }
+
+ /**
+ * Retrieve a navigation item using it's url.
+ *
+ * @param string $url
+ * @param array $url_params
+ *
+ * @return bool|\CRM_Core_DAO
+ */
+ public static function getNavItemByUrl($url, $url_params) {
+ $query = "SELECT * FROM civicrm_navigation WHERE url = %1";
+ $params = array(
+ 1 => array("{$url}?{$url_params}", 'String'),
+ );
+ $dao = CRM_Core_DAO::executeQuery($query, $params, TRUE, 'CRM_Core_DAO_Navigation');
+ $dao->fetch();
+ if (isset($dao->id)) {
+ return $dao;
+ }
+ return FALSE;
+ }
+
+ /**
+ * Get all active reports, organised by component.
+ *
+ * @param int $domain_id
+ *
+ * @return array
+ */
+ public static function getAllActiveReportsByComponent($domain_id) {
+ $sql = "
+ SELECT
+ civicrm_report_instance.id, civicrm_report_instance.title, civicrm_report_instance.permission, civicrm_component.name, civicrm_component.id AS component_id
+ FROM
+ civicrm_option_group
+ LEFT JOIN
+ civicrm_option_value ON civicrm_option_value.option_group_id = civicrm_option_group.id AND civicrm_option_group.name = 'report_template'
+ LEFT JOIN
+ civicrm_report_instance ON civicrm_option_value.value = civicrm_report_instance.report_id
+ LEFT JOIN
+ civicrm_component ON civicrm_option_value.component_id = civicrm_component.id
+ WHERE
+ civicrm_option_value.is_active = 1
+ AND
+ civicrm_report_instance.domain_id = %1
+ ORDER BY civicrm_option_value.weight";
+
+ $dao = CRM_Core_DAO::executeQuery($sql, array(
+ 1 => array($domain_id, 'Integer'),
+ ));
+ $rows = array();
+ while ($dao->fetch()) {
+ $component_name = is_null($dao->name) ? 'CiviContact' : $dao->name;
+ $component_id = is_null($dao->component_id) ? 99 : $dao->component_id;
+ $rows[$component_id]['name'] = $component_name;
+ $rows[$component_id]['reports'][$dao->id] = array(
+ 'title' => $dao->title,
+ 'url' => "civicrm/report/instance/{$dao->id}",
+ 'permission' => $dao->permission,
+ );
+ }
+ return $rows;
+ }
+
+ /**
+ * Create or update a navigation item for a report instance.
+ *
+ * The function will check whether create or update is required.
+ *
+ * @param string $name
+ * @param string $url
+ * @param string $url_params
+ * @param int $parent_id
+ * @param string $permission
+ * @param int $domain_id
+ *
+ * @return \CRM_Core_DAO_Navigation
+ */
+ protected static function createOrUpdateReportNavItem($name, $url, $url_params, $parent_id, $permission, $domain_id) {
+ $id = NULL;
+ $existing_nav = CRM_Core_BAO_Navigation::getNavItemByUrl($url, $url_params);
+ if ($existing_nav) {
+ $id = $existing_nav->id;
+ }
+ $nav = self::createReportNavItem($name, $url, $url_params, $parent_id, $permission, $id, $domain_id);
+ return $nav;
+ }
+
+ /**
+ * Create a navigation item for a report instance.
+ *
+ * @param string $name
+ * @param string $url
+ * @param string $url_params
+ * @param int $parent_id
+ * @param string $permission
+ * @param int $id
+ * @param int $domain_id
+ * ID of domain to create item in.
+ *
+ * @return \CRM_Core_DAO_Navigation
+ */
+ public static function createReportNavItem($name, $url, $url_params, $parent_id, $permission, $id, $domain_id) {
+ if ($url !== NULL) {
+ $url = "{$url}?{$url_params}";
+ }
+ $params = array(
+ 'name' => $name,
+ 'label' => ts($name),
+ 'url' => $url,
+ 'parent_id' => $parent_id,
+ 'is_active' => TRUE,
+ 'permission' => array(
+ $permission,
+ ),
+ 'domain_id' => $domain_id,
+ );
+ if ($id !== NULL) {
+ $params['id'] = $id;
+ }
+ $nav = CRM_Core_BAO_Navigation::add($params);
+ return $nav;
+ }
+
/**
* Get cache key.
*
--- /dev/null
+<?php
+require_once 'CiviTest/CiviUnitTestCase.php';
+
+/**
+ * Class CRM_Core_BAO_NavigationTest.
+ */
+class CRM_Core_BAO_NavigationTest extends CiviUnitTestCase {
+
+ /**
+ * Set up data for the test run.
+ *
+ * Here we ensure we are starting from a default report navigation.
+ */
+ public function setUp() {
+ parent::setUp();
+ CRM_Core_BAO_Navigation::rebuildReportsNavigation();
+ }
+
+ /**
+ * Test that a missing report menu link is added by rebuildReportsNavigation.
+ */
+ public function testCreateMissingReportMenuItemLink() {
+ $reportCount = $this->getCountReportInstances();
+ CRM_Core_DAO::executeQuery("DELETE FROM civicrm_navigation WHERE url = 'civicrm/report/instance/1?reset=1'");
+ $this->assertEquals($reportCount - 1, $this->getCountReportInstances());
+ CRM_Core_BAO_Navigation::rebuildReportsNavigation();
+
+ $this->assertEquals($reportCount, $this->getCountReportInstances());
+ $url = 'civicrm/report/instance/1';
+ $url_params = 'reset=1';
+ $new_nav = CRM_Core_BAO_Navigation::getNavItemByUrl($url, $url_params);
+ $this->assertObjectHasAttribute('id', $new_nav);
+ $this->assertNotNull($new_nav->id);
+ }
+
+ /**
+ * Test that a missing report menu link is added by rebuildReportsNavigation.
+ */
+ public function testCreateMissingReportMenuItemLinkViaAPI() {
+ $reportCount = $this->getCountReportInstances();
+ CRM_Core_DAO::executeQuery("DELETE FROM civicrm_navigation WHERE url = 'civicrm/report/instance/1?reset=1'");
+ $this->assertEquals($reportCount - 1, $this->getCountReportInstances());
+ $this->callAPISuccess('Navigation', 'reset', array('for' => 'report'));
+
+ $this->assertEquals($reportCount, $this->getCountReportInstances());
+ $url = 'civicrm/report/instance/1';
+ $url_params = 'reset=1';
+ $new_nav = CRM_Core_BAO_Navigation::getNavItemByUrl($url, $url_params);
+ $this->assertObjectHasAttribute('id', $new_nav);
+ $this->assertNotNull($new_nav->id);
+ }
+
+ /**
+ * Test that an existing report link is rebuilt under is't parent.
+ *
+ * Function tests CRM_Core_BAO_Navigation::rebuildReportsNavigation.
+ */
+ public function testUpdateExistingReportMenuLink() {
+ $url = 'civicrm/report/instance/1';
+ $url_params = 'reset=1';
+ $existing_nav = CRM_Core_BAO_Navigation::getNavItemByUrl($url, $url_params);
+ $this->assertNotEquals(FALSE, $existing_nav);
+ $existing_nav->parent_id = 1;
+ $existing_nav->save();
+ CRM_Core_BAO_Navigation::rebuildReportsNavigation();
+ $parent_url = 'civicrm/report/list';
+ $parent_url_params = 'compid=99&reset=1';
+ $parent_nav = CRM_Core_BAO_Navigation::getNavItemByUrl($parent_url, $parent_url_params);
+ $this->assertNotEquals($parent_nav->id, 1);
+ $changed_existing_nav = new CRM_Core_BAO_Navigation();
+ $changed_existing_nav->id = $existing_nav->id;
+ $changed_existing_nav->find(TRUE);
+ $this->assertEquals($changed_existing_nav->parent_id, $parent_nav->id);
+ }
+
+
+ /**
+ * Test that a navigation item can be retrieved by it's url.
+ */
+ public function testGetNavItemByUrl() {
+ $random_string = substr(sha1(rand()), 0, 7);
+ $name = "Test Menu Link {$random_string}";
+ $url = "civicrm/test/{$random_string}";
+ $url_params = "reset=1";
+ $params = array(
+ 'name' => $name,
+ 'label' => ts($name),
+ 'url' => "{$url}?{$url_params}",
+ 'parent_id' => NULL,
+ 'is_active' => TRUE,
+ 'permission' => array(
+ 'access CiviCRM',
+ ),
+ );
+ CRM_Core_BAO_Navigation::add($params);
+ $new_nav = CRM_Core_BAO_Navigation::getNavItemByUrl($url, $url_params);
+ $this->assertObjectHasAttribute('id', $new_nav);
+ $this->assertNotNull($new_nav->id);
+ $new_nav->delete();
+ }
+
+ /**
+ * Get a count of report instances.
+ *
+ * @return int
+ */
+ protected function getCountReportInstances() {
+ return CRM_Core_DAO::singleValueQuery(
+ "SELECT count(*) FROM civicrm_navigation WHERE url LIKE 'civicrm/report/instance/%'");
+ }
+
+}