Passed
Push — master ( d6ce84...9c42e9 )
by Gaetano
10:07
created

SQLExecutor::query()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 35
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 18
nc 7
nop 1
dl 0
loc 35
ccs 0
cts 0
cp 0
crap 42
rs 9.0444
c 0
b 0
f 0
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
6
use Kaliop\eZMigrationBundle\API\EmbeddedReferenceResolverBagInterface;
7
use Kaliop\eZMigrationBundle\API\Value\MigrationStep;
8
9
class SQLExecutor extends AbstractExecutor
10
{
11
    use IgnorableStepExecutorTrait;
0 ignored issues
show
Bug introduced by
The trait Kaliop\eZMigrationBundle...orableStepExecutorTrait requires the property $dsl which is not provided by Kaliop\eZMigrationBundle\Core\Executor\SQLExecutor.
Loading history...
12
    use NonScalarReferenceSetterTrait;
0 ignored issues
show
Bug introduced by
The trait Kaliop\eZMigrationBundle...larReferenceSetterTrait requires the property $dsl which is not provided by Kaliop\eZMigrationBundle\Core\Executor\SQLExecutor.
Loading history...
13
14
    protected $scalarReferences = array('count');
15
16
    /**
17
     * @var DatabaseHandler $connection
18
     */
19
    protected $dbHandler;
20
21
    protected $supportedStepTypes = array('sql');
22
    protected $supportedActions = array('exec', 'query');
23
24
    /** @var EmbeddedReferenceResolverBagInterface $referenceResolver */
25
    protected $referenceResolver;
26
27 96
    protected $queryRequiresFetching = false;
28
29 96
    /**
30 96
     * @param DatabaseHandler $dbHandler
31 96
     * @param EmbeddedReferenceResolverBagInterface $referenceResolver
32
     */
33
    public function __construct(DatabaseHandler $dbHandler, EmbeddedReferenceResolverBagInterface $referenceResolver)
34
    {
35
        $this->dbHandler = $dbHandler;
36
        $this->referenceResolver = $referenceResolver;
37
    }
38 3
39
    /**
40 3
     * @param MigrationStep $step
41
     * @return integer
42 3
     * @throws \Exception if migration step is not for this type of db
43
     */
44 3
    public function execute(MigrationStep $step)
45
    {
46 3
        parent::execute($step);
47
48 3
        // BC
49
        if (!isset($step->dsl['mode'])) {
50 3
            $action = 'exec';
51
        } else {
52
            $action = $step->dsl['mode'];
53 3
        }
54
55
        if (!in_array($action, $this->supportedActions)) {
56 3
            throw new \Exception("Invalid step definition: value '$action' is not allowed for 'mode'");
57
        }
58 2
59
        $this->skipStepIfNeeded($step);
60 2
61
        return $this->$action($step);
62
    }
63 2
64
    protected function exec($step)
65 2
    {
66 1
        $conn = $this->dbHandler->getConnection();
67
        // @see http://doctrine-orm.readthedocs.io/projects/doctrine-dbal/en/latest/reference/platforms.html
68
        $dbType = strtolower(preg_replace('/([0-9]+|Platform)/', '', $conn->getDatabasePlatform()->getName()));
69 1
70 1
        if (!isset($step->dsl[$dbType])) {
71 1
            throw new \Exception("Current database type '$dbType' is not supported by the SQL migration");
72 1
        }
73 1
        $sql = $step->dsl[$dbType];
74
75
        if (isset($step->dsl['resolve_references']) && $step->dsl['resolve_references']) {
76
            $sql = $this->referenceResolver->resolveEmbeddedReferences($sql);
77
        }
78 1
79 1
        $result = $conn->exec($sql);
80
81
        $this->setExecReferences($result, $step);
82 1
83
        return $result;
84 1
    }
85
86
    protected function query($step)
87
    {
88
        $conn = $this->dbHandler->getConnection();
89
        // @see http://doctrine-orm.readthedocs.io/projects/doctrine-dbal/en/latest/reference/platforms.html
90
        $dbType = strtolower(preg_replace('/([0-9]+|Platform)/', '', $conn->getDatabasePlatform()->getName()));
91
92
        if (!isset($step->dsl[$dbType])) {
93
            throw new \Exception("Current database type '$dbType' is not supported by the SQL migration");
94
        }
95
        $sql = $step->dsl[$dbType];
96
97
        if (isset($step->dsl['resolve_references']) && $step->dsl['resolve_references']) {
98
            $sql = $this->referenceResolver->resolveEmbeddedReferences($sql);
99
        }
100
101
        /** @var \Doctrine\DBAL\Driver\Statement $stmt */
102
        $stmt = $conn->query($sql);
103
        if ($this->getResultsType($step) == self::$RESULT_TYPE_SINGLE) {
104
            // fetch twice, to insure that we get only 1 row
105
            $result = $stmt->fetch();
106
            if ($stmt->fetch() !== false) {
107
                throw new \Exception('Found two (or more) results but expect only one');
108
            }
109
            $stmt->closeCursor();
110
111
        } else {
112
            // fetch all rows
113
            $result = $stmt->fetchAll();
114
115
            $this->validateResultsCount($result, $step);
116
        }
117
118
        $this->setQueryReferences($result, $step);
119
120
        return $result;
121
    }
122
123
    protected function setExecReferences($result, $step)
124
    {
125
        if (!array_key_exists('references', $step->dsl)) {
126
            return false;
127
        }
128
129
        foreach ($step->dsl['references'] as $reference) {
130
            switch ($reference['attribute']) {
131
                case 'affected_rows':
132
                    $value = $result;
133
                    break;
134
                default:
135
                    throw new \InvalidArgumentException('Sql Executor does not support setting references for attribute ' . $reference['attribute']);
136
            }
137
138
            $overwrite = false;
139
            if (isset($reference['overwrite'])) {
140
                $overwrite = $reference['overwrite'];
141
            }
142
            $this->referenceResolver->addReference($reference['identifier'], $value, $overwrite);
143
        }
144
    }
145
146
    protected function setQueryReferences($result, $step)
147
    {
148
        if (!array_key_exists('references', $step->dsl)) {
149
            return false;
150
        }
151
152
        foreach ($step->dsl['references'] as $reference) {
153
            switch ($reference['attribute']) {
154
                case 'count':
155
                    $value = count($result);
156
                    break;
157
                default:
158
/// @todo...
159
                    throw new \InvalidArgumentException('Sql Executor does not support setting references for attribute ' . $reference['attribute']);
160
            }
161
162
            $overwrite = false;
163
            if (isset($reference['overwrite'])) {
164
                $overwrite = $reference['overwrite'];
165
            }
166
            $this->referenceResolver->addReference($reference['identifier'], $value, $overwrite);
167
        }
168
    }
169
170
    /**
171
     * @param array $referenceDefinition
172
     * @return bool
173
     */
174
    protected function isScalarReference($referenceDefinition)
175
    {
176
        return in_array($referenceDefinition['attribute'], $this->scalarReferences);
177
    }
178
}
179