TableTrait::referencableTables()   A
last analyzed

Complexity

Conditions 5
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 6
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 10
rs 9.6111
1
<?php
2
3
namespace Lagdo\DbAdmin\Driver\MySql\Db\Traits;
4
5
use Lagdo\DbAdmin\Driver\Entity\ForeignKeyEntity;
6
use Lagdo\DbAdmin\Driver\Entity\TableEntity;
7
use Lagdo\DbAdmin\Driver\Entity\TableFieldEntity;
8
9
use function array_pad;
10
use function array_map;
11
use function preg_match;
12
use function preg_match_all;
13
14
trait TableTrait
15
{
16
    abstract public function tableStatuses(bool $fast = false);
17
    abstract public function fields(string $table);
18
19
    /**
20
     * @inheritDoc
21
     */
22
    public function supportForeignKeys(TableEntity $tableStatus)
23
    {
24
        return preg_match('~InnoDB|IBMDB2I~i', $tableStatus->engine)
25
            || (preg_match('~NDB~i', $tableStatus->engine) && $this->driver->minVersion(5.6));
26
    }
27
28
    /**
29
     * @param string $tableName
30
     *
31
     * @return TableFieldEntity|null
32
     */
33
    private function getTablePrimaryKeyField(string $tableName)
34
    {
35
        $pkField = null;
36
        foreach ($this->fields($tableName) as $field) {
37
            if ($field->primary) {
38
                if ($pkField !== null) {
39
                    // No multi column primary key
40
                    return null;
41
                }
42
                $pkField = $field;
43
            }
44
        }
45
        return $pkField;
46
    }
47
48
    /**
49
     * @inheritDoc
50
     */
51
    public function referencableTables(string $table)
52
    {
53
        $fields = []; // table_name => [field]
54
        foreach ($this->tableStatuses(true) as $tableName => $tableStatus) {
55
            if ($tableName !== $table && $this->supportForeignKeys($tableStatus) &&
56
                ($field = $this->getTablePrimaryKeyField($tableName)) !== null) {
57
                $fields[$tableName] = $field;
58
            }
59
        }
60
        return $fields;
61
    }
62
63
    /**
64
     * @param array $match
65
     *
66
     * @return ForeignKeyEntity
67
     */
68
    private function makeTableForeignKey(array $match): ForeignKeyEntity
69
    {
70
        $match = array_pad($match, 8, '');
71
72
        $pattern = '(?:`(?:[^`]|``)+`|"(?:[^"]|"")+")';
73
        preg_match_all("~$pattern~", $match[2], $source);
74
        preg_match_all("~$pattern~", $match[5], $target);
75
76
        $foreignKey = new ForeignKeyEntity();
77
78
        $foreignKey->database = $this->driver->unescapeId($match[4] != "" ? $match[3] : $match[4]);
79
        $foreignKey->table = $this->driver->unescapeId($match[4] != "" ? $match[4] : $match[3]);
80
        $foreignKey->source = array_map(function ($idf) {
81
            return $this->driver->unescapeId($idf);
82
        }, $source[0]);
83
        $foreignKey->target = array_map(function ($idf) {
84
            return $this->driver->unescapeId($idf);
85
        }, $target[0]);
86
        $foreignKey->onDelete = $match[6] ?: "RESTRICT";
87
        $foreignKey->onUpdate = $match[7] ?: "RESTRICT";
88
89
        return $foreignKey;
90
    }
91
92
    /**
93
     * @inheritDoc
94
     */
95
    public function foreignKeys(string $table)
96
    {
97
        static $pattern = '(?:`(?:[^`]|``)+`|"(?:[^"]|"")+")';
98
        $foreignKeys = [];
99
        $onActions = $this->driver->actions();
100
        $createTable = $this->driver->result("SHOW CREATE TABLE " . $this->driver->escapeTableName($table), 1);
101
        if ($createTable) {
102
            preg_match_all("~CONSTRAINT ($pattern) FOREIGN KEY ?\\(((?:$pattern,? ?)+)\\) REFERENCES " .
103
                "($pattern)(?:\\.($pattern))? \\(((?:$pattern,? ?)+)\\)(?: ON DELETE ($onActions))" .
104
                "?(?: ON UPDATE ($onActions))?~", $createTable, $matches, PREG_SET_ORDER);
105
106
            foreach ($matches as $match) {
107
                $foreignKeys[$this->driver->unescapeId($match[1])] = $this->makeTableForeignKey($match);
108
            }
109
        }
110
        return $foreignKeys;
111
    }
112
}
113