Completed
Pull Request — master (#1286)
by Dmitriy
05:40
created

Table::hasIndexByName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * Phinx
4
 *
5
 * (The MIT license)
6
 * Copyright (c) 2015 Rob Morgan
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated * documentation files (the "Software"), to
10
 * deal in the Software without restriction, including without limitation the
11
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
 * sell copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24
 * IN THE SOFTWARE.
25
 *
26
 * @package    Phinx
27
 * @subpackage Phinx\Db
28
 */
29
namespace Phinx\Db;
30
31
use Phinx\Db\Adapter\AdapterInterface;
32
use Phinx\Db\Table\Column;
33
use Phinx\Db\Table\ForeignKey;
34
use Phinx\Db\Table\Index;
35
36
/**
37
 *
38
 * This object is based loosely on: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html.
39
 */
40
class Table
41
{
42
    /**
43
     * @var string
44
     */
45
    protected $name;
46
47
    /**
48
     * @var array
49
     */
50
    protected $options = [];
51
52
    /**
53
     * @var \Phinx\Db\Adapter\AdapterInterface
54
     */
55
    protected $adapter;
56
57
    /**
58
     * @var array
59
     */
60
    protected $columns = [];
61
62
    /**
63
     * @var array
64
     */
65
    protected $indexes = [];
66
67
    /**
68
     * @var \Phinx\Db\Table\ForeignKey[]
69
     */
70
    protected $foreignKeys = [];
71
72
    /**
73
     * @var array
74
     */
75
    protected $data = [];
76
77
    /**
78
     * Class Constuctor.
79
     *
80
     * @param string $name Table Name
81
     * @param array $options Options
82
     * @param \Phinx\Db\Adapter\AdapterInterface $adapter Database Adapter
83
     */
84 239
    public function __construct($name, $options = [], AdapterInterface $adapter = null)
85
    {
86 239
        $this->setName($name);
87 239
        $this->setOptions($options);
88
89 239
        if ($adapter !== null) {
90 231
            $this->setAdapter($adapter);
91 231
        }
92 239
    }
93
94
    /**
95
     * Sets the table name.
96
     *
97
     * @param string $name Table Name
98
     * @return \Phinx\Db\Table
99
     */
100 239
    public function setName($name)
101
    {
102 239
        $this->name = $name;
103 239
104
        return $this;
105
    }
106
107
    /**
108
     * Gets the table name.
109
     *
110
     * @return string
111 215
     */
112
    public function getName()
113 215
    {
114
        return $this->name;
115
    }
116
117
    /**
118
     * Sets the table options.
119
     *
120
     * @param array $options
121
     * @return \Phinx\Db\Table
122 239
     */
123
    public function setOptions($options)
124 239
    {
125 239
        $this->options = $options;
126
127
        return $this;
128
    }
129
130
    /**
131
     * Gets the table options.
132
     *
133 189
     * @return array
134
     */
135 189
    public function getOptions()
136
    {
137
        return $this->options;
138
    }
139
140
    /**
141
     * Sets the database adapter.
142
     *
143
     * @param \Phinx\Db\Adapter\AdapterInterface $adapter Database Adapter
144 231
     * @return \Phinx\Db\Table
145
     */
146 231
    public function setAdapter(AdapterInterface $adapter)
147 231
    {
148
        $this->adapter = $adapter;
149
150
        return $this;
151
    }
152
153
    /**
154
     * Gets the database adapter.
155 225
     *
156
     * @return \Phinx\Db\Adapter\AdapterInterface
157 225
     */
158
    public function getAdapter()
159
    {
160
        return $this->adapter;
161
    }
162
163
    /**
164
     * Does the table exist?
165 195
     *
166
     * @return bool
167 195
     */
168
    public function exists()
169
    {
170
        return $this->getAdapter()->hasTable($this->getName());
171
    }
172
173
    /**
174
     * Drops the database table.
175 1
     *
176
     * @return void
177 1
     */
178 1
    public function drop()
179
    {
180
        $this->getAdapter()->dropTable($this->getName());
181
    }
182
183
    /**
184
     * Renames the database table.
185
     *
186 3
     * @param string $newTableName New Table Name
187
     * @return \Phinx\Db\Table
188 3
     */
189 3
    public function rename($newTableName)
190 3
    {
191
        $this->getAdapter()->renameTable($this->getName(), $newTableName);
192
        $this->setName($newTableName);
193
194
        return $this;
195
    }
196
197
    /**
198
     * Sets an array of columns waiting to be committed.
199
     * Use setPendingColumns
200
     *
201
     * @deprecated
202
     * @param array $columns Columns
203
     * @return \Phinx\Db\Table
204
     */
205
    public function setColumns($columns)
206
    {
207
        $this->setPendingColumns($columns);
208
209
        return $this;
210
    }
211 10
212
    /**
213 10
     * Gets an array of the table columns.
214
     *
215
     * @return \Phinx\Db\Table\Column[]
216
     */
217
    public function getColumns()
218
    {
219
        return $this->getAdapter()->getColumns($this->getName());
220
    }
221
222 196
    /**
223
     * Sets an array of columns waiting to be committed.
224 196
     *
225 196
     * @param array $columns Columns
226
     * @return \Phinx\Db\Table
227
     */
228
    public function setPendingColumns($columns)
229
    {
230
        $this->columns = $columns;
231
232
        return $this;
233 204
    }
234
235 204
    /**
236
     * Gets an array of columns waiting to be committed.
237
     *
238
     * @return \Phinx\Db\Table\Column[]
239
     */
240
    public function getPendingColumns()
241
    {
242
        return $this->columns;
243
    }
244 196
245
    /**
246 196
     * Sets an array of columns waiting to be indexed.
247 196
     *
248
     * @param array $indexes Indexes
249
     * @return \Phinx\Db\Table
250
     */
251
    public function setIndexes($indexes)
252
    {
253
        $this->indexes = $indexes;
254
255 191
        return $this;
256
    }
257 191
258
    /**
259
     * Gets an array of indexes waiting to be committed.
260
     *
261
     * @return array
262
     */
263
    public function getIndexes()
264
    {
265
        return $this->indexes;
266 196
    }
267
268 196
    /**
269 196
     * Sets an array of foreign keys waiting to be commited.
270
     *
271
     * @param \Phinx\Db\Table\ForeignKey[] $foreignKeys foreign keys
272
     * @return \Phinx\Db\Table
273
     */
274
    public function setForeignKeys($foreignKeys)
275
    {
276
        $this->foreignKeys = $foreignKeys;
277 192
278
        return $this;
279 192
    }
280
281
    /**
282
     * Gets an array of foreign keys waiting to be commited.
283
     *
284
     * @return array|\Phinx\Db\Table\ForeignKey[]
285
     */
286
    public function getForeignKeys()
287
    {
288 196
        return $this->foreignKeys;
289
    }
290 196
291 196
    /**
292
     * Sets an array of data to be inserted.
293
     *
294
     * @param array $data Data
295
     * @return \Phinx\Db\Table
296
     */
297
    public function setData($data)
298
    {
299 197
        $this->data = $data;
300
301 197
        return $this;
302
    }
303
304
    /**
305
     * Gets the data waiting to be inserted.
306
     *
307
     * @return array
308
     */
309 196
    public function getData()
310
    {
311 196
        return $this->data;
312 196
    }
313 196
314 196
    /**
315 196
     * Resets all of the pending table changes.
316
     *
317
     * @return void
318
     */
319
    public function reset()
320
    {
321
        $this->setPendingColumns([]);
322
        $this->setIndexes([]);
323
        $this->setForeignKeys([]);
324
        $this->setData([]);
325
    }
326
327
    /**
328
     * Add a table column.
329
     *
330
     * Type can be: string, text, integer, float, decimal, datetime, timestamp,
331
     * time, date, binary, boolean.
332 210
     *
333
     * Valid options can be: limit, default, null, precision or scale.
334
     *
335 210
     * @param string|\Phinx\Db\Table\Column $columnName Column Name
336 1
     * @param string $type Column Type
337
     * @param array $options Column Options
338
     * @throws \RuntimeException
339
     * @throws \InvalidArgumentException
340 209
     * @return \Phinx\Db\Table
341 207
     */
342 207
    public function addColumn($columnName, $type = null, $options = [])
343 207
    {
344 207
        // we need an adapter set to add a column
345 207
        if ($this->getAdapter() === null) {
346 2
            throw new \RuntimeException('An adapter must be specified to add a column.');
347
        }
348
349
        // create a new column object if only strings were supplied
350 209
        if (!$columnName instanceof Column) {
351 1
            $column = new Column();
352 1
            $column->setName($columnName);
353 1
            $column->setType($type);
354 1
            $column->setOptions($options); // map options to column methods
355 1
        } else {
356
            $column = $columnName;
357
        }
358 208
359 208
        // Delegate to Adapters to check column type
360
        if (!$this->getAdapter()->isValidColumnType($column)) {
361
            throw new \InvalidArgumentException(sprintf(
362
                'An invalid column type "%s" was specified for column "%s".',
363
                $column->getType(),
364
                $column->getName()
365
            ));
366
        }
367
368 1
        $this->columns[] = $column;
369
370 1
        return $this;
371 1
    }
372
373
    /**
374
     * Remove a table column.
375
     *
376
     * @param string $columnName Column Name
377
     * @return \Phinx\Db\Table
378
     */
379
    public function removeColumn($columnName)
380
    {
381 4
        $this->getAdapter()->dropColumn($this->getName(), $columnName);
382
383 4
        return $this;
384 4
    }
385
386
    /**
387
     * Rename a table column.
388
     *
389
     * @param string $oldName Old Column Name
390
     * @param string $newName New Column Name
391
     * @return \Phinx\Db\Table
392
     */
393
    public function renameColumn($oldName, $newName)
394
    {
395 17
        $this->getAdapter()->renameColumn($this->getName(), $oldName, $newName);
396
397
        return $this;
398 17
    }
399 4
400 4
    /**
401 4
     * Change a table column type.
402 4
     *
403 13
     * @param string        $columnName    Column Name
404
     * @param string|\Phinx\Db\Table\Column $newColumnType New Column Type
405
     * @param array         $options       Options
406
     * @return \Phinx\Db\Table
407 17
     */
408 15
    public function changeColumn($columnName, $newColumnType, $options = [])
409 15
    {
410
        // create a column object if one wasn't supplied
411 17
        if (!$newColumnType instanceof Column) {
412 17
            $newColumn = new Column();
413
            $newColumn->setType($newColumnType);
414
            $newColumn->setOptions($options);
415
        } else {
416
            $newColumn = $newColumnType;
417
        }
418
419
        // if the name was omitted use the existing column name
420
        if ($newColumn->getName() === null || strlen($newColumn->getName()) === 0) {
421 89
            $newColumn->setName($columnName);
422
        }
423 89
424
        $this->getAdapter()->changeColumn($this->getName(), $columnName, $newColumn);
425
426
        return $this;
427
    }
428
429
    /**
430
     * Checks to see if a column exists.
431
     *
432
     * @param string $columnName Column Name
433
     * @return bool
434
     */
435 29
    public function hasColumn($columnName)
436
    {
437
        return $this->getAdapter()->hasColumn($this->getName(), $columnName);
438 29
    }
439 28
440 28
    /**
441 22
     * Add an index to a database table.
442 22
     *
443 28
     * In $options you can specific unique = true/false or name (index name).
444 28
     *
445 28
     * @param string|array|\Phinx\Db\Table\Index $columns Table Column(s)
446 1
     * @param array $options Index Options
447
     * @return \Phinx\Db\Table
448
     */
449 29
    public function addIndex($columns, $options = [])
450 29
    {
451
        // create a new index object if strings or an array of strings were supplied
452
        if (!$columns instanceof Index) {
453
            $index = new Index();
454
            if (is_string($columns)) {
455
                $columns = [$columns]; // str to array
456
            }
457
            $index->setColumns($columns);
458
            $index->setOptions($options);
459 1
        } else {
460
            $index = $columns;
461 1
        }
462 1
463
        $this->indexes[] = $index;
464
465
        return $this;
466
    }
467
468
    /**
469
     * Removes the given index from a table.
470
     *
471 1
     * @param array $columns Columns
472
     * @return \Phinx\Db\Table
473 1
     */
474 1
    public function removeIndex($columns)
475
    {
476
        $this->getAdapter()->dropIndex($this->getName(), $columns);
477
478
        return $this;
479
    }
480
481
    /**
482
     * Removes the given index identified by its name from a table.
483
     *
484 12
     * @param string $name Index name
485
     * @return \Phinx\Db\Table
486 12
     */
487
    public function removeIndexByName($name)
488
    {
489
        $this->getAdapter()->dropIndexByName($this->getName(), $name);
490
491
        return $this;
492
    }
493
494
    /**
495
     * Checks to see if an index exists.
496
     *
497
     * @param string|array $columns Columns
498
     * @return bool
499
     */
500
    public function hasIndex($columns)
501 8
    {
502
        return $this->getAdapter()->hasIndex($this->getName(), $columns);
503 8
    }
504 4
505 4
    /**
506 8
     * Checks to see if an index specified by name exists.
507 8
     *
508
     * @param string $indexName
509
     * @return bool
510 8
     */
511
    public function hasIndexByName($indexName)
512 8
    {
513 8
        return $this->getAdapter()->hasIndexByName($this->getName(), $indexName);
514 8
    }
515 8
516
    /**
517 8
     * Add a foreign key to a database table.
518
     *
519
     * In $options you can specify on_delete|on_delete = cascade|no_action ..,
520
     * on_update, constraint = constraint name.
521
     *
522
     * @param string|array $columns Columns
523
     * @param string|\Phinx\Db\Table $referencedTable   Referenced Table
524
     * @param string|array $referencedColumns Referenced Columns
525
     * @param array $options Options
526
     * @return \Phinx\Db\Table
527 1
     */
528
    public function addForeignKey($columns, $referencedTable, $referencedColumns = ['id'], $options = [])
529 1
    {
530 1
        if (is_string($referencedColumns)) {
531 1
            $referencedColumns = [$referencedColumns]; // str to array
532 1
        }
533
        $fk = new ForeignKey();
534
        if ($referencedTable instanceof Table) {
535 1
            $fk->setReferencedTable($referencedTable);
536
        } else {
537
            $fk->setReferencedTable(new Table($referencedTable, [], $this->adapter));
538 1
        }
539
        $fk->setColumns($columns)
540
           ->setReferencedColumns($referencedColumns)
541
           ->setOptions($options);
542
        $this->foreignKeys[] = $fk;
543
544
        return $this;
545
    }
546
547
    /**
548 1
     * Removes the given foreign key from the table.
549
     *
550 1
     * @param string|array $columns    Column(s)
551
     * @param null|string  $constraint Constraint names
552
     * @return \Phinx\Db\Table
553
     */
554
    public function dropForeignKey($columns, $constraint = null)
555
    {
556
        if (is_string($columns)) {
557
            $columns = [$columns];
558
        }
559
        if ($constraint) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $constraint of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
560
            $this->getAdapter()->dropForeignKey($this->getName(), [], $constraint);
561 15
        } else {
562
            $this->getAdapter()->dropForeignKey($this->getName(), $columns);
563 15
        }
564 15
565 15
        return $this;
566 15
    }
567
568 15
    /**
569 15
     * Checks to see if a foreign key exists.
570 15
     *
571
     * @param  string|array $columns    Column(s)
572 15
     * @param  null|string  $constraint Constraint names
573
     * @return bool
574 15
     */
575
    public function hasForeignKey($columns, $constraint = null)
576
    {
577
        return $this->getAdapter()->hasForeignKey($this->getName(), $columns, $constraint);
0 ignored issues
show
Documentation introduced by
$columns is of type string|array, but the function expects a array<integer,string>.

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...
578
    }
579
580
    /**
581
     * Add timestamp columns created_at and updated_at to the table.
582
     *
583
     * @param string $createdAtColumnName
584
     * @param string $updatedAtColumnName
585
     *
586
     * @return \Phinx\Db\Table
587
     */
588
    public function addTimestamps($createdAtColumnName = 'created_at', $updatedAtColumnName = 'updated_at')
589 17
    {
590
        $createdAtColumnName = is_null($createdAtColumnName) ? 'created_at' : $createdAtColumnName;
591
        $updatedAtColumnName = is_null($updatedAtColumnName) ? 'updated_at' : $updatedAtColumnName;
592 17
        $this->addColumn($createdAtColumnName, 'timestamp', [
593 11
                'default' => 'CURRENT_TIMESTAMP',
594 11
                'update' => ''
595 11
            ])
596 11
             ->addColumn($updatedAtColumnName, 'timestamp', [
597
                 'null' => true,
598 8
                 'default' => null
599 8
             ]);
600
601
        return $this;
602
    }
603
604
    /**
605
     * Insert data into the table.
606
     *
607 196
     * @param array $data array of data in the form:
608
     *              array(
609 196
     *                  array("col1" => "value1", "col2" => "anotherValue1"),
610 196
     *                  array("col2" => "value2", "col2" => "anotherValue2"),
611 196
     *              )
612 196
     *              or array("col1" => "value1", "col2" => "anotherValue1")
613
     *
614
     * @return \Phinx\Db\Table
615
     */
616
    public function insert($data)
617
    {
618
        // handle array of array situations
619
        if (isset($data[0]) && is_array($data[0])) {
620 46
            foreach ($data as $row) {
621
                $this->data[] = $row;
622 46
            }
623
624
            return $this;
625
        }
626
        $this->data[] = $data;
627 46
628 38
        return $this;
629 46
    }
630
631 46
    /**
632 6
     * Creates a table from the object instance.
633 46
     *
634
     * @return void
635 46
     */
636 3
    public function create()
637 46
    {
638
        $this->getAdapter()->createTable($this);
639 46
        $this->saveData();
640 46
        $this->reset(); // reset pending changes
641 46
    }
642
643
    /**
644
     * Updates a table from the object instance.
645
     *
646
     * @throws \RuntimeException
647
     * @return void
648 196
     */
649
    public function update()
650 196
    {
651 196
        if (!$this->exists()) {
652 192
            throw new \RuntimeException('Cannot update a table that doesn\'t exist!');
653
        }
654
655 12
        // update table
656 12
        foreach ($this->getPendingColumns() as $column) {
657 12
            $this->getAdapter()->addColumn($this, $column);
658 12
        }
659 12
660 12
        foreach ($this->getIndexes() as $index) {
661 1
            $this->getAdapter()->addIndex($this, $index);
662 1
        }
663
664 12
        foreach ($this->getForeignKeys() as $foreignKey) {
665
            $this->getAdapter()->addForeignKey($this, $foreignKey);
666 12
        }
667 11
668 11
        $this->saveData();
669 1
        $this->reset(); // reset pending changes
670 1
    }
671 1
672
    /**
673 12
     * Commit the pending data waiting for insertion.
674
     *
675
     * @return void
676
     */
677
    public function saveData()
678
    {
679
        $rows = $this->getData();
680 2
        if (empty($rows)) {
681
            return;
682 2
        }
683 2
684
        $bulk = true;
685
        $row = current($rows);
686
        $c = array_keys($row);
687
        foreach ($this->getData() as $row) {
688
            $k = array_keys($row);
689
            if ($k != $c) {
690
                $bulk = false;
691
                break;
692 195
            }
693
        }
694 195
695 45
        if ($bulk) {
696 45
            $this->getAdapter()->bulkinsert($this, $this->getData());
697 195
        } else {
698
            foreach ($this->getData() as $row) {
699
                $this->getAdapter()->insert($this, $row);
700 195
            }
701 195
        }
702
    }
703
704
    /**
705
     * Truncates the table.
706
     *
707
     * @return void
708
     */
709
    public function truncate()
710
    {
711
        $this->getAdapter()->truncateTable($this->getName());
712
    }
713
714
    /**
715
     * Commits the table changes.
716
     *
717
     * If the table doesn't exist it is created otherwise it is updated.
718
     *
719
     * @return void
720
     */
721
    public function save()
722
    {
723
        if ($this->exists()) {
724
            $this->update(); // update the table
725
        } else {
726
            $this->create(); // create the table
727
        }
728
729
        $this->reset(); // reset pending changes
730
    }
731
}
732