/** * Builds a filter group and, recursively, constructs a tree of conditions for the filters * * @param QueryBuilder $queryBuilder * @param Filter $filterDefinition * * @throws \Exception * @return Andx|Orx */ protected function buildFilterGroup(QueryBuilder $queryBuilder, Filter $filterDefinition) { // Container for the expressions to add to the $queryBuilder $filterConditionType = $filterDefinition->getConditionType(); if ($filterConditionType == Filter::CONDITION_TYPE_AND) { $expressions = $queryBuilder->expr()->andX(); } elseif ($filterConditionType == Filter::CONDITION_TYPE_OR) { $expressions = $queryBuilder->expr()->orX(); } else { throw new \Exception("Unknown condition type {$filterConditionType} on the filter."); } // Loop through all the filters in the collection $this->addExpressionsForFilter($expressions, $filterDefinition, $queryBuilder); return $expressions; }
/** * Create a FilterDefinition from a deserialized compact exchange JSON filters. * This wil recursively call itself to unpack the whole filter tree. * * @param $jsonSerializable * * @return array|Filter|FilterCondition * @throws \Exception */ public static function createFromJsonSerializable($jsonSerializable) { if (!count((array) $jsonSerializable)) { // Edge case: empty filter return new Filter(); } if (count($jsonSerializable) == 2 && is_array($jsonSerializable[1])) { // Complex Filter $logic = $jsonSerializable[0]; $elements = $jsonSerializable[1]; $filter = new Filter(); $filter->setConditionType($logic); foreach ($elements as $element) { $filter[] = static::createFromJsonSerializable($element); } return $filter; } elseif (count($jsonSerializable) == 3) { // Simple element return new FilterCondition($jsonSerializable[0], $jsonSerializable[1], $jsonSerializable[2]); } throw new \Exception('Unable to parse JSON-serializable filter structure'); }
/** * Test the filter construction against a typical complex multilevel situation */ public function testBuildFilterLevel() { $astSubtree = new ASTGroup('T_LOGIC_AND', [new ASTGroup('T_LOGIC_OR', [new ASTAssertion('test_dse_1', 'T_OP_EQ', 'value1'), new ASTAssertion('test_dse_2', 'T_OP_LT', 'value2')]), new ASTAssertion('test_dse_3', 'T_OP_NEQ', 'value3')]); $filterDefinition1 = new Filter(); $filterDefinition1->setConditionType('OR'); $filter1 = new FilterCondition('test_dse_1', FilterCondition::METHOD_NUMERIC_EQ, 'value1'); $filter2 = new FilterCondition('test_dse_2', FilterCondition::METHOD_NUMERIC_LT, 'value2'); $filterDefinition1[] = $filter1; $filterDefinition1[] = $filter2; $filter3 = new FilterCondition('test_dse_3', FilterCondition::METHOD_NUMERIC_NEQ, 'value3'); $filterDefinition2 = new Filter(); $filterDefinition2->setConditionType('AND'); $filterDefinition2[] = $filterDefinition1; $filterDefinition2[] = $filter3; $expectedFilterTree = $filterDefinition2; $dataSourceElements = [new Field('test_dse_1', '', '', new NumberDataType()), new Field('test_dse_2', '', '', new NumberDataType()), new Field('test_dse_3', '', '', new NumberDataType())]; $dataSource = $this->getMock('Netdudes\\DataSourceryBundle\\DataSource\\DataSourceInterface'); $dataSource->expects($this->any())->method('getFields')->will($this->returnValue($dataSourceElements)); $extensionContainer = $this->getMockBuilder('Netdudes\\DataSourceryBundle\\Extension\\TableBundleExtensionContainer')->disableOriginalConstructor()->getMock(); $interpreterFactory = new InterpreterFactory($extensionContainer); $interpreter = $interpreterFactory->create($dataSource); $this->assertEquals($expectedFilterTree, $interpreter->buildFilterLevel($astSubtree)); }
/** * Transforms a subtree of the AST into a concrete filter definition. * This function recursively builds all sub-trees. * * @param $astSubtree * * @return Filter|Filter * @throws \Exception */ public function buildFilterLevel($astSubtree) { if ($astSubtree instanceof ASTGroup) { $filterDefinition = new Filter(); $condition = $this->translateLogic($astSubtree->getLogic()); $filterDefinition->setConditionType($condition); foreach ($astSubtree->getElements() as $element) { $filterDefinition[] = $this->buildFilterLevel($element); } return $filterDefinition; } elseif ($astSubtree instanceof ASTAssertion) { $dataSourceElement = $this->matchDataSourceElement($astSubtree->getIdentifier()); $method = $this->translateOperator($astSubtree->getOperator(), $dataSourceElement); if ($astSubtree->getValue() instanceof ASTFunctionCall) { $value = $this->callFunction($astSubtree->getValue()); } else { if ($astSubtree->getOperator() == 'T_OP_IN') { // We expect an array here if (!$astSubtree->getValue() instanceof ASTArray) { throw new UQLInterpreterException("Only arrays are valid arguments for IN statements"); } $value = $this->parseArray($astSubtree->getValue()->getElements()); } else { $value = $this->parseValue($astSubtree->getValue()); } } return new FilterCondition($dataSourceElement->getUniqueName(), $method, $value); } else { throw new UQLInterpreterException('Unexpected Abstract Syntax Tree element'); } }