Completed
Push — master ( 792f9b...0f2fc9 )
by Sébastien
02:58
created

MysqlInformationSchema::getSchemaConfig()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

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