MysqlInformationSchema::getReferences()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Soluble\Schema\Source;
4
5
use Soluble\Schema\Exception;
6
use Soluble\Schema\Source;
7
use Soluble\DbWrapper\Adapter\AdapterInterface;
8
use Soluble\DbWrapper\AdapterFactory;
9
use ArrayObject;
10
11
class MysqlInformationSchema extends Source\AbstractSchemaSource
12
{
13
    /**
14
     * Schema name.
15
     *
16
     * @var string
17
     */
18
    protected $schema;
19
20
    /**
21
     * Whether to include full schema options like comment, collations...
22
     *
23
     * @var bool
24
     */
25
    protected $include_options = true;
26
27
    /**
28
     * @var array
29
     */
30
    protected static $localCache = [];
31
32
    /**
33
     * @var bool
34
     */
35
    protected $useLocalCaching = true;
36
37
    /**
38
     * @var array
39
     */
40
    protected static $fullyCachedSchemas = [];
41
42
    /**
43
     * @var Mysql\MysqlDriverInterface
44
     */
45
    protected $driver;
46
47
    /**
48
     * Constructor.
49
     *
50
     * @param \PDO|\mysqli|AdapterInterface $adapter
51
     * @param string|null                   $schema  default schema, taken from adapter if not given
52
     *
53
     * @throws Exception\InvalidArgumentException for invalid connection
54
     * @throws Exception\InvalidUsageException    thrown if no schema can be found
55
     */
56 23
    public function __construct($adapter, $schema = null)
57
    {
58 23
        if (!$adapter instanceof AdapterInterface) {
59
            try {
60 23
                $adapter = AdapterFactory::createAdapterFromResource($adapter);
61
            } catch (Exception\InvalidArgumentException $e) {
62
                $msg = "MysqlInformationSchema requires a valid 'mysqli', 'pdo:mysql' or AdapterInterface parameter ({$e->getMessage()}).";
63
                throw new Exception\InvalidArgumentException($msg);
64
            }
65
        }
66
67 23
        parent::__construct($adapter, $schema);
68
69 23
        $this->driver = new Mysql\MysqlDriver51($this->adapter, $this->schema);
70 23
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75 1
    public function getUniqueKeys($table, $include_primary = false)
76
    {
77 1
        $this->loadCacheInformation($table);
78 1
        $uniques = (array) self::$localCache[$this->schemaSignature]['tables'][$table]['unique_keys'];
79 1
        if ($include_primary) {
80
            try {
81 1
                $pks = $this->getPrimaryKeys($table);
82 1
                if (count($pks) > 0) {
83 1
                    $uniques = array_merge($uniques, ['PRIMARY' => $pks]);
84
                }
85 1
            } catch (Exception\NoPrimaryKeyException $e) {
86
                // Ignore exception
87
            }
88
        }
89
90 1
        return $uniques;
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function getIndexesInformation($table)
97
    {
98
        $this->loadCacheInformation($table);
99
100
        return self::$localCache[$this->schemaSignature]['tables'][$table]['indexes'];
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106 6
    public function getPrimaryKey($table)
107
    {
108 6
        $pks = $this->getPrimaryKeys($table);
109 3
        if (count($pks) > 1) {
110 1
            $keys = implode(',', $pks);
111 1
            throw new Exception\MultiplePrimaryKeyException(__METHOD__ . ". Multiple primary keys found on table '{$this->schemaSignature}'.'$table':  $keys");
112
        }
113
114 2
        return $pks[0];
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 10
    public function getPrimaryKeys($table)
121
    {
122 10
        $this->loadCacheInformation($table);
123 7
        $pks = self::$localCache[$this->schemaSignature]['tables'][$table]['primary_keys'];
124 7
        if (count($pks) == 0) {
125 3
            throw new Exception\NoPrimaryKeyException(__METHOD__ . ". No primary keys found on table  '{$this->schemaSignature}'.'$table'.");
126
        }
127
128 5
        return $pks;
129
    }
130
131
    /**
132
     * {@inheritdoc}
133
     */
134 2
    public function getColumnsInformation($table)
135
    {
136 2
        $this->loadCacheInformation($table);
137
138 2
        return self::$localCache[$this->schemaSignature]['tables'][$table]['columns'];
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 1
    public function getForeignKeys($table)
145
    {
146 1
        $this->loadCacheInformation($table);
147
148 1
        return self::$localCache[$this->schemaSignature]['tables'][$table]['foreign_keys'];
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154 1
    public function getReferences($table)
155
    {
156 1
        $this->loadCacheInformation($table);
157
158 1
        return self::$localCache[$this->schemaSignature]['tables'][$table]['references'];
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164 3
    public function getTablesInformation()
165
    {
166 3
        $this->loadCacheInformation(null);
167
168 3
        return self::$localCache[$this->schemaSignature]['tables'];
169
    }
170
171
    /**
172
     * Get a table configuration.
173
     *
174
     * @throws Exception\ErrorException
175
     * @throws Exception\TableNotFoundException
176
     *
177
     * @param string    $table           table name
178
     * @param bool|null $include_options include extended information
179
     *
180
     * @return ArrayObject
181
     */
182 14
    protected function getTableConfig($table, $include_options = null)
183
    {
184 14
        if ($include_options === null) {
185 14
            $include_options = $this->include_options;
186
        }
187
188 14
        $schema = $this->schemaSignature;
189
190 14
        if ($this->useLocalCaching &&
191 14
                isset(self::$localCache[$schema]['tables'][$table])) {
192 12
            return self::$localCache[$schema]['tables'][$table];
193
        }
194
195 2
        $config = $this->driver->getSchemaConfig($table, $include_options);
196
197 2
        if (!array_key_exists($table, $config['tables'])) {
198 2
            throw new Exception\TableNotFoundException(__METHOD__ . ". Table '$table' in database schema '{$schema}' not found.");
199
        }
200
201
        if ($this->useLocalCaching) {
202
            if (!array_key_exists($schema, self::$localCache)) {
203
                self::$localCache[$schema] = [];
204
            }
205
            self::$localCache[$schema] = new ArrayObject(array_merge_recursive((array) self::$localCache[$schema], (array) $config));
206
        }
207
208
        return $config['tables'][$table];
209
    }
210
211
    /**
212
     * Get schema configuration.
213
     *
214
     * @throws Exception\ErrorException
215
     * @throws Exception\SchemaNotFoundException
216
     *
217
     * @param bool|null $include_options include extended information
218
     *
219
     * @return ArrayObject
220
     */
221 5
    public function getSchemaConfig($include_options = null)
222
    {
223 5
        if ($include_options === null) {
224 5
            $include_options = $this->include_options;
225
        }
226 5
        $schema = $this->schemaSignature;
227 5
        if ($this->useLocalCaching && in_array($schema, self::$fullyCachedSchemas)) {
228 3
            return self::$localCache[$schema];
229
        }
230
231 2
        $config = $this->driver->getSchemaConfig($table = null, $include_options);
232 2
        if (count($config['tables']) == 0) {
233 1
            throw new Exception\SchemaNotFoundException(__METHOD__ . " Error: schema '{$schema}' not found or without any table or view");
234
        }
235 1
        if ($this->useLocalCaching) {
236 1
            self::$localCache[$schema] = $config;
237 1
            self::$fullyCachedSchemas[] = $schema;
238
        }
239
240 1
        return $config;
241
    }
242
243
    /**
244
     * @param string $table
245
     *
246
     * @throws Exception\InvalidArgumentException
247
     * @throws Exception\TableNotFoundException
248
     */
249 17
    protected function loadCacheInformation($table = null)
250
    {
251 17
        $schema = $this->schema;
252 17
        $this->checkTableArgument($table);
253
254 15
        if (!in_array($schema, self::$fullyCachedSchemas)) {
255 15
            if ($table !== null) {
256 12
                $this->getTableConfig($table);
257
            } else {
258 14
                $this->getSchemaConfig();
259
            }
260
        } elseif ($table !== null) {
261
            // Just in case to check if table exists
262
            $this->getTableConfig($table);
263
        }
264 14
    }
265
266
    /**
267
     * Clear local cache information for the current schema.
268
     *
269
     * @throws Exception\InvalidArgumentException
270
     */
271 1
    public function clearCacheInformation()
272
    {
273 1
        $schema = $this->schema;
274 1
        if (array_key_exists($schema, self::$localCache)) {
275
            unset(self::$localCache[$schema]);
276
            if (($key = array_search($schema, self::$fullyCachedSchemas)) !== false) {
277
                unset(self::$fullyCachedSchemas[$key]);
278
            }
279
        }
280 1
    }
281
}
282