function unLock(eZContentObject $object) { $filterConds = array('action' => 'creating_translation', 'param' => $object->attribute('id')); $rows = eZPersistentObject::fetchObjectList(eZPendingActions::definition(), null, $filterConds); foreach ($rows as $row) { $row->remove(); } }
/** * @param int $nodeID * @param string $action */ public function updateNodeVisibility( $nodeID, $action ) { $node = eZContentObjectTreeNode::fetch( $nodeID ); eZContentOperationCollection::registerSearchObject($node->attribute( 'contentobject_id' )); if ( $node->childrenCount( false ) ) { $pendingAction = new eZPendingActions( array( 'action' => self::PENDING_ACTION_INDEX_SUBTREE, 'created' => time(), 'param' => $nodeID ) ); $pendingAction->store(); } }
/** * Deletes a content object, or a list of content objects * * @param array $deleteIDArray * @param bool $moveToTrash * * @return array An array with operation status, always true */ public static function deleteObject($deleteIDArray, $moveToTrash = false) { $ini = eZINI::instance(); $delayedIndexingValue = $ini->variable('SearchSettings', 'DelayedIndexing'); if ($delayedIndexingValue === 'enabled' || $delayedIndexingValue === 'classbased') { $pendingActionsToDelete = array(); $classList = $ini->variable('SearchSettings', 'DelayedIndexingClassList'); // Will be used below if DelayedIndexing is classbased $assignedNodesByObject = array(); $nodesToDeleteByObject = array(); $aNodes = eZContentObjectTreeNode::fetch($deleteIDArray); if (!is_array($aNodes)) { $aNodes = array($aNodes); } foreach ($aNodes as $node) { $object = $node->object(); $objectID = $object->attribute('id'); $assignedNodes = $object->attribute('assigned_nodes'); // Only delete pending action if this is the last object's node that is requested for deletion // But $deleteIDArray can also contain all the object's node (mainly if this method is called programmatically) // So if this is not the last node, then store its id in a temp array // This temp array will then be compared to the whole object's assigned nodes array if (count($assignedNodes) > 1) { // $assignedNodesByObject will be used as a referent to check if we want to delete all lasting nodes if (!isset($assignedNodesByObject[$objectID])) { $assignedNodesByObject[$objectID] = array(); foreach ($assignedNodes as $assignedNode) { $assignedNodesByObject[$objectID][] = $assignedNode->attribute('node_id'); } } // Store the node assignment we want to delete // Then compare the array to the referent node assignment array $nodesToDeleteByObject[$objectID][] = $node->attribute('node_id'); $diff = array_diff($assignedNodesByObject[$objectID], $nodesToDeleteByObject[$objectID]); if (!empty($diff)) { continue; } } if ($delayedIndexingValue !== 'classbased' || is_array($classList) && in_array($object->attribute('class_identifier'), $classList)) { $pendingActionsToDelete[] = $objectID; } } if (!empty($pendingActionsToDelete)) { $filterConds = array('param' => array($pendingActionsToDelete)); eZPendingActions::removeByAction('index_object', $filterConds); } } eZContentObjectTreeNode::removeSubtrees($deleteIDArray, $moveToTrash); return array('status' => true); }
/** * Test for eZPendingActions::removeByAction() */ public function testRemoveByAction() { // Insert several fixtures at one time. Can't use @dataProvider to do that $fixtures = $this->providerForTestFecthByAction(); foreach ($fixtures as $fixture) { $this->insertPendingAction($fixture[0], $fixture[1], $fixture[2]); } eZPendingActions::removeByAction('test'); $res = eZPendingActions::fetchByAction('test'); $this->assertTrue(empty($res)); }
/** * Adds a "pending clear cache" action if ViewCaching is disabled. * This method should be called at publish time. * Cache should then be cleared by a cronjob * @return void */ public function addPendingClearCacheIfNeeded() { if (eZINI::instance()->variable('ContentSettings', 'ViewCaching') === 'disabled') { $rowPending = array('action' => self::ACTION_CLEAR_CACHE, 'created' => time(), 'param' => $this->contentObject->attribute('id')); $pendingItem = new eZPendingActions($rowPending); $pendingItem->store(); } }
/** * Update index when node's visibility is modified. * * If the node has children, they will be also re-indexed, but this action is deferred to ezfindexsubtree cronjob. * * @param int $nodeID * @param string $action */ public function updateNodeVisibility($nodeID, $action) { $node = eZContentObjectTreeNode::fetch($nodeID); eZContentOperationCollection::registerSearchObject($node->attribute('contentobject_id')); $params = array('Depth' => 1, 'DepthOperator' => 'eq', 'Limitation' => array(), 'IgnoreVisibility' => true); if ($node->subTreeCount($params) > 0) { $pendingAction = new eZPendingActions(array('action' => 'index_subtree', 'created' => time(), 'param' => $nodeID)); $pendingAction->store(); } }
$nodeID = $module->actionParameter( 'NodeID' ); $languageCode = $module->actionParameter( 'LanguageCode' ); $viewMode = 'full'; if ( !$module->hasActionParameter( 'ViewMode' ) ) { $viewMode = $module->actionParameter( 'ViewMode' ); } if ( $module->isCurrentAction( 'IndexObject' ) || $module->isCurrentAction( 'IndexSubtree' )) { eZContentOperationCollection::registerSearchObject( $objectID ); } if ( $module->isCurrentAction( 'IndexSubtree' ) ) { $pendingAction = new eZPendingActions( array( 'action' => eZSolr::PENDING_ACTION_INDEX_SUBTREE, 'created' => time(), 'param' => $nodeID ) ); $pendingAction->store(); } if ( $module->isCurrentAction( 'RemoveObject' ) ) { $object = eZContentObject::fetch($objectID); eZSearch::removeObject($object, true); } return $module->redirect( 'content', 'view', array( $viewMode, $nodeID, $languageCode ) );
$entries = eZPendingActions::fetchByAction(eZSolr::PENDING_ACTION_INDEX_SUBTREE); if (!empty($entries)) { $parentNodeIDList = array(); foreach ($entries as $entry) { $parentNodeID = $entry->attribute('param'); $parentNodeIDList[] = (int) $parentNodeID; $offset = 0; while (true) { $nodes = eZContentObjectTreeNode::subTreeByNodeID(array('IgnoreVisibility' => true, 'Offset' => $offset, 'Limit' => $limit, 'Limitation' => array()), $parentNodeID); if (!empty($nodes) && is_array($nodes)) { foreach ($nodes as $node) { ++$offset; $cli->output("\tIndexing object ID #{$node->attribute('contentobject_id')}"); // delay commits with passing false for $commit parameter $eZSolr->addObject($node->attribute('object'), false); } // finish up with commit $eZSolr->commit(); // clear object cache to conserver memory eZContentObject::clearCache(); } else { break; // No valid nodes } } } eZPendingActions::removeByAction(eZSolr::PENDING_ACTION_INDEX_SUBTREE, array('param' => array($parentNodeIDList))); } if (!$isQuiet) { $cli->output("Done"); }
/** * Same test as {@link self::testRemovePendingSearchSeveralNodesForObject()}, with not all nodes removed * Use case * -------- * 1. If all nodes are removed, pending action must also be removed * 2. If NOT all nodes are removed (at least one node remaining for object), pending action must NOT be removed (case tested here) * * @group issue_17932 */ public function testRemovePendingSearchNotAllNodesRemoved() { $this->folder->addNode( 43 ); $folderObjectID = $this->folder->object->attribute( 'id' ); $aNodeID = array( $this->folder->nodes[0]->attribute( 'node_id' ) ); // Only delete the first node eZContentOperationCollection::deleteObject( $aNodeID ); $filterConds = array( 'action' => 'index_object', 'param' => $folderObjectID ); $pendingCount = eZPersistentObject::count( eZPendingActions::definition(), $filterConds ); self::assertGreaterThan( 0, $pendingCount, "eZContentOperationCollection::deleteObject() must remove pending action for object #$folderObjectID as all nodes have been removed" ); }
$entries = eZPendingActions::fetchByAction('index_subtree'); if (!empty($entries)) { $parentNodeIDList = array(); foreach ($entries as $entry) { $parentNodeID = $entry->attribute('param'); $parentNodeIDList[] = (int) $parentNodeID; $offset = 0; while (true) { $nodes = eZContentObjectTreeNode::subTreeByNodeID(array('IgnoreVisibility' => true, 'Offset' => $offset, 'Limit' => $limit, 'Limitation' => array()), $parentNodeID); if (!empty($nodes) && is_array($nodes)) { foreach ($nodes as $node) { ++$offset; $cli->output("\tIndexing object ID #{$node->attribute('contentobject_id')}"); // delay commits with passing false for $commit parameter $searchEngine->addObject($node->attribute('object'), false); } // finish up with commit $searchEngine->commit(); // clear object cache to conserve memory eZContentObject::clearCache(); } else { break; // No valid nodes } } } eZPendingActions::removeByAction('index_subtree', array('param' => array($parentNodeIDList))); } if (!$isQuiet) { $cli->output("Done"); }
/** * Clears view cache for imported content objects. * ObjectIDs are stored in 'ezpending_actions' table, with {@link SQLIContent::ACTION_CLEAR_CACHE} action */ public static function viewCacheClear() { $db = eZDB::instance(); $isCli = isset($_SERVER['argv']); $output = null; $progressBar = null; $i = 0; $conds = array('action' => SQLIContent::ACTION_CLEAR_CACHE); $limit = array('offset' => 0, 'length' => 50); $count = (int) eZPersistentObject::count(eZPendingActions::definition(), $conds); if ($isCli && $count > 0) { // Progress bar implementation $output = new ezcConsoleOutput(); $output->outputLine('Starting to clear view cache for imported objects...'); $progressBarOptions = array('emptyChar' => ' ', 'barChar' => '='); $progressBar = new ezcConsoleProgressbar($output, $count, $progressBarOptions); $progressBar->start(); } /* * To avoid fatal errors due to memory exhaustion, pending actions are fetched by packets */ do { $aObjectsToClear = eZPendingActions::fetchObjectList(eZPendingActions::definition(), null, $conds, null, $limit); $jMax = count($aObjectsToClear); if ($jMax > 0) { for ($j = 0; $j < $jMax; ++$j) { if ($isCli) { $progressBar->advance(); } $db->begin(); eZContentCacheManager::clearContentCacheIfNeeded((int) $aObjectsToClear[$j]->attribute('param')); $aObjectsToClear[$j]->remove(); $db->commit(); $i++; } } unset($aObjectsToClear); eZContentObject::clearCache(); if (eZINI::instance('site.ini')->variable('ContentSettings', 'StaticCache') == 'enabled') { $optionArray = array('iniFile' => 'site.ini', 'iniSection' => 'ContentSettings', 'iniVariable' => 'StaticCacheHandler'); $options = new ezpExtensionOptions($optionArray); $staticCacheHandler = eZExtension::getHandlerClass($options); $staticCacheHandler::executeActions(); } } while ($i < $count); if ($isCli && $count > 0) { $progressBar->finish(); $output->outputLine(); } }
/** * @param int $remoteNodeID * @param int $localParentNodeID * * @return eZContentObject * @throws Exception */ public function import($remoteNodeID, $localParentNodeID) { if (!class_exists('OCOpenDataApiNode')) { throw new Exception("Libreria OCOpenDataApiNode non trovata"); } $apiNodeUrl = rtrim($this->attributes['definition']['Url'], '/') . '/api/opendata/v1/content/node/' . $remoteNodeID; $remoteApiNode = OCOpenDataApiNode::fromLink($apiNodeUrl); if (!$remoteApiNode instanceof OCOpenDataApiNode) { throw new Exception("Url remoto \"{$apiNodeUrl}\" non raggiungibile"); } $newObject = $remoteApiNode->createContentObject($localParentNodeID); if (!$newObject instanceof eZContentObject) { throw new Exception("Fallita la creazione dell'oggetto da nodo remoto"); } $rowPending = array('action' => self::ACTION_SYNC_OBJECT, 'param' => $newObject->attribute('id')); $pendingItem = new eZPendingActions($rowPending); $pendingItem->store(); return $newObject; }
/** * Called when a node's visibility is modified. * Will re-index content identified by $nodeID. * If the node has children, they will be also re-indexed, but this action is deferred to ezfindexsubtree cronjob. * * @todo when Solr supports it: update fields only * * @param $nodeID * @param $action * @return void * @see eZSearch::updateNodeVisibility() */ public function updateNodeVisibility($nodeID, $action) { $node = eZContentObjectTreeNode::fetch($nodeID); $this->addObject($node->attribute('object')); $params = array('Depth' => 1, 'DepthOperator' => 'eq', 'Limitation' => array(), 'IgnoreVisibility' => true); if ($node->subTreeCount($params) > 0) { $pendingAction = new eZPendingActions(array('action' => self::PENDING_ACTION_INDEX_SUBTREE, 'created' => time(), 'param' => $nodeID)); $pendingAction->store(); } }
public function unlock() { eZPendingActions::removeByAction(self::ACTION_KEY); }
/** * Deletes a content object, or a list of content objects * * @param array $deleteIDArray * @param bool $moveToTrash * * @return array An array with operation status, always true */ static public function deleteObject( $deleteIDArray, $moveToTrash = false ) { $ini = eZINI::instance(); $aNodes = eZContentObjectTreeNode::fetch( $deleteIDArray ); if( !is_array( $aNodes ) ) { $aNodes = array( $aNodes ); } $delayedIndexingValue = $ini->variable( 'SearchSettings', 'DelayedIndexing' ); if ( $delayedIndexingValue === 'enabled' || $delayedIndexingValue === 'classbased' ) { $pendingActionsToDelete = array(); $classList = $ini->variable( 'SearchSettings', 'DelayedIndexingClassList' ); // Will be used below if DelayedIndexing is classbased $assignedNodesByObject = array(); $nodesToDeleteByObject = array(); foreach ( $aNodes as $node ) { $object = $node->object(); $objectID = $object->attribute( 'id' ); $assignedNodes = $object->attribute( 'assigned_nodes' ); // Only delete pending action if this is the last object's node that is requested for deletion // But $deleteIDArray can also contain all the object's node (mainly if this method is called programmatically) // So if this is not the last node, then store its id in a temp array // This temp array will then be compared to the whole object's assigned nodes array if ( count( $assignedNodes ) > 1 ) { // $assignedNodesByObject will be used as a referent to check if we want to delete all lasting nodes if ( !isset( $assignedNodesByObject[$objectID] ) ) { $assignedNodesByObject[$objectID] = array(); foreach ( $assignedNodes as $assignedNode ) { $assignedNodesByObject[$objectID][] = $assignedNode->attribute( 'node_id' ); } } // Store the node assignment we want to delete // Then compare the array to the referent node assignment array $nodesToDeleteByObject[$objectID][] = $node->attribute( 'node_id' ); $diff = array_diff( $assignedNodesByObject[$objectID], $nodesToDeleteByObject[$objectID] ); if ( !empty( $diff ) ) // We still have more node assignments for object, pending action is not to be deleted considering this iteration { continue; } } if ( $delayedIndexingValue !== 'classbased' || ( is_array( $classList ) && in_array( $object->attribute( 'class_identifier' ), $classList ) ) ) { $pendingActionsToDelete[] = $objectID; } } if ( !empty( $pendingActionsToDelete ) ) { $filterConds = array( 'param' => array ( $pendingActionsToDelete ) ); eZPendingActions::removeByAction( 'index_object', $filterConds ); } } // Add assigned nodes to the clear cache list // This allows to clear assigned nodes separately (e.g. in reverse proxies) // as once content is removed, there is no more assigned nodes, and http cache clear is not possible any more. // See https://jira.ez.no/browse/EZP-22447 foreach ( $aNodes as $node ) { eZContentCacheManager::addAdditionalNodeIDPerObject( $node->attribute( 'contentobject_id' ), $node->attribute( 'node_id' ) ); } eZContentObjectTreeNode::removeSubtrees( $deleteIDArray, $moveToTrash ); return array( 'status' => true ); }