Passed
Pull Request — master (#172)
by David
02:16
created

FindObjectsQueryFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
declare(strict_types=1);
3
4
namespace TheCodingMachine\TDBM\QueryFactory;
5
6
use Doctrine\Common\Cache\Cache;
7
use Doctrine\DBAL\Platforms\MySqlPlatform;
8
use Doctrine\DBAL\Schema\Schema;
9
use Mouf\Database\MagicQuery;
10
use TheCodingMachine\TDBM\InnerResultArray;
11
use TheCodingMachine\TDBM\OrderByAnalyzer;
12
use TheCodingMachine\TDBM\QueryFactory\SmartEagerLoad\PartialQueryFactory;
13
use TheCodingMachine\TDBM\QueryFactory\SmartEagerLoad\Query\PartialQuery;
14
use TheCodingMachine\TDBM\QueryFactory\SmartEagerLoad\Query\StaticPartialQuery;
15
use TheCodingMachine\TDBM\QueryFactory\SmartEagerLoad\StorageNode;
16
use TheCodingMachine\TDBM\TDBMService;
17
use function implode;
18
19
/**
20
 * This class is in charge of creating the MagicQuery SQL based on parameters passed to findObjects method.
21
 */
22
class FindObjectsQueryFactory extends AbstractQueryFactory implements PartialQueryFactory
23
{
24
    private $additionalTablesFetch;
25
    private $filterString;
26
    /**
27
     * @var Cache
28
     */
29
    private $cache;
30
31
    public function __construct(string $mainTable, array $additionalTablesFetch, $filterString, $orderBy, TDBMService $tdbmService, Schema $schema, OrderByAnalyzer $orderByAnalyzer, Cache $cache)
32
    {
33
        parent::__construct($tdbmService, $schema, $orderByAnalyzer, $mainTable, $orderBy);
34
        $this->additionalTablesFetch = $additionalTablesFetch;
35
        $this->filterString = $filterString;
36
        $this->cache = $cache;
37
    }
38
39
    protected function compute(): void
40
    {
41
        $key = 'FindObjectsQueryFactory_'.$this->mainTable.'__'.implode('_/_', $this->additionalTablesFetch).'__'.$this->filterString.'__'.$this->orderBy;
42
        if ($this->cache->contains($key)) {
43
            [
44
                $this->magicSql,
45
                $this->magicSqlCount,
46
                $this->columnDescList,
47
                $this->magicSqlSubQuery
48
            ] = $this->cache->fetch($key);
49
            return;
50
        }
51
52
        list($columnDescList, $columnsList, $orderString) = $this->getColumnsList($this->mainTable, $this->additionalTablesFetch, $this->orderBy, true);
53
54
        $sql = 'SELECT DISTINCT '.implode(', ', $columnsList).' FROM MAGICJOIN('.$this->mainTable.')';
55
56
        $pkColumnNames = $this->tdbmService->getPrimaryKeyColumns($this->mainTable);
57
        $mysqlPlatform = new MySqlPlatform();
58
        $pkColumnNames = array_map(function ($pkColumn) use ($mysqlPlatform) {
59
            return $mysqlPlatform->quoteIdentifier($this->mainTable).'.'.$mysqlPlatform->quoteIdentifier($pkColumn);
60
        }, $pkColumnNames);
61
62
        $subQuery = 'SELECT DISTINCT '.implode(', ', $pkColumnNames).' FROM MAGICJOIN('.$this->mainTable.')';
63
64
        if (count($pkColumnNames) === 1 || $this->tdbmService->getConnection()->getDatabasePlatform() instanceof MySqlPlatform) {
65
            $countSql = 'SELECT COUNT(DISTINCT '.implode(', ', $pkColumnNames).') FROM MAGICJOIN('.$this->mainTable.')';
66
        } else {
67
            $countSql = 'SELECT COUNT(*) FROM ('.$subQuery.') tmp';
68
        }
69
70
        if (!empty($this->filterString)) {
71
            $sql .= ' WHERE '.$this->filterString;
72
            $countSql .= ' WHERE '.$this->filterString;
73
            $subQuery .= ' WHERE '.$this->filterString;
74
        }
75
76
        if (!empty($orderString)) {
77
            $sql .= ' ORDER BY '.$orderString;
78
        }
79
80
        $this->magicSql = $sql;
81
        $this->magicSqlCount = $countSql;
82
        $this->magicSqlSubQuery = $subQuery;
83
        $this->columnDescList = $columnDescList;
84
85
        $this->cache->save($key, [
86
            $this->magicSql,
87
            $this->magicSqlCount,
88
            $this->columnDescList,
89
            $this->magicSqlSubQuery,
90
        ]);
91
    }
92
93
    /**
94
     * Generates a SQL query to be used as a sub-query.
95
     * @param array<string, mixed> $parameters
96
     */
97
    public function getPartialQuery(StorageNode $storageNode, MagicQuery $magicQuery, array $parameters): PartialQuery
98
    {
99
        $mysqlPlatform = new MySqlPlatform();
100
101
        // Special case: if the main table is part of an inheritance relationship, we need to get all related tables
102
        $relatedTables = $this->tdbmService->_getRelatedTablesByInheritance($this->mainTable);
103
        if (count($relatedTables) === 1) {
104
            $sql = 'FROM '.$mysqlPlatform->quoteIdentifier($this->mainTable);
105
        } else {
106
            // Let's use MagicQuery to build the query
107
            $sql = 'FROM MAGICJOIN('.$this->mainTable.')';
108
        }
109
110
        if (!empty($this->filterString)) {
111
            $sql .= ' WHERE '.$this->filterString;
112
        }
113
114
        return new StaticPartialQuery($sql, $parameters, $relatedTables, $storageNode, $magicQuery);
115
    }
116
}
117