Completed
Push — master ( 09e072...c7757e )
by Luís
15s
created

Index::_addColumn()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 4
cp 0.75
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 1
nop 1
crap 2.0625
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Schema;
21
22
use Doctrine\DBAL\Platforms\AbstractPlatform;
23
24
class Index extends AbstractAsset implements Constraint
25
{
26
    /**
27
     * Asset identifier instances of the column names the index is associated with.
28
     * array($columnName => Identifier)
29
     *
30
     * @var Identifier[]
31
     */
32
    protected $_columns = [];
33
34
    /**
35
     * @var boolean
36
     */
37
    protected $_isUnique = false;
38
39
    /**
40
     * @var boolean
41
     */
42
    protected $_isPrimary = false;
43
44
    /**
45
     * Platform specific flags for indexes.
46
     * array($flagName => true)
47
     *
48
     * @var array
49
     */
50
    protected $_flags = [];
51
52
    /**
53
     * Platform specific options
54
     *
55
     * @todo $_flags should eventually be refactored into options
56
     *
57
     * @var array
58
     */
59
    private $options = [];
60
61
    /**
62
     * @param string   $indexName
63
     * @param string[] $columns
64
     * @param boolean  $isUnique
65
     * @param boolean  $isPrimary
66
     * @param string[] $flags
67
     * @param array    $options
68
     */
69 616
    public function __construct($indexName, array $columns, $isUnique = false, $isPrimary = false, array $flags = [], array $options = [])
70
    {
71 616
        $isUnique = $isUnique || $isPrimary;
72
73 616
        $this->_setName($indexName);
74 616
        $this->_isUnique = $isUnique;
75 616
        $this->_isPrimary = $isPrimary;
76 616
        $this->options = $options;
77
78 616
        foreach ($columns as $column) {
79 595
            $this->_addColumn($column);
80
        }
81 616
        foreach ($flags as $flag) {
82 18
            $this->addFlag($flag);
83
        }
84 616
    }
85
86
    /**
87
     * @param string $column
88
     *
89
     * @return void
90
     *
91
     * @throws \InvalidArgumentException
92
     */
93 595
    protected function _addColumn($column)
94
    {
95 595
        if (is_string($column)) {
96 595
            $this->_columns[$column] = new Identifier($column);
97
        } else {
98
            throw new \InvalidArgumentException("Expecting a string as Index Column");
99
        }
100 595
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105 303
    public function getColumns()
106
    {
107 303
        return array_keys($this->_columns);
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113 379 View Code Duplication
    public function getQuotedColumns(AbstractPlatform $platform)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
114
    {
115 379
        $columns = [];
116
117 379
        foreach ($this->_columns as $column) {
118 371
            $columns[] = $column->getQuotedName($platform);
119
        }
120
121 379
        return $columns;
122
    }
123
124
    /**
125
     * @return string[]
126
     */
127 1
    public function getUnquotedColumns()
128
    {
129 1
        return array_map([$this, 'trimQuotes'], $this->getColumns());
130
    }
131
132
    /**
133
     * Is the index neither unique nor primary key?
134
     *
135
     * @return boolean
136
     */
137 1
    public function isSimpleIndex()
138
    {
139 1
        return !$this->_isPrimary && !$this->_isUnique;
140
    }
141
142
    /**
143
     * @return boolean
144
     */
145 267
    public function isUnique()
146
    {
147 267
        return $this->_isUnique;
148
    }
149
150
    /**
151
     * @return boolean
152
     */
153 571
    public function isPrimary()
154
    {
155 571
        return $this->_isPrimary;
156
    }
157
158
    /**
159
     * @param string  $columnName
160
     * @param integer $pos
161
     *
162
     * @return boolean
163
     */
164 1
    public function hasColumnAtPosition($columnName, $pos = 0)
165
    {
166 1
        $columnName   = $this->trimQuotes(strtolower($columnName));
167 1
        $indexColumns = array_map('strtolower', $this->getUnquotedColumns());
168
169 1
        return array_search($columnName, $indexColumns) === $pos;
170
    }
171
172
    /**
173
     * Checks if this index exactly spans the given column names in the correct order.
174
     *
175
     * @param array $columnNames
176
     *
177
     * @return boolean
178
     */
179 113
    public function spansColumns(array $columnNames)
180
    {
181 113
        $columns         = $this->getColumns();
182 113
        $numberOfColumns = count($columns);
183 113
        $sameColumns     = true;
184
185 113
        for ($i = 0; $i < $numberOfColumns; $i++) {
186 113
            if ( ! isset($columnNames[$i]) || $this->trimQuotes(strtolower($columns[$i])) !== $this->trimQuotes(strtolower($columnNames[$i]))) {
187 52
                $sameColumns = false;
188
            }
189
        }
190
191 113
        return $sameColumns;
192
    }
193
194
    /**
195
     * Checks if the other index already fulfills all the indexing and constraint needs of the current one.
196
     *
197
     * @param Index $other
198
     *
199
     * @return boolean
200
     */
201 116
    public function isFullfilledBy(Index $other)
202
    {
203
        // allow the other index to be equally large only. It being larger is an option
204
        // but it creates a problem with scenarios of the kind PRIMARY KEY(foo,bar) UNIQUE(foo)
205 116
        if (count($other->getColumns()) != count($this->getColumns())) {
206 14
            return false;
207
        }
208
209
        // Check if columns are the same, and even in the same order
210 109
        $sameColumns = $this->spansColumns($other->getColumns());
211
212 109
        if ($sameColumns) {
213 77
            if ( ! $this->samePartialIndex($other)) {
214 1
                return false;
215
            }
216
217 77
            if ( ! $this->isUnique() && ! $this->isPrimary()) {
218
                // this is a special case: If the current key is neither primary or unique, any unique or
219
                // primary key will always have the same effect for the index and there cannot be any constraint
220
                // overlaps. This means a primary or unique index can always fulfill the requirements of just an
221
                // index that has no constraints.
222 57
                return true;
223
            }
224
225 20
            if ($other->isPrimary() != $this->isPrimary()) {
226 3
                return false;
227
            }
228
229 18
            if ($other->isUnique() != $this->isUnique()) {
230 1
                return false;
231
            }
232
233 18
            return true;
234
        }
235
236 52
        return false;
237
    }
238
239
    /**
240
     * Detects if the other index is a non-unique, non primary index that can be overwritten by this one.
241
     *
242
     * @param Index $other
243
     *
244
     * @return boolean
245
     */
246 1
    public function overrules(Index $other)
247
    {
248 1
        if ($other->isPrimary()) {
249
            return false;
250 1
        } elseif ($this->isSimpleIndex() && $other->isUnique()) {
251
            return false;
252
        }
253
254 1
        if ($this->spansColumns($other->getColumns()) && ($this->isPrimary() || $this->isUnique()) && $this->samePartialIndex($other)) {
255 1
            return true;
256
        }
257
258 1
        return false;
259
    }
260
261
    /**
262
     * Returns platform specific flags for indexes.
263
     *
264
     * @return string[]
265
     */
266 12
    public function getFlags()
267
    {
268 12
        return array_keys($this->_flags);
269
    }
270
271
    /**
272
     * Adds Flag for an index that translates to platform specific handling.
273
     *
274
     * @example $index->addFlag('CLUSTERED')
275
     *
276
     * @param string $flag
277
     *
278
     * @return Index
279
     */
280 33
    public function addFlag($flag)
281
    {
282 33
        $this->_flags[strtolower($flag)] = true;
283
284 33
        return $this;
285
    }
286
287
    /**
288
     * Does this index have a specific flag?
289
     *
290
     * @param string $flag
291
     *
292
     * @return boolean
293
     */
294 147
    public function hasFlag($flag)
295
    {
296 147
        return isset($this->_flags[strtolower($flag)]);
297
    }
298
299
    /**
300
     * Removes a flag.
301
     *
302
     * @param string $flag
303
     *
304
     * @return void
305
     */
306 1
    public function removeFlag($flag)
307
    {
308 1
        unset($this->_flags[strtolower($flag)]);
309 1
    }
310
311
    /**
312
     * @param string $name
313
     *
314
     * @return boolean
315
     */
316 111
    public function hasOption($name)
317
    {
318 111
        return isset($this->options[strtolower($name)]);
319
    }
320
321
    /**
322
     * @param string $name
323
     *
324
     * @return mixed
325
     */
326 7
    public function getOption($name)
327
    {
328 7
        return $this->options[strtolower($name)];
329
    }
330
331
    /**
332
     * @return array
333
     */
334 12
    public function getOptions()
335
    {
336 12
        return $this->options;
337
    }
338
339
    /**
340
     * Return whether the two indexes have the same partial index
341
     * @param \Doctrine\DBAL\Schema\Index $other
342
     *
343
     * @return boolean
344
     */
345 78
    private function samePartialIndex(Index $other)
346
    {
347 78
        if ($this->hasOption('where') && $other->hasOption('where') && $this->getOption('where') == $other->getOption('where')) {
348 2
            return true;
349
        }
350
351 78
        if ( ! $this->hasOption('where') && ! $other->hasOption('where')) {
352 76
            return true;
353
        }
354
355 2
        return false;
356
    }
357
358
}
359