Completed
Push — master ( c341b6...280bd5 )
by Rafael
04:24
created

NodeFilter   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 78
Duplicated Lines 0 %

Test Coverage

Coverage 92.11%

Importance

Changes 0
Metric Value
wmc 17
eloc 44
dl 0
loc 78
ccs 35
cts 38
cp 0.9211
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __invoke() 0 26 6
B applyFilter() 0 38 11
1
<?php
2
/*******************************************************************************
3
 *  This file is part of the GraphQL Bundle package.
4
 *
5
 *  (c) YnloUltratech <[email protected]>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 ******************************************************************************/
10
11
namespace Ynlo\GraphQLBundle\Filter\Common;
12
13
use Doctrine\ORM\Mapping\ClassMetadataInfo;
14
use Doctrine\ORM\QueryBuilder;
15
use Ynlo\GraphQLBundle\Filter\FilterContext;
16
use Ynlo\GraphQLBundle\Filter\FilterInterface;
17
use Ynlo\GraphQLBundle\Model\Filter\NodeComparisonExpression;
18
use Ynlo\GraphQLBundle\Model\NodeInterface;
19
use Ynlo\GraphQLBundle\Type\NodeComparisonOperatorType;
20
21
/**
22
 * Node filter to filter by related nodes
23
 */
24
class NodeFilter implements FilterInterface
25
{
26
    /**
27
     * @inheritDoc
28
     */
29 7
    public function __invoke(FilterContext $context, QueryBuilder $qb, $condition)
30
    {
31 7
        if (!$condition instanceof NodeComparisonExpression) {
32 1
            throw new \RuntimeException('Invalid filter condition');
33
        }
34
35 6
        if (!$context->getField() || !$context->getField()->getName()) {
36 1
            throw new \RuntimeException('There are not valid field related to this filter.');
37
        }
38
39 5
        $entity = $context->getNode()->getClass();
0 ignored issues
show
Bug introduced by
The method getClass() does not exist on Ynlo\GraphQLBundle\Defin...wareDefinitionInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Ynlo\GraphQLBundle\Definition\ImplementorInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

39
        $entity = $context->getNode()->/** @scrutinizer ignore-call */ getClass();
Loading history...
40 5
        $metadata = $qb->getEntityManager()->getClassMetadata($entity);
41 5
        $column = $context->getField()->getOriginName();
42 5
        if ($context->getField()->getOriginType() === 'ReflectionMethod') {
43
            $column = $context->getField()->getName();
44
        }
45
46 5
        if (!$metadata->hasAssociation($column)) {
47 1
            throw new \RuntimeException(sprintf('There are not valid association in %s called %s.', $entity, $column));
48
        }
49
50 4
        $association = $metadata->getAssociationMapping($column);
51
52 4
        $alias = $qb->getRootAliases()[0];
53
54 4
        $this->applyFilter($qb, $association['type'], $alias, $column, $condition);
55 4
    }
56
57
    /**
58
     * @param QueryBuilder             $qb
59
     * @param string                   $assocType
60
     * @param string                   $alias
61
     * @param string                   $column
62
     * @param NodeComparisonExpression $condition
63
     */
64 4
    protected function applyFilter(QueryBuilder $qb, $assocType, $alias, $column, NodeComparisonExpression $condition): void
65
    {
66 4
        $ids = [];
67 4
        foreach ($condition->getNodes() as $node) {
68 4
            if ($node instanceof NodeInterface) {
69 4
                $ids[] = $node->getId();
70
            }
71
        }
72 4
        $ids = array_filter($ids);
73
74 4
        switch ($assocType) {
75
            case ClassMetadataInfo::MANY_TO_ONE:
76
            case ClassMetadataInfo::ONE_TO_ONE:
77
            case ClassMetadataInfo::ONE_TO_MANY:
78 2
                if ($condition->getOp() === NodeComparisonOperatorType::IN) {
79 1
                    if (empty($ids)) {
80
                        $qb->andWhere($qb->expr()->isNull("{$alias}.{$column}"));
81
                    } else {
82 1
                        $qb->andWhere($qb->expr()->in("{$alias}.{$column}", $ids));
83
                    }
84
                } else {
85 1
                    if (empty($ids)) {
86
                        $qb->andWhere($qb->expr()->isNotNull("{$alias}.{$column}"));
87
                    } else {
88 1
                        $qb->andWhere($qb->expr()->notIn("{$alias}.{$column}", $ids));
89
                    }
90
                }
91 2
                break;
92
            case ClassMetadataInfo::MANY_TO_MANY:
93 2
                $paramName = sprintf('%s_ids_%s', $column, mt_rand());
94 2
                if ($condition->getOp() === NodeComparisonOperatorType::IN) {
95 1
                    $qb->andWhere(sprintf(':%s MEMBER OF %s.%s', $paramName, $alias, $column))
96 1
                       ->setParameter($paramName, $ids);
97
                } else {
98 1
                    $qb->andWhere(sprintf(':%s NOT MEMBER OF %s.%s', $paramName, $alias, $column))
99 1
                       ->setParameter($paramName, $ids);
100
                }
101 2
                break;
102
        }
103 4
    }
104
}
105