Passed
Pull Request — master (#172)
by David
03:49
created

FindObjectsQueryFactory::getPartialQuery()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 18
rs 9.9666
cc 3
nc 4
nop 3
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->cache->fetch($key);
48
            return;
49
        }
50
51
        list($columnDescList, $columnsList, $orderString) = $this->getColumnsList($this->mainTable, $this->additionalTablesFetch, $this->orderBy, true);
52
53
        $sql = 'SELECT DISTINCT '.implode(', ', $columnsList).' FROM MAGICJOIN('.$this->mainTable.')';
54
55
        $pkColumnNames = $this->tdbmService->getPrimaryKeyColumns($this->mainTable);
56
        $mysqlPlatform = new MySqlPlatform();
57
        $pkColumnNames = array_map(function ($pkColumn) use ($mysqlPlatform) {
58
            return $mysqlPlatform->quoteIdentifier($this->mainTable).'.'.$mysqlPlatform->quoteIdentifier($pkColumn);
59
        }, $pkColumnNames);
60
61
        $subQuery = 'SELECT DISTINCT '.implode(', ', $pkColumnNames).' FROM MAGICJOIN('.$this->mainTable.')';
62
63
        if (count($pkColumnNames) === 1 || $this->tdbmService->getConnection()->getDatabasePlatform() instanceof MySqlPlatform) {
64
            $countSql = 'SELECT COUNT(DISTINCT '.implode(', ', $pkColumnNames).') FROM MAGICJOIN('.$this->mainTable.')';
65
        } else {
66
            $countSql = 'SELECT COUNT(*) FROM ('.$subQuery.') tmp';
67
        }
68
69
        if (!empty($this->filterString)) {
70
            $sql .= ' WHERE '.$this->filterString;
71
            $countSql .= ' WHERE '.$this->filterString;
72
            $subQuery .= ' WHERE '.$this->filterString;
73
        }
74
75
        if (!empty($orderString)) {
76
            $sql .= ' ORDER BY '.$orderString;
77
        }
78
79
        $this->magicSql = $sql;
80
        $this->magicSqlCount = $countSql;
81
        $this->magicSqlSubQuery = $subQuery;
82
        $this->columnDescList = $columnDescList;
83
84
        $this->cache->save($key, [
85
            $this->magicSql,
86
            $this->magicSqlCount,
87
            $this->columnDescList,
88
        ]);
89
    }
90
91
    /**
92
     * Generates a SQL query to be used as a sub-query.
93
     * @param array<string, mixed> $parameters
94
     */
95
    public function getPartialQuery(StorageNode $storageNode, MagicQuery $magicQuery, array $parameters): PartialQuery
96
    {
97
        $mysqlPlatform = new MySqlPlatform();
98
99
        // Special case: if the main table is part of an inheritance relationship, we need to get all related tables
100
        $relatedTables = $this->tdbmService->_getRelatedTablesByInheritance($this->mainTable);
101
        if (count($relatedTables) === 1) {
102
            $sql = 'FROM '.$mysqlPlatform->quoteIdentifier($this->mainTable);
103
        } else {
104
            // Let's use MagicQuery to build the query
105
            $sql = 'FROM MAGICJOIN('.$this->mainTable.')';
106
        }
107
108
        if (!empty($this->filterString)) {
109
            $sql .= ' WHERE '.$this->filterString;
110
        }
111
112
        return new StaticPartialQuery($sql, $parameters, $relatedTables, $storageNode, $magicQuery);
113
    }
114
}
115