1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5: *
6: * Licensed under The MIT License
7: * For full copyright and license information, please see the LICENSE.txt
8: * Redistributions of files must retain the above copyright notice.
9: *
10: * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 3.0.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\Database\Schema;
16:
17: use Cake\Database\Connection;
18: use Cake\Database\Exception;
19: use PDOException;
20:
21: /**
22: * Represents a database schema collection
23: *
24: * Used to access information about the tables,
25: * and other data in a database.
26: */
27: class Collection
28: {
29: /**
30: * Connection object
31: *
32: * @var \Cake\Database\Connection
33: */
34: protected $_connection;
35:
36: /**
37: * Schema dialect instance.
38: *
39: * @var \Cake\Database\Schema\BaseSchema
40: */
41: protected $_dialect;
42:
43: /**
44: * Constructor.
45: *
46: * @param \Cake\Database\Connection $connection The connection instance.
47: */
48: public function __construct(Connection $connection)
49: {
50: $this->_connection = $connection;
51: $this->_dialect = $connection->getDriver()->schemaDialect();
52: }
53:
54: /**
55: * Get the list of tables available in the current connection.
56: *
57: * @return array The list of tables in the connected database/schema.
58: */
59: public function listTables()
60: {
61: list($sql, $params) = $this->_dialect->listTablesSql($this->_connection->config());
62: $result = [];
63: $statement = $this->_connection->execute($sql, $params);
64: while ($row = $statement->fetch()) {
65: $result[] = $row[0];
66: }
67: $statement->closeCursor();
68:
69: return $result;
70: }
71:
72: /**
73: * Get the column metadata for a table.
74: *
75: * The name can include a database schema name in the form 'schema.table'.
76: *
77: * Caching will be applied if `cacheMetadata` key is present in the Connection
78: * configuration options. Defaults to _cake_model_ when true.
79: *
80: * ### Options
81: *
82: * - `forceRefresh` - Set to true to force rebuilding the cached metadata.
83: * Defaults to false.
84: *
85: * @param string $name The name of the table to describe.
86: * @param array $options The options to use, see above.
87: * @return \Cake\Database\Schema\TableSchema Object with column metadata.
88: * @throws \Cake\Database\Exception when table cannot be described.
89: */
90: public function describe($name, array $options = [])
91: {
92: $config = $this->_connection->config();
93: if (strpos($name, '.')) {
94: list($config['schema'], $name) = explode('.', $name);
95: }
96: $table = new TableSchema($name);
97:
98: $this->_reflect('Column', $name, $config, $table);
99: if (count($table->columns()) === 0) {
100: throw new Exception(sprintf('Cannot describe %s. It has 0 columns.', $name));
101: }
102:
103: $this->_reflect('Index', $name, $config, $table);
104: $this->_reflect('ForeignKey', $name, $config, $table);
105: $this->_reflect('Options', $name, $config, $table);
106:
107: return $table;
108: }
109:
110: /**
111: * Helper method for running each step of the reflection process.
112: *
113: * @param string $stage The stage name.
114: * @param string $name The table name.
115: * @param array $config The config data.
116: * @param \Cake\Database\Schema\TableSchema $schema The table instance
117: * @return void
118: * @throws \Cake\Database\Exception on query failure.
119: */
120: protected function _reflect($stage, $name, $config, $schema)
121: {
122: $describeMethod = "describe{$stage}Sql";
123: $convertMethod = "convert{$stage}Description";
124:
125: list($sql, $params) = $this->_dialect->{$describeMethod}($name, $config);
126: if (empty($sql)) {
127: return;
128: }
129: try {
130: $statement = $this->_connection->execute($sql, $params);
131: } catch (PDOException $e) {
132: throw new Exception($e->getMessage(), 500, $e);
133: }
134: foreach ($statement->fetchAll('assoc') as $row) {
135: $this->_dialect->{$convertMethod}($schema, $row);
136: }
137: $statement->closeCursor();
138: }
139: }
140: