/** * Create policy limitation query. * * @param array $limitation Override the limitation of the user. Same format as the return of eZUser::hasAccessTo() * @param boolean $ignoreVisibility Set to true for the visibility to be ignored * @return string Lucene/Solr query string which can be used as filter query for Solr */ protected function policyLimitationFilterQuery($limitation = null, $ignoreVisibility = null) { $eZFindIni = eZINI::instance('ezfind.ini'); $filterQuery = false; $policies = array(); $pathFieldName = $ignoreVisibility ? eZSolr::getMetaFieldName('path') : eZSolr::getMetaFieldName('visible_path'); if (is_array($limitation)) { if (empty($limitation)) { $limitation['accessWord'] = 'yes'; } } else { $limitation = eZUser::currentUser()->hasAccessTo('content', 'read'); } if (isset($limitation['accessWord'])) { switch ($limitation['accessWord']) { case 'limited': if (isset($limitation['policies'])) { $policies = $limitation['policies']; break; } // break omitted, "limited" without policies == "no" // break omitted, "limited" without policies == "no" case 'no': return ' NOT *:* '; case 'yes': break; default: return false; } } // Add limitations for filter query based on local permissions. $limitationHash = array('Class' => eZSolr::getMetaFieldName('contentclass_id'), 'Section' => eZSolr::getMetaFieldName('section_id'), 'User_Section' => eZSolr::getMetaFieldName('section_id'), 'Subtree' => eZSolr::getMetaFieldName('path_string'), 'User_Subtree' => eZSolr::getMetaFieldName('path_string'), 'Node' => eZSolr::getMetaFieldName('main_node_id'), 'Owner' => eZSolr::getMetaFieldName('owner_id'), 'Group' => eZSolr::getMetaFieldName('owner_group_id'), 'ObjectStates' => eZSolr::getMetaFieldName('object_states')); $filterQueryPolicies = array(); // policies are concatenated with OR foreach ($policies as $limitationList) { // policy limitations are concatenated with AND // except for locations policity limitations, concatenated with OR $filterQueryPolicyLimitations = array(); $policyLimitationsOnLocations = array(); foreach ($limitationList as $limitationType => $limitationValues) { // limitation values of one type in a policy are concatenated with OR $filterQueryPolicyLimitationParts = array(); switch ($limitationType) { case 'User_Subtree': case 'Subtree': foreach ($limitationValues as $limitationValue) { $pathString = trim($limitationValue, '/'); $pathArray = explode('/', $pathString); // we only take the last node ID in the path identification string $subtreeNodeID = array_pop($pathArray); $policyLimitationsOnLocations[] = $pathFieldName . ':' . $subtreeNodeID; if (isset($this->searchPluginInstance->postSearchProcessingData['subtree_limitations'])) { $this->searchPluginInstance->postSearchProcessingData['subtree_limitations'][] = $subtreeNodeID; } else { $this->searchPluginInstance->postSearchProcessingData['subtree_limitations'] = array($subtreeNodeID); } } break; case 'Node': foreach ($limitationValues as $limitationValue) { $pathString = trim($limitationValue, '/'); $pathArray = explode('/', $pathString); // we only take the last node ID in the path identification string $nodeID = array_pop($pathArray); $policyLimitationsOnLocations[] = $limitationHash[$limitationType] . ':' . $nodeID; if (isset($this->searchPluginInstance->postSearchProcessingData['subtree_limitations'])) { $this->searchPluginInstance->postSearchProcessingData['subtree_limitations'][] = $nodeID; } else { $this->searchPluginInstance->postSearchProcessingData['subtree_limitations'] = array($nodeID); } } break; case 'Group': foreach (eZUser::currentUser()->attribute('contentobject')->attribute('parent_nodes') as $groupID) { $filterQueryPolicyLimitationParts[] = $limitationHash[$limitationType] . ':' . $groupID; } break; case 'Owner': $filterQueryPolicyLimitationParts[] = $limitationHash[$limitationType] . ':' . eZUser::currentUser()->attribute('contentobject_id'); break; case 'Class': case 'Section': case 'User_Section': foreach ($limitationValues as $limitationValue) { $filterQueryPolicyLimitationParts[] = $limitationHash[$limitationType] . ':' . $limitationValue; } break; default: //hacky, object state limitations reference the state group name in their //limitation //hence the following match on substring if (strpos($limitationType, 'StateGroup') !== false) { foreach ($limitationValues as $limitationValue) { $filterQueryPolicyLimitationParts[] = $limitationHash['ObjectStates'] . ':' . $limitationValue; } } else { eZDebug::writeDebug($limitationType, __METHOD__ . ' unknown limitation type: ' . $limitationType); continue; } } if (!empty($filterQueryPolicyLimitationParts)) { $filterQueryPolicyLimitations[] = '( ' . implode(' OR ', $filterQueryPolicyLimitationParts) . ' )'; } } // Policy limitations on locations (node and/or subtree) need to be concatenated with OR // unlike the other types of limitation if (!empty($policyLimitationsOnLocations)) { $filterQueryPolicyLimitations[] = '( ' . implode(' OR ', $policyLimitationsOnLocations) . ')'; } if (!empty($filterQueryPolicyLimitations)) { $filterQueryPolicies[] = '( ' . implode(' AND ', $filterQueryPolicyLimitations) . ')'; } } if (!empty($filterQueryPolicies)) { $filterQuery = implode(' OR ', $filterQueryPolicies); } // Add limitations for allowing search of other installations. $anonymousPart = ''; if ($eZFindIni->variable('SiteSettings', 'SearchOtherInstallations') == 'enabled') { $anonymousPart = ' OR ' . eZSolr::getMetaFieldName('anon_access') . ':true '; } if (!empty($filterQuery)) { $filterQuery = '((' . eZSolr::getMetaFieldName('installation_id') . ':' . eZSolr::installationID() . ' AND (' . $filterQuery . ')) ' . $anonymousPart . ' )'; } else { $filterQuery = '(' . eZSolr::getMetaFieldName('installation_id') . ':' . eZSolr::installationID() . $anonymousPart . ')'; } // Add ignore visibility condition, either explicitely set to boolean false or not specified if ($ignoreVisibility === false || $ignoreVisibility === null) { $filterQuery .= ' AND ' . eZSolr::getMetaFieldName('is_invisible') . ':false'; } eZDebugSetting::writeDebug('extension-ezfind-query', $filterQuery, __METHOD__); return $filterQuery; }
/** * Get attribute value * * @param string Attribute name * * @return mixed Attribute value. null if attribute does not exist. */ public function attribute($attr) { switch ($attr) { case 'responseHeader': return $this->ResultArray['responseHeader']; break; case 'hasError': return !empty($this->ResultArray['error']); break; case 'error': if (!empty($this->ResultArray['error'])) { return $this->ResultArray['error']; } break; case 'facet_queries': if (!empty($this->FacetQueries)) { return $this->FacetQueries; } // If the facets count is empty, an error has occured. if (empty($this->ResultArray['facet_counts'])) { return null; } $facetArray = array(); foreach ($this->ResultArray['facet_counts']['facet_queries'] as $query => $count) { list($field, $fieldValue) = explode(':', $query); $fieldInfo = array('field' => $field, 'count' => $count, 'queryLimit' => $query, 'fieldValue' => $fieldValue); $facetArray[] = $fieldInfo; } $this->FacetQueries = $facetArray; return $this->FacetQueries; break; case 'facet_fields': if (!empty($this->FacetFields)) { return $this->FacetFields; } // If the facets count is empty, an error has occured. if (empty($this->ResultArray['facet_counts'])) { return null; } $facetArray = array(); foreach ($this->ResultArray['facet_counts']['facet_fields'] as $field => $facetField) { switch ($field) { // class facet field case eZSolr::getMetaFieldName('contentclass_id'): $fieldInfo = array('field' => 'class', 'count' => count($facetField), 'nameList' => array(), 'queryLimit' => array(), 'fieldList' => array(), 'countList' => array()); foreach ($facetField as $contentClassID => $count) { if ($contentClass = eZContentClass::fetch($contentClassID)) { $fieldInfo['nameList'][$contentClassID] = $contentClass->attribute('name'); $fieldInfo['queryLimit'][$contentClassID] = 'contentclass_id:' . $contentClassID; $fieldInfo['countList'][$contentClassID] = $count; $fieldInfo['fieldList'][$contentClassID] = 'contentclass_id'; } else { eZDebug::writeWarning('Could not fetch eZContentClass: ' . $contentClassID, __METHOD__); } } $facetArray[] = $fieldInfo; break; // instalaltion facet field // instalaltion facet field case eZSolr::getMetaFieldName('installation_id'): $findINI = eZINI::instance('ezfind.ini'); $siteNameMapList = $findINI->variable('FacetSettings', 'SiteNameList'); $fieldInfo = array('field' => 'installation', 'count' => count($facetField), 'nameList' => array(), 'queryLimit' => array(), 'fieldList' => array(), 'countList' => array()); foreach ($facetField as $installationID => $count) { $fieldInfo['nameList'][$installationID] = isset($siteNameMapList[$installationID]) ? $siteNameMapList[$installationID] : $installationID; $fieldInfo['queryLimit'][$installationID] = 'installation_id:' . $installationID; $fieldInfo['countList'][$installationID] = $count; $fieldInfo['fieldList'][$installationID] = 'installation_id'; } $facetArray[] = $fieldInfo; break; // author facet field // author facet field case eZSolr::getMetaFieldName('owner_id'): $fieldInfo = array('field' => 'author', 'count' => count($facetField), 'nameList' => array(), 'queryLimit' => array(), 'fieldList' => array(), 'countList' => array()); foreach ($facetField as $ownerID => $count) { if ($owner = eZContentObject::fetch($ownerID)) { $fieldInfo['nameList'][$ownerID] = $owner->attribute('name'); $fieldInfo['queryLimit'][$ownerID] = 'owner_id:' . $ownerID; $fieldInfo['countList'][$ownerID] = $count; $fieldInfo['fieldList'][$ownerID] = 'owner_id'; } else { eZDebug::writeWarning('Could not fetch owner ( eZContentObject ): ' . $ownerID, __METHOD__); } } $facetArray[] = $fieldInfo; break; // translation facet field // translation facet field case eZSolr::getMetaFieldName('language_code'): $fieldInfo = array('field' => 'translation', 'count' => count($facetField), 'nameList' => array(), 'queryLimit' => array(), 'fieldList' => array(), 'countList' => array()); foreach ($facetField as $languageCode => $count) { $fieldInfo['nameList'][$languageCode] = $languageCode; $fieldInfo['queryLimit'][$languageCode] = 'language_code:' . $languageCode; $fieldInfo['fieldList'][$languageCode] = 'language_code'; $fieldInfo['countList'][$languageCode] = $count; } $facetArray[] = $fieldInfo; break; default: $fieldInfo = array('field' => $attr, 'count' => count($facetField), 'queryLimit' => array(), 'fieldList' => array(), 'nameList' => array(), 'countList' => array()); foreach ($facetField as $value => $count) { $fieldInfo['nameList'][$value] = $value; $fieldInfo['fieldList'][$value] = $field; $fieldInfo['queryLimit'][$value] = $field . ':' . $value; $fieldInfo['countList'][$value] = $count; } $facetArray[] = $fieldInfo; break; } } $this->FacetFields = $facetArray; return $this->FacetFields; break; case 'engine': return eZSolr::engineText(); break; //may or may not be active, so returns false if not present //may or may not be active, so returns false if not present case 'spellcheck': if (isset($this->ResultArray['spellcheck']) && $this->ResultArray['spellcheck']['suggestions'] > 0) { return $this->ResultArray['spellcheck']['suggestions']; } else { return false; } break; case 'spellcheck_collation': if (isset($this->ResultArray['spellcheck']['suggestions']['collation'])) { // work around border case if 'collation' is searched for but does not exist in the spell check index // the collation string is the last element of the suggestions array return end($this->ResultArray['spellcheck']['suggestions']); } else { return false; } break; //only relevant for MoreLikeThis queries //only relevant for MoreLikeThis queries case 'interestingTerms': if (isset($this->ResultArray['interestingTerms'])) { return $this->ResultArray['interestingTerms']; } else { return false; } break; case 'facet_dates': if (isset($this->ResultArray['facet_dates'])) { return $this->ResultArray['facet_dates']; } else { return false; } break; case 'facet_ranges': if (isset($this->ResultArray['facet_counts']['facet_ranges'])) { return $this->ResultArray['facet_counts']['facet_ranges']; } else { return false; } break; case 'clusters': if (isset($this->ResultArray['clusters'])) { return $this->ResultArray['clusters']; } else { return false; } break; default: break; } return null; }
public function buildFetch(OCClassSearchFormFetcher $fetcher, $requestValue, &$filters) { $bounds = OCClassSearchFormPublishedFieldBounds::fromString($this->attributes['value']); $filters[] = eZSolr::getMetaFieldName('published') . ':[' . $bounds->attribute('start_solr') . ' TO ' . $bounds->attribute('end_solr') . ']'; $fetcher->addFetchField(array('name' => $this->attributes['label'], 'value' => $bounds->humanString(), 'remove_view_parameters' => $fetcher->getViewParametersString(array('publish_date')))); }
/** * Get solr field name, from base name. The base name may either be a * meta-data name, or an eZ Publish content class attribute, specified by * <class identifier>/<attribute identifier>[/<option>] * * @param string $baseName Base field name. * @param boolean $includingClassID conditions the structure of the answer. See return value explanation. * @param $context is introduced in ez find 2.2 to allow for more optimal sorting, faceting, filtering * * @return mixed Internal base name. Returns null if no valid base name was provided. * If $includingClassID is true, an associative array will be returned, as shown below : * <code> * array( 'fieldName' => 'attr_title_t', * 'contentClassId' => 16 ); * </code> */ static function getFieldName( $baseName, $includingClassID = false, $context = 'search' ) { // If the base name is a meta field, get the correct field name. if ( eZSolr::hasMetaAttributeType( $baseName, $context ) ) { return eZSolr::getMetaFieldName( $baseName, $context ); } else { // Get class and attribute identifiers + optional option. $subattribute = null; $fieldDef = explode( '/', $baseName ); // Check if content class attribute ID is provided. if ( is_numeric( $fieldDef[0] ) ) { if ( count( $fieldDef ) == 1 ) { $contentClassAttributeID = $fieldDef[0]; } else if ( count( $fieldDef ) == 2 ) { list( $contentClassAttributeID, $subattribute ) = $fieldDef; } } else { switch( count( $fieldDef ) ) { case 1: { // Return fieldname as is. return $baseName; } break; case 2: { // Field def contains class indentifier and class attribute identifier. list( $classIdentifier, $attributeIdentifier ) = $fieldDef; } break; case 3: { // Field def contains class indentifier, class attribute identifier and optional specification. list( $classIdentifier, $attributeIdentifier, $subattribute ) = $fieldDef; } break; } $contentClassAttributeID = eZContentObjectTreeNode::classAttributeIDByIdentifier( $classIdentifier . '/' . $attributeIdentifier ); } if ( !$contentClassAttributeID ) { eZDebug::writeNotice( 'Could not get content class from base name: ' . $baseName, __METHOD__ ); return null; } $contentClassAttribute = eZContentClassAttribute::fetch( $contentClassAttributeID ); $fieldName = ezfSolrDocumentFieldBase::getFieldName( $contentClassAttribute, $subattribute, $context ); if ( $includingClassID ) { return array( 'fieldName' => $fieldName, 'contentClassId' => $contentClassAttribute->attribute( 'contentclass_id' ) ); } else return $fieldName; } }
/** * Returns autocomplete suggestions for given params * * @param mixed $args * @return array */ public static function autocomplete($args) { $result = array(); $findINI = eZINI::instance('ezfind.ini'); // Only make calls if explicitely enabled if ($findINI->hasVariable('AutoCompleteSettings', 'AutoComplete') && $findINI->variable('AutoCompleteSettings', 'AutoComplete') === 'enabled') { $solrINI = eZINI::instance('solr.ini'); $siteINI = eZINI::instance(); $currentLanguage = $siteINI->variable('RegionalSettings', 'ContentObjectLocale'); $input = isset($args[0]) ? mb_strtolower($args[0], 'UTF-8') : null; $limit = isset($args[1]) ? (int) $args[1] : (int) $findINI->variable('AutoCompleteSettings', 'Limit'); $facetField = $findINI->variable('AutoCompleteSettings', 'FacetField'); $facetMethod = $findINI->variable('AutoCompleteSettings', 'FacetMethod'); $params = array('q' => '*:*', 'rows' => 0, 'json.nl' => 'arrarr', 'facet' => 'true', 'facet.field' => $facetField, 'facet.prefix' => $input, 'facet.limit' => $limit, 'facet.method' => $facetMethod, 'facet.mincount' => 1); if ($findINI->variable('LanguageSearch', 'MultiCore') == 'enabled') { $languageMapping = $findINI->variable('LanguageSearch', 'LanguagesCoresMap'); $shardMapping = $solrINI->variable('SolrBase', 'Shards'); $fullSolrURI = $shardMapping[$languageMapping[$currentLanguage]]; } else { $fullSolrURI = $solrINI->variable('SolrBase', 'SearchServerURI'); // Autocomplete search should be done in current language and fallback languages $validLanguages = array_unique(array_merge($siteINI->variable('RegionalSettings', 'SiteLanguageList'), array($currentLanguage))); $params['fq'] = 'meta_language_code_ms:(' . implode(' OR ', $validLanguages) . ')'; } //build the query part for the subtree limitation if (isset($args[2]) && (int) $args[2]) { if (isset($params['fq']) && $params['fq']) { $params['fq'] .= ' AND '; } $params['fq'] .= eZSolr::getMetaFieldName('path') . ':' . (int) $args[2]; } //build the query part for the class limitation if (isset($args[3]) && $args[3]) { if (isset($params['fq']) && $params['fq']) { $params['fq'] .= ' AND '; } $classes = explode(',', $args[3]); $classQueryParts = array(); foreach ($classes as $class) { if (!is_numeric($class)) { if ($class = eZContentClass::fetchByIdentifier($class)) { $classQueryParts[] = eZSolr::getMetaFieldName('contentclass_id') . ':' . $class->attribute('id'); } } else { $classQueryParts[] = eZSolr::getMetaFieldName('contentclass_id') . ':' . $class; } } $classQueryParts = implode(' OR ', $classQueryParts); $params['fq'] .= '(' . $classQueryParts . ')'; } $solrBase = new eZSolrBase($fullSolrURI); $result = $solrBase->rawSolrRequest('/select', $params, 'json'); return $result['facet_counts']['facet_fields'][$facetField]; } else { // not enabled, just return an empty array return array(); } }