|
5 | 5 |
|
6 | 6 | use Cake\Collection\Collection; |
7 | 7 | use Cake\Utility\Hash; |
| 8 | +use Cake\Utility\Inflector; |
8 | 9 | use Migrations\Db\Adapter\AdapterInterface; |
9 | 10 | use ReflectionClass; |
10 | 11 |
|
@@ -64,6 +65,13 @@ public function parseFields(array $arguments): array |
64 | 65 | $type = 'primary'; |
65 | 66 | } |
66 | 67 | } |
| 68 | + |
| 69 | + // Handle references - convert to integer type |
| 70 | + $isReference = in_array($type, ['references', 'references?'], true); |
| 71 | + if ($isReference) { |
| 72 | + $type = str_contains($type, '?') ? 'integer?' : 'integer'; |
| 73 | + } |
| 74 | + |
67 | 75 | $nullable = (bool)strpos($type, '?'); |
68 | 76 | $type = $nullable ? str_replace('?', '', $type) : $type; |
69 | 77 |
|
@@ -109,6 +117,11 @@ public function parseIndexes(array $arguments): array |
109 | 117 | $indexType = Hash::get($matches, 3); |
110 | 118 | $indexName = Hash::get($matches, 4); |
111 | 119 |
|
| 120 | + // Skip references - they create foreign keys, not indexes |
| 121 | + if ($type && str_starts_with($type, 'references')) { |
| 122 | + continue; |
| 123 | + } |
| 124 | + |
112 | 125 | if ( |
113 | 126 | in_array($type, ['primary', 'primary_key'], true) || |
114 | 127 | in_array($indexType, ['primary', 'primary_key'], true) || |
@@ -168,6 +181,55 @@ public function parsePrimaryKey(array $arguments): array |
168 | 181 | return $primaryKey; |
169 | 182 | } |
170 | 183 |
|
| 184 | + /** |
| 185 | + * Parses a list of arguments into an array of foreign key constraints |
| 186 | + * |
| 187 | + * @param array<int, string> $arguments A list of arguments being parsed |
| 188 | + * @return array<string, array> |
| 189 | + */ |
| 190 | + public function parseForeignKeys(array $arguments): array |
| 191 | + { |
| 192 | + $foreignKeys = []; |
| 193 | + $arguments = $this->validArguments($arguments); |
| 194 | + |
| 195 | + foreach ($arguments as $field) { |
| 196 | + preg_match($this->regexpParseColumn, $field, $matches); |
| 197 | + $fieldName = $matches[1]; |
| 198 | + $type = Hash::get($matches, 2, ''); |
| 199 | + $indexType = Hash::get($matches, 3); |
| 200 | + $indexName = Hash::get($matches, 4); |
| 201 | + |
| 202 | + // Check if type is 'references' or 'references?' |
| 203 | + $isReference = str_starts_with($type, 'references'); |
| 204 | + if (!$isReference) { |
| 205 | + continue; |
| 206 | + } |
| 207 | + |
| 208 | + // Determine referenced table |
| 209 | + // If indexType is provided, use it as the referenced table name |
| 210 | + // Otherwise, infer from field name (e.g., category_id -> categories) |
| 211 | + $referencedTable = $indexType; |
| 212 | + if (!$referencedTable) { |
| 213 | + // Remove common suffixes like _id and pluralize |
| 214 | + $referencedTable = preg_replace('/_id$/', '', $fieldName); |
| 215 | + $referencedTable = Inflector::pluralize($referencedTable); |
| 216 | + } |
| 217 | + |
| 218 | + // Generate constraint name |
| 219 | + $constraintName = $indexName ?: 'fk_' . $fieldName; |
| 220 | + |
| 221 | + $foreignKeys[$constraintName] = [ |
| 222 | + 'type' => 'foreign', |
| 223 | + 'columns' => [$fieldName], |
| 224 | + 'references' => [$referencedTable, 'id'], |
| 225 | + 'update' => 'CASCADE', |
| 226 | + 'delete' => 'CASCADE', |
| 227 | + ]; |
| 228 | + } |
| 229 | + |
| 230 | + return $foreignKeys; |
| 231 | + } |
| 232 | + |
171 | 233 | /** |
172 | 234 | * Returns a list of only valid arguments |
173 | 235 | * |
|
0 commit comments