Completed
Push — master ( aa2dbb...5f8e8d )
by
unknown
02:19
created

Builder   B

Complexity

Total Complexity 5

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 17

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 5
c 5
b 1
f 0
lcom 1
cbo 17
dl 0
loc 142
rs 7.8571

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 1
A getFromAlias() 0 8 2
B buildQueryBuilder() 0 32 2
1
<?php
2
namespace Netdudes\DataSourceryBundle\DataSource\Driver\Doctrine\QueryBuilder;
3
4
use Doctrine\ORM\EntityManager;
5
use Doctrine\ORM\QueryBuilder;
6
use Netdudes\DataSourceryBundle\DataSource\DataSourceInterface;
7
use Netdudes\DataSourceryBundle\DataSource\Driver\Doctrine\DoctrineDriver;
8
use Netdudes\DataSourceryBundle\DataSource\Driver\Doctrine\Events\GenerateJoinsEvent;
9
use Netdudes\DataSourceryBundle\DataSource\Driver\Doctrine\Events\GenerateSelectsEvent;
10
use Netdudes\DataSourceryBundle\DataSource\Driver\Doctrine\Events\PostGenerateQueryBuilderEvent;
11
use Netdudes\DataSourceryBundle\Query\Query;
12
use Netdudes\DataSourceryBundle\Query\SearchTextFieldHandler;
13
use Netdudes\DataSourceryBundle\Query\SearchTextFilterConditionTransformer;
14
15
class Builder
16
{
17
    /**
18
     * @var Filterer
19
     */
20
    protected $filterer;
21
22
    /**
23
     * @var Sorter
24
     */
25
    protected $sorter;
26
27
    /**
28
     * @var Paginator
29
     */
30
    protected $paginator;
31
32
    /**
33
     * @var string
34
     */
35
    protected $fromAlias;
36
37
    /**
38
     * @var array
39
     */
40
    protected $joins;
41
42
    /**
43
     * @var array
44
     */
45
    protected $selectFieldsMap = [];
46
47
    /**
48
     * @var RequiredFieldsExtractor
49
     */
50
    protected $requiredFieldsExtractor;
51
52
    /**
53
     * @var JoinGenerator
54
     */
55
    protected $joinGenerator;
56
57
    /**
58
     * @var SelectGenerator
59
     */
60
    protected $selectGenerator;
61
62
    /**
63
     * @var SearchTextFieldHandler
64
     */
65
    protected $searchTextFieldHandler;
66
67
    /**
68
     * @var EntityManager
69
     */
70
    private $entityManager;
71
72
    /**
73
     * @var DataSourceInterface
74
     */
75
    private $dataSource;
76
77
    /**
78
     * @param DataSourceInterface $dataSource
79
     * @param EntityManager       $entityManager
80
     */
81
    public function __construct(DataSourceInterface $dataSource, EntityManager $entityManager)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $entityManager. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
82
    {
83
        $this->dataSource = $dataSource;
84
        $this->entityManager = $entityManager;
85
86
        $fields = $dataSource->getFields();
87
        $transformers = $dataSource->getTransformers();
88
89
        $this->requiredFieldsExtractor = new RequiredFieldsExtractor($fields, $transformers);
90
        $this->joinGenerator = new JoinGenerator($fields, $this->getFromAlias(), $this->requiredFieldsExtractor);
91
        $this->selectGenerator = new SelectGenerator($fields, $this->getFromAlias(), $this->joinGenerator, $this->requiredFieldsExtractor);
92
        $this->filterer = new Filterer();
93
        $this->searchTextFieldHandler = new SearchTextFieldHandler(new SearchTextFilterConditionTransformer());
94
        $this->sorter = new Sorter();
95
        $this->paginator = new Paginator();
96
    }
97
98
    /**
99
     * Gets the fully generated query builder. Will autogenerate select and
100
     * join statements as needed.
101
     *
102
     * This function is cached, and will only be generated once per execution.
103
     *
104
     * @param Query $query
105
     *
106
     * @return QueryBuilder
107
     */
108
    public function buildQueryBuilder(Query $query, $entityClass)
109
    {
110
        $this->searchTextFieldHandler->handle($query->getFilter(), $this->dataSource->getFields());
0 ignored issues
show
Documentation introduced by
$this->dataSource->getFields() is of type array<integer,object<Net...ration\FieldInterface>>, but the function expects a array<integer,object<Net...e\Configuration\Field>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
111
112
        $queryBuilder = $this->entityManager->createQueryBuilder();
113
        $queryBuilder->from($entityClass, $this->getFromAlias());
114
115
        $select = $this->selectGenerator->generate($query);
116
        $event = new GenerateSelectsEvent($select, $this->getFromAlias());
117
        $this->dataSource->getEventDispatcher()->dispatch(DoctrineDriver::EVENT_GENERATE_SELECTS, $event);
118
        $select = $event->select;
119
        $queryBuilder->add('select', $select);
120
121
        $joins = $this->joinGenerator->generate($query);
122
        $event = new GenerateJoinsEvent($this->getFromAlias(), $joins);
123
        $this->dataSource->getEventDispatcher()->dispatch(DoctrineDriver::EVENT_GENERATE_JOINS, $event);
124
        $joins = $event->joins;
125
        foreach ($joins as $join) {
126
            $queryBuilder
127
                ->leftJoin($join->getJoin(), $join->getAlias(), $join->getConditionType(), $join->getCondition(), $join->getIndexBy());
128
        }
129
130
        $this->filterer->filter($queryBuilder, $query->getFilter(), $this->selectGenerator->getUniqueNameToSelectFieldMap($query));
131
132
        $this->sorter->sort($queryBuilder, $query->getSort(), $this->selectGenerator->getUniqueNameToSelectFieldMap($query));
133
134
        $this->paginator->paginate($queryBuilder, $query->getPagination(), $this->dataSource->getFields());
0 ignored issues
show
Unused Code introduced by
The call to Paginator::paginate() has too many arguments starting with $this->dataSource->getFields().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
135
136
        $this->dataSource->getEventDispatcher()->dispatch(DoctrineDriver::EVENT_POST_GENERATE_QUERY_BUILDER, new PostGenerateQueryBuilderEvent($queryBuilder, $this->getFromAlias()));
137
138
        return $queryBuilder;
139
    }
140
141
    /**
142
     * Gets the FROM alias, an internal name given to the class in the FROM part of the DQL.
143
     *
144
     * This name is generated once, and it's unique per execution of the data source.
145
     *
146
     * @return string
147
     */
148
    protected function getFromAlias()
149
    {
150
        if (is_null($this->fromAlias)) {
151
            $this->fromAlias = uniqid('ENTITY_');
152
        }
153
154
        return $this->fromAlias;
155
    }
156
}
157