/** * Adds object $contentObject to the search database. * * @param eZContentObject $contentObject Object to add to search engine * @param bool $commit Whether to commit after adding the object * @return bool True if the operation succeed. */ public function addObject($contentObject, $commit = true) { $contentObjectID = $contentObject->attribute('id'); $currentVersion = $contentObject->currentVersion(); if (!$currentVersion) { $errCurrentVersion = $contentObject->attribute('current_version'); eZDebug::writeError("Failed to fetch \"current version\" ({$errCurrentVersion})" . " of content object (ID: {$contentObjectID})", 'eZSearchEngine'); return false; } $indexArray = array(); $indexArrayOnlyWords = array(); $wordCount = 0; $placement = 0; $previousWord = ''; eZContentObject::recursionProtectionStart(); foreach ($currentVersion->contentObjectAttributes() as $attribute) { $metaData = array(); $classAttribute = $attribute->contentClassAttribute(); if ($classAttribute->attribute("is_searchable") == 1) { // Fetch attribute translations $attributeTranslations = $attribute->fetchAttributeTranslations(); foreach ($attributeTranslations as $translation) { $tmpMetaData = $translation->metaData(); if (!is_array($tmpMetaData)) { $tmpMetaData = array(array('id' => $attribute->attribute('contentclass_attribute_identifier'), 'text' => $tmpMetaData)); } $metaData = array_merge($metaData, $tmpMetaData); } foreach ($metaData as $metaDataPart) { $text = eZSearchEngine::normalizeText(htmlspecialchars($metaDataPart['text'], ENT_NOQUOTES, 'UTF-8'), true); // Split text on whitespace if (is_numeric(trim($text))) { $integerValue = (int) $text; } else { $integerValue = 0; } $wordArray = explode(' ', $text); foreach ($wordArray as $word) { if (trim($word) != "") { // words stored in search index are limited to 150 characters if (strlen($word) > 150) { $word = substr($word, 0, 150); } $indexArray[] = array('Word' => $word, 'ContentClassAttributeID' => $attribute->attribute('contentclassattribute_id'), 'identifier' => $metaDataPart['id'], 'integer_value' => $integerValue); $indexArrayOnlyWords[$word] = 1; $wordCount++; //if we have "www." before word than //treat it as url and add additional entry to the index if (substr(strtolower($word), 0, 4) == 'www.') { $additionalUrlWord = substr($word, 4); $indexArray[] = array('Word' => $additionalUrlWord, 'ContentClassAttributeID' => $attribute->attribute('contentclassattribute_id'), 'identifier' => $metaDataPart['id'], 'integer_value' => $integerValue); $indexArrayOnlyWords[$additionalUrlWord] = 1; $wordCount++; } } } } } } eZContentObject::recursionProtectionEnd(); $wordIDArray = $this->buildWordIDArray(array_keys($indexArrayOnlyWords)); $db = eZDB::instance(); $db->begin(); for ($arrayCount = 0; $arrayCount < $wordCount; $arrayCount += 1000) { $placement = $this->indexWords($contentObject, array_slice($indexArray, $arrayCount, 1000), $wordIDArray, $placement); } $db->commit(); return true; }
/** * Adds object $contentObject to the search database. * * @param eZContentObject $contentObject Object to add to search engine * @param bool $commit Whether to commit after adding the object. If set, run optimize() as well every 1000nd time this function is run. * @return bool True if the operation succeed. */ function addObject( $contentObject, $commit = true ) { // Add all translations to the document list $docList = array(); // Check if we need to index this object after all // Exclude if class identifier is in the exclude list for classes $excludeClasses = $this->FindINI->variable( 'IndexExclude', 'ClassIdentifierList' ); if ( $excludeClasses && in_array( $contentObject->attribute( 'class_identifier' ), $excludeClasses ) ) { return true; } // Get global object values $mainNode = $contentObject->attribute( 'main_node' ); if ( !$mainNode ) { eZDebug::writeError( 'Unable to fetch main node for object: ' . $contentObject->attribute( 'id' ), __METHOD__ ); return false; } $mainNodePathArray = $mainNode->attribute( 'path_array' ); $mainNodeID = $mainNode->attribute( 'node_id' ); // initialize array of parent node path ids, needed for multivalued path field and subtree filters $nodePathArray = array(); //included in $nodePathArray //$pathArray = $mainNode->attribute( 'path_array' ); $currentVersion = $contentObject->currentVersion(); // Get object meta attributes. $metaAttributeValues = self::getMetaAttributesForObject( $contentObject ); // Get node attributes. $nodeAttributeValues = array(); foreach ( $contentObject->attribute( 'assigned_nodes' ) as $contentNode ) { $nodeID = $contentNode->attribute( 'node_id' ); foreach ( eZSolr::nodeAttributes() as $attributeName => $fieldType ) { $nodeAttributeValues[$nodeID][] = array( 'name' => $attributeName, 'value' => $contentNode->attribute( $attributeName ), 'fieldType' => $fieldType ); } $nodePathArray[] = $contentNode->attribute( 'path_array' ); } // Check anonymous user access. if ( $this->FindINI->variable( 'SiteSettings', 'IndexPubliclyAvailable' ) == 'enabled' ) { $anonymousUserID = $this->SiteINI->variable( 'UserSettings', 'AnonymousUserID' ); $currentUserID = eZUser::currentUserID(); $user = eZUser::instance( $anonymousUserID ); eZUser::setCurrentlyLoggedInUser( $user, $anonymousUserID ); $anonymousAccess = $contentObject->attribute( 'can_read' ); $user = eZUser::instance( $currentUserID ); eZUser::setCurrentlyLoggedInUser( $user, $currentUserID ); $anonymousAccess = $anonymousAccess ? 'true' : 'false'; } else { $anonymousAccess = 'false'; } // Load index time boost factors if any //$boostMetaFields = $this->FindINI->variable( "IndexBoost", "MetaField" ); $boostClasses = $this->FindINI->variable( 'IndexBoost', 'Class' ); $boostAttributes = $this->FindINI->variable( 'IndexBoost', 'Attribute' ); $boostDatatypes = $this->FindINI->variable( 'IndexBoost', 'Datatype' ); $reverseRelatedScale = $this->FindINI->variable( 'IndexBoost', 'ReverseRelatedScale' ); // Initialise default doc boost $docBoost = 1.0; $contentClassIdentifier = $contentObject->attribute( 'class_identifier' ); // Just test if the boost factor is defined by checking if it has a numeric value if ( isset( $boostClasses[$contentClassIdentifier] ) && is_numeric( $boostClasses[$contentClassIdentifier] ) ) { $docBoost += $boostClasses[$contentClassIdentifier]; } // Google like boosting, using eZ Publish reverseRelatedObjectCount $reverseRelatedObjectCount = $contentObject->reverseRelatedObjectCount(); $docBoost += $reverseRelatedScale * $reverseRelatedObjectCount; // Create the list of available languages for this version : $availableLanguages = $currentVersion->translationList( false, false ); // Loop over each language version and create an eZSolrDoc for it foreach ( $availableLanguages as $languageCode ) { $doc = new eZSolrDoc( $docBoost ); // Set global unique object ID $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'guid' ), $this->guid( $contentObject, $languageCode ) ); // Set installation identifier $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'installation_id' ), self::installationID() ); $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'installation_url' ), $this->FindINI->variable( 'SiteSettings', 'URLProtocol' ) . $this->SiteINI->variable( 'SiteSettings', 'SiteURL' ) . '/' ); // Set Object attributes $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'name' ), $contentObject->name( false, $languageCode ) ); // Also add value to the "sort_name" field as "name" is unsortable, due to Solr limitation (tokenized field) $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'sort_name' ), $contentObject->name( false, $languageCode ) ); $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'anon_access' ), $anonymousAccess ); $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'language_code' ), $languageCode ); $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'available_language_codes' ), $availableLanguages ); if ( $owner = $contentObject->attribute( 'owner' ) ) { // Set owner name $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'owner_name' ), $owner->name( false, $languageCode ) ); // Set owner group ID foreach ( $owner->attribute( 'parent_nodes' ) as $groupID ) { $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'owner_group_id' ), $groupID ); } } // from eZ Publish 4.1 only: object states // so let's check if the content object has it if ( method_exists( $contentObject, 'stateIDArray' ) ) { $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'object_states' ), $contentObject->stateIDArray() ); } // Set content object meta attribute values. foreach ( $metaAttributeValues as $metaInfo ) { $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfo['name'] ), ezfSolrDocumentFieldBase::preProcessValue( $metaInfo['value'], $metaInfo['fieldType'] ) ); } // Set content node meta attribute values. foreach ( $nodeAttributeValues as $nodeID => $metaInfoArray ) { foreach( $metaInfoArray as $metaInfo) { $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfo['name'] ), ezfSolrDocumentFieldBase::preProcessValue( $metaInfo['value'], $metaInfo['fieldType'] ) ); } } // Main node gets single valued fields for sorting, using a dedicated prefix foreach ( $nodeAttributeValues[$mainNodeID] as $metaInfo ) { $fieldName = 'main_node_' . ezfSolrDocumentFieldBase::generateMetaFieldName( $metaInfo['name'] ); $doc->addField( $fieldName, ezfSolrDocumentFieldBase::preProcessValue( $metaInfo['value'], $metaInfo['fieldType'] ) ); } // Add main url_alias $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'main_url_alias' ), $mainNode->attribute( 'url_alias' ) ); // Add main path_string $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'main_path_string' ), $mainNode->attribute( 'path_string' ) ); // add nodeid of all parent nodes path elements foreach ( $nodePathArray as $pathArray ) { foreach ( $pathArray as $pathNodeID) { $doc->addField( ezfSolrDocumentFieldBase::generateMetaFieldName( 'path' ), $pathNodeID ); } } // Since eZ Fnd 2.3 // cannot call metafield field bame constructor as we are creating multiple fields foreach ( $mainNodePathArray as $key => $pathNodeID ) { $doc->addField( 'meta_main_path_element_' . $key . '_si', $pathNodeID ); } eZContentObject::recursionProtectionStart(); // Loop through all eZContentObjectAttributes and add them to the Solr document. // @since eZ Find 2.3: look for the attribute storage setting $doAttributeStorage = ( ( $this->FindINI->variable( 'IndexOptions', 'EnableSolrAttributeStorage' ) ) === 'true' ) ? true : false; if ( $doAttributeStorage ) { $allAttributeData = array(); } foreach ( $currentVersion->contentObjectAttributes( $languageCode ) as $attribute ) { $metaDataText = ''; $classAttribute = $attribute->contentClassAttribute(); $attributeIdentifier = $classAttribute->attribute( 'identifier' ); $combinedIdentifier = $contentClassIdentifier . '/' . $attributeIdentifier; $boostAttribute = false; if ( isset( $boostAttributes[$attributeIdentifier]) && is_numeric( $boostAttributes[$attributeIdentifier])) { $boostAttribute = $boostAttributes[$attributeIdentifier]; } if ( isset( $boostAttributes[$combinedIdentifier]) && is_numeric( $boostAttributes[$combinedIdentifier])) { $boostAttribute += $boostAttributes[$combinedIdentifier]; } if ( $classAttribute->attribute( 'is_searchable' ) == 1 ) { $documentFieldBase = ezfSolrDocumentFieldBase::getInstance( $attribute ); $this->addFieldBaseToDoc( $documentFieldBase, $doc, $boostAttribute ); } if ( $doAttributeStorage ) { $storageFieldName = ezfSolrStorage::getSolrStorageFieldName( $attributeIdentifier ); $attributeData = ezfSolrStorage::getAttributeData( $attribute ); $allAttributeData['data_map'][$attributeIdentifier] = $attributeData; $doc->addField( $storageFieldName, ezfSolrStorage::serializeData( $attributeData ) ); } } eZContentObject::recursionProtectionEnd(); if ( $doAttributeStorage ) { $doc->addField( 'as_all_bst', ezfSolrStorage::serializeData( $allAttributeData ) ); } $docList[$languageCode] = $doc; } // Since eZFind 2.7: indexhooks $generalPlugins = $this->FindINI->variable( 'IndexPlugins', 'General' ); $classPlugins = $this->FindINI->variable( 'IndexPlugins', 'Class' ); if ( !empty( $generalPlugins ) ) { foreach ( $generalPlugins as $pluginClassString ) { if( !class_exists( $pluginClassString ) ) { eZDebug::writeError( "Unable to find the PHP class '$classname' defined for index time plugins for eZ Find", __METHOD__ ); continue; } $plugin = new $pluginClassString; if ( $plugin instanceof ezfIndexPlugin ) { $plugin->modify( $contentObject, $docList ); } } } if (array_key_exists($contentObject->attribute( 'class_identifier' ), $classPlugins ) ) { $pluginClassString = $classPlugins[$contentObject->attribute( 'class_identifier' )]; if ( class_exists( $pluginClassString ) ) { $plugin = new $pluginClassString; if ($plugin instanceof ezfIndexPlugin) { $plugin->modify( $contentObject, $docList ); } } } $optimize = false; if ( $this->FindINI->variable( 'IndexOptions', 'DisableDirectCommits' ) === 'true' ) { $commit = false; } $commitWithin = 0; if ( $this->FindINI->variable( 'IndexOptions', 'CommitWithin' ) > 0 ) { $commitWithin = $this->FindINI->variable( 'IndexOptions', 'CommitWithin' ); } if ( $commit && ( $this->FindINI->variable( 'IndexOptions', 'OptimizeOnCommit' ) === 'enabled' ) ) { $optimize = true; } if ( $this->UseMultiLanguageCores === true) { $result = true; foreach ( $availableLanguages as $languageCode ) { $languageResult = $this->SolrLanguageShards[$languageCode]->addDocs( array( $docList[$languageCode] ), $commit, $optimize, $commitWithin ); if ( !$languageResult ) { $result = false; } } return $result; } else { return $this->Solr->addDocs( $docList, $commit, $optimize, $commitWithin ); } }
$db->commit(); } elseif ( $storingAllowed ) { if ( !isset( $currentRedirectionURI ) ) $currentRedirectionURI = $Module->redirectionURI( 'content', 'edit', array( $ObjectID, $EditVersion, $EditLanguage ) ); eZContentObject::recursionProtectionStart(); foreach( $contentObjectAttributes as $contentObjectAttribute ) { $object->handleCustomHTTPActions( $contentObjectAttribute, $attributeDataBaseName, $customActionAttributeArray, array( 'module' => $Module, 'current-redirection-uri' => $currentRedirectionURI ) ); $contentObjectAttribute->setContent( $contentObjectAttribute->attribute( 'content' ) ); } eZContentObject::recursionProtectionEnd(); } $invalidNodeAssignmentList = array(); if ( $Module->isCurrentAction( 'Publish' ) ) { $mainFound = false; $assignments = $version->attribute( 'parent_nodes' ); $db = eZDB::instance(); $db->begin(); foreach ( array_keys( $assignments ) as $key ) { // Check that node assignment node exists. if ( !$assignments[$key]->attribute( 'parent_node_obj' ) ) { $validation[ 'placement' ][] = array( 'text' => ezpI18n::tr( 'kernel/content', 'A node in the node assignment list has been deleted.' ) );
/** * test for getData() */ public function testGetData() { $providerArray = array(); #start 1 : the simplest attribute $content1 = "Hello world"; $ezcca1 = new eZContentClassAttribute(array('identifier' => 'title', 'data_type_string' => 'ezstring')); $ezcoa1 = new eZContentObjectAttributeTester(array("data_type_string" => 'ezstring', "id" => 100123, "data_text" => $content1, "contentclass_attribute" => $ezcca1)); $fieldName1 = ezfSolrDocumentFieldBase::getFieldName($ezcca1); $expectedData1 = array($fieldName1 => $content1); $providerArray[] = array($expectedData1, $ezcoa1); #end 1 #start 2 : attribute with subattributes $ezcca2 = new eZContentClassAttribute(array('identifier' => 'dummy', 'data_type_string' => 'dummy_example')); $ezcoa2 = new eZContentObjectAttributeTester(array("data_type_string" => 'dummy_example', "id" => 100124, "contentclass_attribute" => $ezcca2)); $fieldList2 = ezfSolrDocumentFieldBase::getFieldNameList($ezcca2); $expectedData2 = array(); foreach ($fieldList2 as $fieldName) { $expectedData2[$fieldName] = 'DATA_FOR_' . $fieldName; } $fieldName2 = ezfSolrDocumentFieldBase::getFieldName($ezcca2); $providerArray[] = array($expectedData2, $ezcoa2); #end 2 #start 3 : object relations $expectedData3 = array(); $tester3 = new ezfSolrDocumentFieldObjectRelationTester(new eZContentObjectAttribute(array())); $time3 = time(); $image3 = new ezpObject("image", 2); $image3->name = __METHOD__ . $time3; $image3->caption = __METHOD__ . $time3; $imageId3 = $image3->publish(); // $image3->object->clearCache(); $dataMapImage3 = $image3->dataMap; // eZContentObjectAttribute objects, attributes of the related Image $imageName3 = $dataMapImage3['name']; $imageCaption3 = $dataMapImage3['caption']; $article3 = new ezpObject("article", 2); $articleId3 = $article3->publish(); // Create object relation $article3->object->addContentObjectRelation($imageId3, $article3->current_version, 154, eZContentObject::RELATION_ATTRIBUTE); $dataMapArticle3 = $article3->attribute('data_map'); $ezcoa3 = $dataMapArticle3['image']; $ezcoa3->setAttribute('data_int', $imageId3); $ezcoa3->store(); $ezcca3 = $ezcoa3->attribute('contentclass_attribute'); $defaultFieldName3 = ezfSolrDocumentFieldBase::generateAttributeFieldName($ezcca3, ezfSolrDocumentFieldObjectRelation::$subattributesDefinition[ezfSolrDocumentFieldObjectRelation::DEFAULT_SUBATTRIBUTE]); $expectedData3[$defaultFieldName3] = $tester3->getPlainTextRepresentation($ezcoa3); // required to allow another call to metaData() // on $ezcoa3 in getPlainTextRepresentation, called from the getData() method : eZContentObject::recursionProtectionEnd(); $fieldNameImageName3 = ezfSolrDocumentFieldBase::generateSubattributeFieldName($ezcca3, $imageName3->attribute('contentclass_attribute_identifier'), ezfSolrDocumentFieldObjectRelation::getClassAttributeType($imageName3->attribute('contentclass_attribute'))); $expectedData3[$fieldNameImageName3] = trim(implode(' ', array_values(ezfSolrDocumentFieldBase::getInstance($imageName3)->getData())), "\t\r\n "); $fieldNameImageCaption3 = ezfSolrDocumentFieldBase::generateSubattributeFieldName($ezcca3, $imageCaption3->attribute('contentclass_attribute_identifier'), ezfSolrDocumentFieldObjectRelation::getClassAttributeType($imageCaption3->attribute('contentclass_attribute'))); $expectedData3[$fieldNameImageCaption3] = trim(implode(' ', array_values(ezfSolrDocumentFieldBase::getInstance($imageCaption3)->getData())), "\t\r\n "); $image3 = eZContentObject::fetch($imageId3); $metaAttributeValues = eZSolr::getMetaAttributesForObject($image3); foreach ($metaAttributeValues as $metaInfo) { $expectedData3[ezfSolrDocumentFieldBase::generateSubmetaFieldName($metaInfo['name'], $ezcca3)] = ezfSolrDocumentFieldBase::preProcessValue($metaInfo['value'], $metaInfo['fieldType']); } $providerArray[] = array($expectedData3, $ezcoa3); #end 3 // Let's perform the actual testing : foreach ($providerArray as $input) { $expected = $input[0]; $contentObjectAttribute = $input[1]; $instance = ezfSolrDocumentFieldBase::getInstance($contentObjectAttribute); self::assertEquals($expected, $instance->getData()); } }