diff --git a/classes/ezfezpsolrquerybuilder.php b/classes/ezfezpsolrquerybuilder.php index 4577ada4..03857b3d 100644 --- a/classes/ezfezpsolrquerybuilder.php +++ b/classes/ezfezpsolrquerybuilder.php @@ -438,6 +438,12 @@ public function buildSearch( $searchText, $params = array(), $searchTypes = arra implode( ' ', $docTransformerFields) . ' ' . implode( ' ', $extraFieldsToReturn ); + // WIP locations as child docs of main content + // first add a "parent" filter to the main query + $filterQuery[]='meta_doctype_ms:content'; + // add the child doctransformer + $fieldsToReturnString .= ' ' . '[child parentFilter="meta_doctype_ms:content" childFilter="meta_doctype_ms:location"]'; + if ( ! $asObjects ) { if ( empty( $fieldsToReturn )) diff --git a/classes/ezfindresultnode.php b/classes/ezfindresultnode.php index fafca310..258b84f0 100644 --- a/classes/ezfindresultnode.php +++ b/classes/ezfindresultnode.php @@ -18,15 +18,19 @@ function eZFindResultNode( $rows = array() ) $this->ContentObjectID = $rows['id']; } $this->LocalAttributeValueList = array(); - $this->LocalAttributeNameList = array( 'is_local_installation', - 'name', - 'global_url_alias', - 'published', - 'language_code', - 'highlight', - 'score_percent', - 'elevated' - ); + $this->LocalAttributeNameList = array( + 'is_local_installation', + 'name', + 'global_url_alias', + 'published', + 'language_code', + 'highlight', + 'score_percent', + 'elevated', + //WIP: for now contains raw dump of child docs returned ... ie all nodes that satisfy + // upstream child filter conditions + 'children', + ); } /*! diff --git a/classes/ezsolrdoc.php b/classes/ezsolrdoc.php index 7f7fb5b1..314c25db 100644 --- a/classes/ezsolrdoc.php +++ b/classes/ezsolrdoc.php @@ -22,6 +22,12 @@ class eZSolrDoc */ public $Doc = array(); + /** + * + * @var array of child documents as eZSolrDoc objects! + */ + public $Children = array(); + /** * * @var numeric @@ -105,23 +111,25 @@ public function setFieldBoost ($name, $boost) } } + /** - * Convert current object to XML string * - * @return string XML string. + * @param DOMDocument $domDoc The (usually) empty DOM master document + * @param mixed $inputArray containing the fields, field values and field boosts + * @param Booleam $boost the Lucene overall document boost to apply if any + * @return DOMElement The doc and field structure */ - function docToXML() + public static function createDocElementFromArray( DOMDocument $domDoc, $inputArray = array(), $boost = NULL ) { - $this->DomDoc = new DOMDocument( '1.0', 'utf-8' ); - $this->DomRootElement = $this->DomDoc->createElement( 'doc' ); - $this->DomDoc->appendChild( $this->DomRootElement ); + $docRootElement = $domDoc->createElement( 'doc' ); - if ($this->DocBoost !== null && is_numeric( $this->DocBoost ) ) + if ( $boost !== null && is_numeric( $boost ) ) { - $this->DomRootElement->setAttribute( 'boost', $this->DocBoost ); + $docRootElement->setAttribute( 'boost', $boost ); } - foreach ($this->Doc as $name => $field) { + foreach ( $inputArray as $name => $field ) + { foreach( $field['content'] as $value ) { // $value should never be array. Log the value and the stack trace. @@ -133,19 +141,40 @@ function docToXML() "\nStack trace: " . var_export( $dump, 1 ) ); continue; } - $fieldElement = $this->DomDoc->createElement( 'field' ); - $fieldElement->appendChild( $this->DomDoc->createTextNode( $value ) ); + $fieldElement = $domDoc->createElement( 'field' ); + $fieldElement->appendChild( $domDoc->createTextNode( $value ) ); $fieldElement->setAttribute( 'name', $name ); - if ( $field['boost'] !== null && is_numeric( $field['boost'] ) ) + if ( isset( $field['boost'] ) && is_numeric( $field['boost'] ) ) { $fieldElement->setAttribute( 'boost', $field['boost'] ); } - $this->DomRootElement->appendChild( $fieldElement ); + $docRootElement->appendChild( $fieldElement ); } } + return $docRootElement; + } + /** + * Convert current object to XML string + * + * @return string XML string. + */ + function docToXML() + { + $this->DomDoc = new DOMDocument( '1.0', 'utf-8' ); + $this->DomRootElement = self::createDocElementFromArray( $this->DomDoc, $this->Doc, $this->DocBoost ); + + foreach ( $this->Children as $child ) + { + if ( $child instanceof eZSolrDoc ) + { + $this->DomRootElement->appendChild( self::createDocElementFromArray( $this->DomDoc, $child->Doc ) ); + } + } + + $this->DomDoc->appendChild( $this->DomRootElement ); $rawXML = $this->DomDoc->saveXML( $this->DomRootElement ); //make sure there are no control characters left that could currupt the XML string diff --git a/java/solr/ezp-default/conf/schema.xml b/java/solr/ezp-default/conf/schema.xml index 55f72553..2dde8a79 100644 --- a/java/solr/ezp-default/conf/schema.xml +++ b/java/solr/ezp-default/conf/schema.xml @@ -529,6 +529,7 @@ &customfields; + diff --git a/search/plugins/ezsolr/ezsolr.php b/search/plugins/ezsolr/ezsolr.php index 19c2ae31..425d82e4 100644 --- a/search/plugins/ezsolr/ezsolr.php +++ b/search/plugins/ezsolr/ezsolr.php @@ -99,6 +99,29 @@ static function nodeAttributes() 'view_count' => 'sint' ); } + + /** + * + * @return array additional node attributes which are stored in the nested location child docs + */ + static function additionalNodeAttributes() + { + return array( 'parent_node_id' => 'mstring', + 'main_node_id' => 'mstring', + 'parent_node_id' => 'mstring', + 'contentobject_id' => 'mstring', + 'path_identification_string' => 'mstring', + 'remote_id' => 'mstring', + 'name' => 'mstring', + 'children_count' => 'sint', + 'is_main' => 'boolean', + 'url' => 'mstring', + 'class_identifier' => 'mstring', + 'class_name' => 'mstring', + 'is_container' => 'boolean',); + } + + /** * Get meta attribute Solr document field type * @@ -130,7 +153,8 @@ static function getMetaAttributeType( $name, $context = 'search' ) 'visible_path_string' => 'mstring', 'hidden_path_string' => 'mstring' ), self::metaAttributes(), - self::nodeAttributes() ), + self::nodeAttributes(), + self::additionalNodeattributes() ), 'facet' => array( 'owner_name' => 'string' ), 'filter' => array(), @@ -489,9 +513,18 @@ function addObject( $contentObject, $commit = true, $commitWithin = 0, $softComm $nodeID = $contentNode->attribute( 'node_id' ); foreach ( eZSolr::nodeAttributes() as $attributeName => $fieldType ) { - $nodeAttributeValues[$nodeID][] = array( 'name' => $attributeName, - 'value' => $contentNode->attribute( $attributeName ), - 'fieldType' => $fieldType ); + $nodeAttributeValues[$nodeID][$attributeName] = array( + 'value' => $contentNode->attribute($attributeName), + 'fieldType' => $fieldType); + } + + //WIP additional meta info for locations/nodes + foreach (eZSolr::additionalNodeAttributes() as $attributeName => $fieldType) + { + $additionalAttributeValues[$nodeID][$attributeName] = array ( + 'value' => $contentNode->attribute($attributeName), + 'fieldType' => $fieldType); + } $nodePathArray[] = $contentNode->attribute( 'path_array' ); if ( $contentNode->attribute( 'is_hidden' ) || $contentNode->attribute( 'is_invisible' ) ) @@ -561,6 +594,8 @@ function addObject( $contentObject, $commit = true, $commitWithin = 0, $softComm $doc = new eZSolrDoc( $docBoost ); // Set global unique object ID $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'guid' ), $this->guid( $contentObject, $languageCode ) ); + // WIP: hardcoded fieldname for now + $doc->addField('meta_doctype_ms','content'); // Set installation identifier $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'installation_id' ), self::installationID() ); @@ -604,19 +639,43 @@ function addObject( $contentObject, $commit = true, $commitWithin = 0, $softComm } // Set content node meta attribute values. + // WIP: initial hack, add children docs here as well foreach ( $nodeAttributeValues as $nodeID => $metaInfoArray ) { - foreach( $metaInfoArray as $metaInfo) + $doc->Children[$nodeID] = new eZSolrDoc(); + $doc->Children[$nodeID]->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'guid' ), $this->guid( $contentObject, $languageCode, $nodeID ) ); + // hardcoded field name for now + $doc->Children[$nodeID]->addField('meta_doctype_ms','location'); + + foreach( $metaInfoArray as $metaInfoName => $metaInfo) { - $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfo['name'] ), - ezfSolrDocumentFieldBase::preProcessValue( $metaInfo['value'], $metaInfo['fieldType'] ) ); + $locFieldName = ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfoName ); + $locFieldValue = ezfSolrDocumentFieldBase::preProcessValue( $metaInfo['value'], $metaInfo['fieldType'] ); + $doc->addField( $locFieldName, $locFieldValue ); + $doc->Children[$nodeID]->addField('loc_' . $locFieldName, $locFieldValue); + } + // WIP: add sorting by priority values as a field in the content doc for the respective parent + // location (aka node) ids + } + + //WIP additional meta data to add to the location child docs + foreach ( $additionalAttributeValues as $nodeID => $metaInfoArray ) + { + foreach( $metaInfoArray as $metaInfoName => $metaInfo) + { + $locFieldName = ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfoName ); + $locFieldValue = ezfSolrDocumentFieldBase::preProcessValue( $metaInfo['value'], $metaInfo['fieldType'] ); + $doc->Children[$nodeID]->addField('loc_' . $locFieldName, $locFieldValue); } + // provide data for sorting according to the the fetch content list way, 1 level deep + $doc->addField('loc_priority_for_parent_' . $additionalAttributeValues[$nodeID]['parent_node_id']['value'] . '_i', $nodeAttributeValues[$nodeID]['priority']['value']); + } // Main node gets single valued fields for sorting, using a dedicated prefix - foreach ( $nodeAttributeValues[$mainNodeID] as $metaInfo ) + foreach ( $nodeAttributeValues[$mainNodeID] as $metaInfoName => $metaInfo ) { - $fieldName = 'main_node_' . ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfo['name'] ); + $fieldName = 'main_node_' . ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfoName ); $doc->addField( $fieldName, ezfSolrDocumentFieldBase::preProcessValue( $metaInfo['value'], $metaInfo['fieldType'] ) ); @@ -1220,12 +1279,12 @@ static function installationID() * @param string $languageCode * @return string guid */ - function guid( $contentObject, $languageCode = '' ) + function guid( $contentObject, $languageCode = '', $locationID = '' ) { if ( !$contentObject instanceof eZContentObject ) return md5( self::installationID() . '-' . $contentObject . '-' . $languageCode ); - return md5( self::installationID() . '-' . $contentObject->attribute( 'id' ) . '-' . $languageCode ); + return md5( self::installationID() . '-' . $contentObject->attribute( 'id' ) . '-' . $languageCode . '-' . $locationID ); } /** @@ -1696,6 +1755,7 @@ protected function buildResultObjects( $resultArray, &$searchCount, $asObjects = $emit['highlight'] = isset( $highLights[$doc[ezfSolrDocumentFieldBase::generateMetaFieldName( 'guid' )]] ) ? $highLights[$doc[ezfSolrDocumentFieldBase::generateMetaFieldName( 'guid' )]] : null; $emit['elevated'] = ( isset($doc['[elevated]']) ? $doc['[elevated]'] === true : false ); + $emit['children'] = ( isset( $doc['_childDouments_'] ) ) ? $doc['_childDocuments_'] : NULL; $objectRes[] = $emit; unset( $emit ); continue; @@ -1780,6 +1840,7 @@ protected function buildResultObjects( $resultArray, &$searchCount, $asObjects = $maxScore != 0 ? $resultTree->setAttribute( 'score_percent', (int) ( ( $doc['score'] / $maxScore ) * 100 ) ) : $resultTree->setAttribute( 'score_percent', 100 ); $resultTree->setAttribute( 'language_code', $doc[ezfSolrDocumentFieldBase::generateMetaFieldName( 'language_code' )] ); $resultTree->setAttribute( 'elevated', ( isset($doc['[elevated]']) ? $doc['[elevated]'] === true : false ) ); + $resultTree->setAttribute( 'children', ( isset($doc['_childDocuments_']) ? $doc['_childDocuments_'] : NULL ) ); $objectRes[] = $resultTree; } }