|
5 | 5 | use Automatorm\Exception;
|
6 | 6 | use Automatorm\Database\Query;
|
7 | 7 | use Automatorm\Database\Connection;
|
8 |
| - |
| 8 | +use Automatorm\Cache\CacheInterface; |
9 | 9 | use HodgePodge\Core\Cache;
|
10 | 10 |
|
11 | 11 | class Schema
|
@@ -34,134 +34,152 @@ protected function __construct($model, $database, $namespace) {
|
34 | 34 | $this->namespace = $namespace;
|
35 | 35 | $this->version = static::CURRENT_VERSION;
|
36 | 36 | }
|
37 |
| - |
| 37 | + |
| 38 | + protected static $cache = '\\Automatorm\\Cache\\HodgePodgeCache'; |
| 39 | + public static function registerCache($cache) |
| 40 | + { |
| 41 | + static::$cache = $cache; |
| 42 | + } |
| 43 | + |
38 | 44 | public static function generate($dbconnection = 'default', $namespace = 'models', $cachebust = false)
|
39 | 45 | {
|
40 |
| - Cache::lifetime(60 * 60 * 24 * 7, 'model'); // Cache model weekly |
| 46 | + $key = 'schema_' . md5($dbconnection . $namespace . $db->database . static::CURRENT_VERSION); |
41 | 47 |
|
42 | 48 | $db = Connection::get($dbconnection);
|
43 |
| - $cache = new Cache('schema_' . md5($dbconnection . $namespace . $db->database . static::CURRENT_VERSION), 'model'); |
| 49 | + if (is_object(static::$cache)) { |
| 50 | + $cache = static::$cache; |
| 51 | + } else { |
| 52 | + $cache = new static::$cache; |
| 53 | + } |
44 | 54 |
|
45 |
| - $obj = $cache(); |
| 55 | + $obj = $cache->get($key); |
46 | 56 |
|
47 | 57 | if ($obj && $obj->version != static::CURRENT_VERSION)
|
48 | 58 | {
|
49 | 59 | unset($obj);
|
50 | 60 | }
|
51 | 61 |
|
52 | 62 | if ($cachebust or !$obj) {
|
53 |
| - // Get a list of all foreign keys in this database |
54 |
| - $query = new Query($dbconnection); |
55 |
| - $query->sql(" |
56 |
| - SELECT b.table_name, b.column_name, b.referenced_table_name, b.referenced_column_name |
57 |
| - FROM information_schema.table_constraints a |
58 |
| - JOIN information_schema.key_column_usage b |
59 |
| - ON a.table_schema = b.table_schema AND a.constraint_name = b.constraint_name |
60 |
| - WHERE a.table_schema = database() AND a.constraint_type = 'FOREIGN KEY' |
61 |
| - ORDER BY b.table_name, b.constraint_name;" |
62 |
| - ); |
63 |
| - $query->sql(" |
64 |
| - SELECT table_name, column_name, data_type FROM information_schema.columns where table_schema = database(); |
65 |
| - "); |
66 |
| - |
67 |
| - list($keys, $schema) = $query->execute(); |
| 63 | + $model = static::generateSchema($dbconnection); |
| 64 | + $obj = new static($model, $dbconnection, $namespace); |
| 65 | + $cache->put($key, $obj, 60 * 60 * 24 * 7); |
| 66 | + } |
| 67 | + |
| 68 | + return static::$object_list[$dbconnection] = $obj; |
| 69 | + } |
| 70 | + |
| 71 | + public static function generateSchema($dbconnection) |
| 72 | + { |
| 73 | + $model = []; |
| 74 | + |
| 75 | + // Get a list of all foreign keys in this database |
| 76 | + $query = new Query($dbconnection); |
| 77 | + $query->sql(" |
| 78 | + SELECT b.table_name, b.column_name, b.referenced_table_name, b.referenced_column_name |
| 79 | + FROM information_schema.table_constraints a |
| 80 | + JOIN information_schema.key_column_usage b |
| 81 | + ON a.table_schema = b.table_schema AND a.constraint_name = b.constraint_name |
| 82 | + WHERE a.table_schema = database() AND a.constraint_type = 'FOREIGN KEY' |
| 83 | + ORDER BY b.table_name, b.constraint_name;" |
| 84 | + ); |
| 85 | + $query->sql(" |
| 86 | + SELECT table_name, column_name, data_type FROM information_schema.columns where table_schema = database(); |
| 87 | + "); |
| 88 | + |
| 89 | + list($keys, $schema) = $query->execute(); |
| 90 | + |
| 91 | + // Assemble list of table columns by table |
| 92 | + foreach ($schema as $row) { |
| 93 | + $table_name = self::normaliseCase($row['table_name']); |
68 | 94 |
|
69 |
| - // Assemble list of table columns by table |
70 |
| - foreach ($schema as $row) { |
71 |
| - $table_name = self::normaliseCase($row['table_name']); |
72 |
| - |
73 |
| - $model[$table_name]['table_name'] = $row['table_name']; |
74 |
| - // All tables default to type 'table' - can also be 'pivot' or 'foreign' as detected later |
75 |
| - $model[$table_name]['type'] = 'table'; |
76 |
| - // List all columns for this table |
77 |
| - $model[$table_name]['columns'][$row['column_name']] = $row['data_type']; |
78 |
| - } |
| 95 | + $model[$table_name]['table_name'] = $row['table_name']; |
| 96 | + // All tables default to type 'table' - can also be 'pivot' or 'foreign' as detected later |
| 97 | + $model[$table_name]['type'] = 'table'; |
| 98 | + // List all columns for this table |
| 99 | + $model[$table_name]['columns'][$row['column_name']] = $row['data_type']; |
| 100 | + } |
| 101 | + |
| 102 | + // Loop over every foreign key definition |
| 103 | + foreach ($keys as $row) { |
| 104 | + $table_name = self::normaliseCase($row['table_name']); |
| 105 | + $ref_table_name = self::normaliseCase($row['referenced_table_name']); |
79 | 106 |
|
80 |
| - // Loop over every foreign key definition |
81 |
| - foreach ($keys as $row) { |
82 |
| - $table_name = self::normaliseCase($row['table_name']); |
83 |
| - $ref_table_name = self::normaliseCase($row['referenced_table_name']); |
84 |
| - |
85 |
| - if ($row['referenced_column_name'] == 'id' and $row['column_name'] == 'id') { |
86 |
| - // If both columns in the key are 'id' then this is a 1 to 1 relationship. |
87 |
| - // Create a link in both objects to each other |
88 |
| - $model[$ref_table_name]['one-to-one'][self::underscoreCase($table_name)] = $table_name; |
89 |
| - $model[$table_name]['one-to-one'][self::underscoreCase($ref_table_name)] = $ref_table_name; |
90 |
| - $model[$table_name]['type'] = 'foreign'; |
91 |
| - } elseif ($row['referenced_column_name'] == 'id') { |
92 |
| - // if this foreign key points at one 'id' column then this is a usable foreign 'key' |
93 |
| - if (substr($row['column_name'], -3) == '_id') { |
94 |
| - $column_root = substr($row['column_name'], 0, -3); |
95 |
| - $model[$table_name]['many-to-one'][$column_root] = $ref_table_name; |
96 |
| - |
97 |
| - // Add the key constraint in reverse, trying to make a sensible name. |
98 |
| - // If the column name was derived from the table name, just use the table name. |
99 |
| - // (e.g "my_account" table and "my_account_id" -> my_account) |
100 |
| - // Otherwise, append the column name to the table name to make sure it is unique. |
101 |
| - // (e.g "your_account" table and "my_account_id" -> your_account_my_account) |
102 |
| - if ($column_root == $row['referenced_table_name']) { |
103 |
| - $property_name = self::underscoreCase($table_name); |
104 |
| - } else { |
105 |
| - $property_name = self::underscoreCase($table_name) . '_' . $column_root; |
106 |
| - } |
107 |
| - |
108 |
| - $model[$ref_table_name]['one-to-many'][$property_name] = array('table' => $table_name, 'column_name' => $row['column_name']); |
| 107 | + if ($row['referenced_column_name'] == 'id' and $row['column_name'] == 'id') { |
| 108 | + // If both columns in the key are 'id' then this is a 1 to 1 relationship. |
| 109 | + // Create a link in both objects to each other |
| 110 | + $model[$ref_table_name]['one-to-one'][self::underscoreCase($table_name)] = $table_name; |
| 111 | + $model[$table_name]['one-to-one'][self::underscoreCase($ref_table_name)] = $ref_table_name; |
| 112 | + $model[$table_name]['type'] = 'foreign'; |
| 113 | + } elseif ($row['referenced_column_name'] == 'id') { |
| 114 | + // if this foreign key points at one 'id' column then this is a usable foreign 'key' |
| 115 | + if (substr($row['column_name'], -3) == '_id') { |
| 116 | + $column_root = substr($row['column_name'], 0, -3); |
| 117 | + $model[$table_name]['many-to-one'][$column_root] = $ref_table_name; |
| 118 | + |
| 119 | + // Add the key constraint in reverse, trying to make a sensible name. |
| 120 | + // If the column name was derived from the table name, just use the table name. |
| 121 | + // (e.g "my_account" table and "my_account_id" -> my_account) |
| 122 | + // Otherwise, append the column name to the table name to make sure it is unique. |
| 123 | + // (e.g "your_account" table and "my_account_id" -> your_account_my_account) |
| 124 | + if ($column_root == $row['referenced_table_name']) { |
| 125 | + $property_name = self::underscoreCase($table_name); |
| 126 | + } else { |
| 127 | + $property_name = self::underscoreCase($table_name) . '_' . $column_root; |
109 | 128 | }
|
| 129 | + |
| 130 | + $model[$ref_table_name]['one-to-many'][$property_name] = array('table' => $table_name, 'column_name' => $row['column_name']); |
110 | 131 | }
|
111 | 132 | }
|
112 |
| - |
113 |
| - // Now look for pivot tables |
114 |
| - foreach ($model as $pivottablename => $pivot) { |
115 |
| - // If we have found a table with only foreign keys then this must be a pivot table |
116 |
| - if (count($pivot['many-to-one']) > 1 and count($pivot['columns']) == count($pivot['many-to-one'])) { |
117 |
| - // Grab all foreign keys and rearrange them into arrays. |
118 |
| - $tableinfo = array(); |
119 |
| - foreach($pivot['many-to-one'] as $column => $tablename) { |
120 |
| - $tableinfo[] = array('column' => $column . '_id', 'column_raw' => $column, 'table' => $tablename); |
| 133 | + } |
| 134 | + |
| 135 | + // Now look for pivot tables |
| 136 | + foreach ($model as $pivottablename => $pivot) { |
| 137 | + // If we have found a table with only foreign keys then this must be a pivot table |
| 138 | + if (count($pivot['many-to-one']) > 1 and count($pivot['columns']) == count($pivot['many-to-one'])) { |
| 139 | + // Grab all foreign keys and rearrange them into arrays. |
| 140 | + $tableinfo = array(); |
| 141 | + foreach($pivot['many-to-one'] as $column => $tablename) { |
| 142 | + $tableinfo[] = array('column' => $column . '_id', 'column_raw' => $column, 'table' => $tablename); |
| 143 | + } |
| 144 | + |
| 145 | + // For each foreign key, store details in the table it point to on how to get to the OTHER table in the "Many to Many" relationship |
| 146 | + foreach ($tableinfo as $i => $table) |
| 147 | + { |
| 148 | + // If the column name is named based on the foreign table name, then use the pivot table name as the property name |
| 149 | + // This is the normal/usual case |
| 150 | + if ($table['column'] == self::underscoreCase($table['table']) . '_id') { |
| 151 | + $property_name = self::underscoreCase($pivottablename); |
| 152 | + } else { |
| 153 | + // Else append the column name to the pivot table name. |
| 154 | + // This is mostly for when a pivot table references the same table twice, and so |
| 155 | + // needs to have a unique name for at least one of the columns (which is not based on the table name) |
| 156 | + $property_name = self::underscoreCase($pivottablename) . '_' . $table['column_raw']; |
121 | 157 | }
|
122 | 158 |
|
123 |
| - // For each foreign key, store details in the table it point to on how to get to the OTHER table in the "Many to Many" relationship |
124 |
| - foreach ($tableinfo as $i => $table) |
125 |
| - { |
126 |
| - // If the column name is named based on the foreign table name, then use the pivot table name as the property name |
127 |
| - // This is the normal/usual case |
128 |
| - if ($table['column'] == Schema::underscoreCase($table['table']) . '_id') { |
129 |
| - $property_name = Schema::underscoreCase($pivottablename); |
130 |
| - } else { |
131 |
| - // Else append the column name to the pivot table name. |
132 |
| - // This is mostly for when a pivot table references the same table twice, and so |
133 |
| - // needs to have a unique name for at least one of the columns (which is not based on the table name) |
134 |
| - $property_name = Schema::underscoreCase($pivottablename) . '_' . $table['column_raw']; |
135 |
| - } |
136 |
| - |
137 |
| - // Outersect of tables to create an array of all OTHER foreign keys in this table, for this foreign key. |
138 |
| - $othertables = array_values(array_diff_assoc($tableinfo, array($i => $table))); |
139 |
| - |
140 |
| - $model[ $table['table'] ][ 'many-to-many' ][ $property_name ] = array( |
141 |
| - 'pivot' => $pivottablename, |
142 |
| - 'connections' => $othertables, |
143 |
| - 'id' => $table['column'], |
144 |
| - ); |
145 |
| - |
146 |
| - } |
| 159 | + // Outersect of tables to create an array of all OTHER foreign keys in this table, for this foreign key. |
| 160 | + $othertables = array_values(array_diff_assoc($tableinfo, array($i => $table))); |
147 | 161 |
|
148 |
| - $model[$pivottablename]['type'] = 'pivot'; |
| 162 | + $model[ $table['table'] ][ 'many-to-many' ][ $property_name ] = array( |
| 163 | + 'pivot' => $pivottablename, |
| 164 | + 'connections' => $othertables, |
| 165 | + 'id' => $table['column'], |
| 166 | + ); |
149 | 167 |
|
150 |
| - // Remove the M-1 keys for these tables to fully encapsulate the M-M scheme. |
151 |
| - foreach ($tableinfo as $table) |
152 |
| - { |
153 |
| - foreach((array) $model[ $table['table'] ][ 'one-to-many' ] as $key => $val) { |
154 |
| - if ($val['table'] == $pivottablename) unset ($model[ $table['table'] ][ 'one-to-many' ][$key]); |
155 |
| - } |
| 168 | + } |
| 169 | + |
| 170 | + $model[$pivottablename]['type'] = 'pivot'; |
| 171 | + |
| 172 | + // Remove the M-1 keys for these tables to fully encapsulate the M-M scheme. |
| 173 | + foreach ($tableinfo as $table) |
| 174 | + { |
| 175 | + foreach((array) $model[ $table['table'] ][ 'one-to-many' ] as $key => $val) { |
| 176 | + if ($val['table'] == $pivottablename) unset ($model[ $table['table'] ][ 'one-to-many' ][$key]); |
156 | 177 | }
|
157 | 178 | }
|
158 | 179 | }
|
159 |
| - |
160 |
| - $obj = new static($model, $dbconnection, $namespace); |
161 |
| - $cache($obj); |
162 | 180 | }
|
163 | 181 |
|
164 |
| - return static::$object_list[$dbconnection] = $obj; |
| 182 | + return $model; |
165 | 183 | }
|
166 | 184 |
|
167 | 185 | // Normalised an under_scored or CamelCased phrase to "under scored" or "camel cased"
|
|
0 commit comments