Completed
Push — master ( eb2d7d...e8d14f )
by Sébastien
02:24
created

MysqlInformationSchema::__construct()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.9158

Importance

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