private function applyFilters (QueryBuilder $qb, array $filters)
    {

        if (!isset($filters['groupOp']) || !in_array($filters['groupOp'], array('AND', 'OR'))){
            throw new \InvalidArgumentException('Operator does not match OR | AND');
        }

        if (!isset($filters['rules']) || !is_array($filters['rules'])){
            throw new \InvalidArgumentException('Rules are not set.');
        }
        
        $groupOp = $filters['groupOp'];
    
        $andXWithWhere = $qb->expr()->andX();
        $andXWithHaving = $qb->expr()->andX();
        
        $orXWithWhere = $qb->expr()->orX();
        $orXWithHaving = $qb->expr()->orX();

        $supportedAggregateOperators = array('eq', 'ne', 'lt', 'le', 'gt', 'ge');
    
        foreach ($filters['rules'] as $rule) {
            $rule = $this->getResolvedRule((array) $rule);
            
            $field = $this->getFieldQuery($rule['field'], $rule['op'], $rule['data'], $qb);
            $isAgrigated = $this->isAggregated($rule['field']);
            
            if ($groupOp === 'AND'){
                if (false === $isAgrigated){
                    $andXWithWhere->add($field);
                } else if ($isAgrigated && in_array($rule['op'], $supportedAggregateOperators)){
                    $andXWithHaving->add($field);
                }  
            } elseif ($groupOp === 'OR'){
                if (false === $isAgrigated){
                    $orXWithWhere->add($field);
                } else if ($isAgrigated && in_array($rule['op'], $supportedAggregateOperators)){
                    $orXWithHaving->add($field);
                }
            }
        }
    
        
          
        (count($andXWithWhere->getParts()) > 0) ? $qb->andWhere($andXWithWhere) : null;
        (count($andXWithHaving->getParts()) > 0) ? $qb->andHaving($andXWithHaving) : null; 
        
        // we use addWhere/addHaving because if we add a where/having clause beforehand then it will be ignored.
        (count($orXWithWhere->getParts()) > 0) ? $qb->andWhere($orXWithWhere) : null;
        (count($orXWithHaving->getParts()) > 0) ? $qb->andHaving($orXWithHaving) : null;     
    }