public function getMatchingArtifacts(PFUser $user, Project $project, array $tracker_ids, Tracker_Hierarchy $hierarchy, Tracker_CrossSearch_Query $query, $excluded_artifact_ids = array()) { $shared_fields = $this->shared_field_factory->getSharedFields($query->getSharedFields()); $semantic_fields = $query->getSemanticCriteria(); $artifacts_info = $this->dao->searchMatchingArtifacts($user, $project->getId(), $query, $tracker_ids, $shared_fields, $semantic_fields, $this->artifact_link_field_ids_for_column_display, $excluded_artifact_ids); return $this->result_sorter->buildTreeWithMissingChildren($user, $artifacts_info, $excluded_artifact_ids); }
public function itIsNotEmptyWhenThereIsASharedFieldSelected() { $shared_fields_criteria = array(1084 => array('values' => array(0 => '1080'))); $query = new Tracker_CrossSearch_Query($shared_fields_criteria, array(), array()); $this->assertFalse($query->isEmpty()); }
/** * Monstro query * * @param User $user * @param unknown_type $group_id * @param Tracker_CrossSearch_Query $query * @param array $tracker_ids * @param array $shared_fields * @param array $semantic_fields * @param array $artifact_link_field_ids_for_column_display * @param array $excluded_artifact_ids */ public function searchMatchingArtifacts(User $user, $group_id, Tracker_CrossSearch_Query $query, array $tracker_ids, array $shared_fields, array $semantic_fields, array $artifact_link_field_ids_for_column_display, array $excluded_artifact_ids = array()) { $report_dao = new Tracker_ReportDao(); $report_dao->logStart(__METHOD__, json_encode(array('user' => $user->getUserName(), 'project' => $group_id, 'query' => $query->toArrayOfDoom(), 'trackers' => array_values($tracker_ids)))); $is_super_user = $user->isSuperUser(); $ugroups = $user->getUgroups($group_id, array()); $quoted_ugroups = $this->da->quoteSmartImplode(',', $ugroups); $quoted_tracker_ids = $this->da->quoteSmartImplode(',', $tracker_ids); $excluded_artifact_ids = $this->da->quoteSmartImplode(',', $excluded_artifact_ids); $shared_fields_constraints = $this->getSharedFieldsSqlFragment($shared_fields); $title_constraint = $this->getTitleSqlFragment($this->getSemanticFieldCriteria($semantic_fields, 'title')); $status_constraint = $this->getStatusSqlFragment($this->getSemanticFieldCriteria($semantic_fields, 'status')); $tracker_constraint = $tracker_ids ? " AND artifact.tracker_id IN ({$quoted_tracker_ids}) " : ""; $artifact_ids_list = $query->listArtifactIds(); $artifact_link_constraints = ''; if (count($artifact_ids_list)) { $artifact_ids_list = $this->da->quoteSmartImplode(',', $artifact_ids_list); $artifacts_fields = $this->getArtifactLinkFields($artifact_ids_list, $is_super_user, $quoted_ugroups); $artifact_link_constraints = $this->getArtifactLinkSearchSqlFragment($artifacts_fields); } $artifact_link_columns_select = $this->getArtifactLinkSelects($artifact_link_field_ids_for_column_display); $artifact_link_columns_join = $this->getArtifactLinkColumns($artifact_link_field_ids_for_column_display, $is_super_user, $quoted_ugroups); $artifact_permissions = $report_dao->getSqlFragmentForArtifactPermissions($user->isSuperUser(), $user->getUgroups($group_id, array())); $artifact_permissions_join = $artifact_permissions['from']; $artifact_permissions_where = $artifact_permissions['where']; $tracker_semantic_title_join = $this->getTrackerSemanticTitleJoin($is_super_user, $quoted_ugroups); $tracker_semantic_status_join = $this->getTrackerSemanticStatusJoin($is_super_user, $quoted_ugroups); $from = " FROM tracker_artifact AS artifact\n INNER JOIN tracker_changeset AS c ON (artifact.last_changeset_id = c.id) \n {$shared_fields_constraints} \n {$artifact_link_constraints} \n {$tracker_semantic_title_join} \n {$tracker_semantic_status_join} \n {$artifact_permissions_join} "; $where = " WHERE 1 {$artifact_permissions_where} {$title_constraint} {$status_constraint} "; $permissions_manager = PermissionsManager::instance(); $tracker_factory = TrackerFactory::instance(); $sqls = array(); foreach ($tracker_ids as $tracker_id) { // {{{ This is a big copy 'n paste from Tracker_Report::getMatchingIdsInDb. // TODO: // instead of building a big query with plenty of unions, // call getMatchingIdsInDb foreach tracker involved in the // crosssearch query. As getMatchingIdsInDb returns the // tuple (artifact_ids, matching_ids) -- where ids are // comma separated --, we will have to do the join in php // by concatenating strings. // Example: // $artifact_ids = $changeset_ids = ''; // foreach ($trackers as $tracker) { // merge($artifact_ids, $changeset_ids, report->getMatchingIdsInDb(..., $tracker, ...)); // } // crosssearch->retrieveColumns($artifact_ids, $changeset_ids) // // And if we are feeling lucky, we can also move the // reportdao->searchMatchingIds in searchdao since it make more sense. // // Possible caveat: // - 1 big sql query full of unions is really slower // than n small queries? $instances = array('artifact_type' => $tracker_id); $ugroups = $user->getUgroups($group_id, $instances); $static_ugroups = $user->getStaticUgroups($group_id); $dynamic_ugroups = $user->getDynamicUgroups($group_id, $instances); $permissions = $permissions_manager->getPermissionsAndUgroupsByObjectid($tracker_id, $ugroups); $subwhere = " {$where} AND artifact.tracker_id = {$tracker_id} "; $tracker = $tracker_factory->getTrackerById($tracker_id); $contributor_field = $tracker->getContributorField(); $contributor_field_id = $contributor_field ? $contributor_field->getId() : null; // }}} $sqls = array_merge($sqls, $report_dao->getSqlFragmentsAccordinglyToTrackerPermissions($user->isSuperUser(), $from, $subwhere, $group_id, $tracker_id, $permissions, $ugroups, $static_ugroups, $dynamic_ugroups, $contributor_field_id)); } array_filter($sqls); if (count($sqls) == 0) { $results = new DataAccessResultEmpty(); } else { $union = implode(' UNION ', $sqls); $sql = "SET SESSION group_concat_max_len = 134217728"; $this->retrieve($sql); $sql = "\n SELECT artifact.id,\n artifact.last_changeset_id,\n CVT.value AS title,\n artifact.tracker_id,\n GROUP_CONCAT(CVAL.artifact_id) AS artifactlinks\n {$artifact_link_columns_select}\n \n FROM tracker_artifact AS artifact\n INNER JOIN tracker_artifact_priority ON (tracker_artifact_priority.curr_id = artifact.id)\n INNER JOIN ( {$union} ) AS R ON (R.id = artifact.id)\n INNER JOIN tracker_changeset AS c ON (R.last_changeset_id = c.id)\n\n -- shared_fields_constraints\n \n -- artifact_link_constraints\n\n {$tracker_semantic_title_join}\n\n LEFT JOIN (\n tracker_changeset_value_artifactlink AS CVAL\n INNER JOIN tracker_changeset_value AS CV2 ON (CV2.id = CVAL.changeset_value_id) \n \n ) ON CV2.changeset_id = artifact.last_changeset_id\n\n {$artifact_link_columns_join}\n -- artifact_permissions_join\n \n WHERE 1\n -- artifact_permissions_where\n {$tracker_constraint}\n -- title_constraint\n -- status_constraint\n "; if ($excluded_artifact_ids != '') { $sql .= "\n AND artifact.id NOT IN ({$excluded_artifact_ids}) "; } $sql .= "\n GROUP BY artifact.id\n ORDER BY tracker_artifact_priority.rank\n "; $results = $this->retrieve($sql); } $nb_matching = count($results); $report_dao->logEnd(__METHOD__, $nb_matching); return $results; }
public function getArtifactLinkCriteria(User $user, Tracker_Report $report, Tracker_CrossSearch_Query $cross_search_query) { $criteria = array(); $allowed_artifact_ids = array(); foreach ($this->planning_trackers as $tracker) { $tracker_id = $tracker->getId(); $tracker_artifacts = Tracker_ArtifactFactory::instance()->getArtifactsByTrackerIdUserCanView($user, $tracker_id); // TODO: far from being perfect, anyway we should not modify query but // we should only use criteria in the whole stack foreach ($tracker_artifacts as $artifact) { $allowed_artifact_ids[$artifact->getId()] = true; } $tracker_artifacts = $cross_search_query->setSelectedArtifacts($tracker_id, $tracker_artifacts); $field = new Tracker_CrossSearch_ArtifactReportField($tracker, $tracker_artifacts); $criteria[] = $this->buildCriteria($report, $field); } $cross_search_query->purgeArtifactIdsNotInList($allowed_artifact_ids); return $criteria; }