protected function earlyOptimizationOfFilters(FlowQuery $flowQuery, array $parsedFilter)
{
$optimized = false;
$output = array();
$outputNodePaths = array();
foreach ($parsedFilter['Filters'] as $filter) {
$instanceOfFilters = array();
$attributeFilters = array();
if (isset($filter['AttributeFilters'])) {
foreach ($filter['AttributeFilters'] as $attributeFilter) {
if ($attributeFilter['Operator'] === 'instanceof' && $attributeFilter['Identifier'] === null) {
$instanceOfFilters[] = $attributeFilter;
} else {
$attributeFilters[] = $attributeFilter;
}
}
}
// Only apply optimization if there's a property name filter or a instanceof filter or another filter already did optimization
if (isset($filter['PropertyNameFilter']) || isset($filter['PathFilter']) || count($instanceOfFilters) > 0 || $optimized === true) {
$optimized = true;
$filteredOutput = array();
$filteredOutputNodePaths = array();
// Optimize property name filter if present
if (isset($filter['PropertyNameFilter']) || isset($filter['PathFilter'])) {
$nodePath = isset($filter['PropertyNameFilter']) ? $filter['PropertyNameFilter'] : $filter['PathFilter'];
/** @var NodeInterface $contextNode */
foreach ($flowQuery->getContext() as $contextNode) {
$childNode = $contextNode->getNode($nodePath);
if ($childNode !== null && !isset($filteredOutputNodePaths[$childNode->getPath()])) {
$filteredOutput[] = $childNode;
$filteredOutputNodePaths[$childNode->getPath()] = true;
}
}
} elseif (count($instanceOfFilters) > 0) {
// Optimize node type filter if present
$allowedNodeTypes = array_map(function ($instanceOfFilter) {
return $instanceOfFilter['Operand'];
}, $instanceOfFilters);
/** @var NodeInterface $contextNode */
foreach ($flowQuery->getContext() as $contextNode) {
/** @var NodeInterface $childNode */
foreach ($contextNode->getChildNodes(implode($allowedNodeTypes, ',')) as $childNode) {
if (!isset($filteredOutputNodePaths[$childNode->getPath()])) {
$filteredOutput[] = $childNode;
$filteredOutputNodePaths[$childNode->getPath()] = true;
}
}
}
}
// Apply attribute filters if present
if (isset($filter['AttributeFilters'])) {
$attributeFilters = array_reduce($filter['AttributeFilters'], function ($filters, $attributeFilter) {
return $filters . $attributeFilter['text'];
});
$filteredFlowQuery = new FlowQuery($filteredOutput);
$filteredFlowQuery->pushOperation('filter', array($attributeFilters));
$filteredOutput = $filteredFlowQuery->get();
}
// Add filtered nodes to output
foreach ($filteredOutput as $filteredNode) {
if (!isset($outputNodePaths[$filteredNode->getPath()])) {
$output[] = $filteredNode;
}
}
}
}
if ($optimized === true) {
$flowQuery->setContext($output);
}
return $optimized;
}