- Timestamp:
- 12/16/09 00:52:11 (8 months ago)
- Files:
-
- fActiveRecord.php (modified) (14 diffs)
- fORMRelated.php (modified) (8 diffs)
- fORMSchema.php (modified) (2 diffs)
- fSchema.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
fActiveRecord.php
r731 r735 Hide Line Numbers 16 16 * @link http://flourishlib.com/fActiveRecord 17 17 * 18 * @version 1.0.0b51 18 * @version 1.0.0b52 19 * @changes 1.0.0b52 Backwards Compatibility Break - Added the $force_cascade parameter to ::delete() and ::store() - enabled calling ::prepare() and ::encode() for non-column get methods, added `::has{RelatedRecords}()` methods [wb, 2009-12-16] 19 20 * @changes 1.0.0b51 Made ::changed() properly recognize that a blank string and NULL are equivalent due to the way that ::set() casts values [wb, 2009-11-14] 20 21 * @changes 1.0.0b50 Fixed a bug with trying to load by a multi-column primary key where one of the columns was not specified [wb, 2009-11-13] … … 686 687 * `verbColumName()`. 687 688 * 688 * This method also handles `associate`, `build`, `count` and `link` verbs 689 * for records in many-to-many relationships; `build`, `count` and 690 * `populate` verbs for all related records in one-to-many relationships 691 * and the `create` verb for all related records in *-to-one relationships. 689 * This method also handles `associate`, `build`, `count`, `has`, and `link` 690 * verbs for records in many-to-many relationships; `build`, `count`, `has` 691 * and `populate` verbs for all related records in one-to-many relationships 692 * and `create`, `has` and `populate` verbs for all related records in 693 * one-to-one relationships, and the `create` verb for all related records 694 * in many-to-one relationships. 692 695 * 693 696 * Method callbacks registered through fORM::registerActiveRecordMethod() … … 834 837 } 835 838 return fORMRelated::createRecord($class, $this->values, $this->related_records, $subject); 839 840 case 'has': 841 $table = fORM::tablize($class); 842 $route = isset($parameters[0]) ? $parameters[0] : NULL; 843 $schema = fORMSchema::retrieve($class); 844 845 // Here the subject will either be a single class name for 846 // one-to-one relationships, or a plural class name for 847 // one-to-* relationships 848 $subject = fGrammar::camelize($subject, TRUE); 849 850 $related_table = fORM::tablize($subject); 851 852 // Here, only a non-plural class name will properly tablize, 853 // so if we don't find one matching we can simply singularize 854 if (!in_array($related_table, $schema->getTables())) { 855 $subject = fGrammar::singularize($subject); 856 857 // This triggers an error if you try to use a plural form 858 // for a one-to-one relationship 859 if (fORMSchema::isOneToOne($schema, $table, $related_table, $route)) { 860 throw new fProgrammerException( 861 'The table %1$s is not in a%2$srelationship with the table %3$s', 862 $table, 863 ' one-to-many ', 864 $subject 865 ); 866 } 867 868 $route = fORMSchema::getRouteName($schema, $table, fORM::tablize($subject), $route, '*-to-many'); 869 } else { 870 $route = fORMSchema::getRouteName($schema, $table, $related_table, $route, 'one-to-one'); 871 } 872 873 return fORMRelated::hasRecords($class, $this->values, $this->related_records, $subject, $route); 836 874 837 875 case 'inject': … … 872 910 873 911 case 'populate': 874 $table = fORM::tablize($class); 875 $route = isset($parameters[0]) ? $parameters[0] : NULL; 876 877 // one-to-many relationships need to use plural forms 912 $table = fORM::tablize($class); 913 $route = isset($parameters[0]) ? $parameters[0] : NULL; 878 914 $schema = fORMSchema::retrieve($class); 879 if (in_array($subject, $schema->getTables())) { 880 if (fORMSchema::isOneToOne($schema, $table, $subject, $route)) { 915 916 // Here the subject will either be a single class name for 917 // one-to-one relationships, or a plural class name for 918 // one-to-* relationships 919 $subject = fGrammar::camelize($subject, TRUE); 920 921 $related_table = fORM::tablize($subject); 922 923 // Here, only a non-plural class name will properly tablize, 924 // so if we don't find one matching we can simply singularize 925 if (!in_array($related_table, $schema->getTables())) { 926 $subject = fGrammar::singularize($subject); 927 928 // This triggers an error if you try to use a plural form 929 // for a one-to-one relationship 930 if (fORMSchema::isOneToOne($schema, $table, $related_table, $route)) { 881 931 throw new fProgrammerException( 882 932 'The table %1$s is not in a%2$srelationship with the table %3$s', … … 886 936 ); 887 937 } 888 $subject = fGrammar::singularize($subject); 889 } 890 891 $subject = fGrammar::camelize($subject, TRUE); 938 939 $route = fORMSchema::getRouteName($schema, $table, fORM::tablize($subject), $route, '*-to-many'); 940 } else { 941 $route = fORMSchema::getRouteName($schema, $table, $related_table, $route, 'one-to-one'); 942 } 892 943 893 944 fORMRelated::populateRecords($class, $this->related_records, $subject, $route); … … 1258 1309 * This method will start a database transaction if one is not already active. 1259 1310 * 1311 * @param boolean $force_cascade When TRUE, this will cause all child objects to be deleted, even if the ON DELETE clause is RESTRICT or NO ACTION 1260 1312 * @return fActiveRecord The record object, to allow for method chaining 1261 1313 */ 1262 public function delete() 1263 { 1314 public function delete($force_cascade=FALSE) 1315 { 1316 // This flag prevents recursive relationships, such as one-to-one 1317 // relationships, from creating infinite loops 1318 if (!empty($this->cache['fActiveRecord::delete()::being_deleted'])) { 1319 return; 1320 } 1321 1264 1322 $class = get_class($this); 1265 1323 … … 1307 1365 1308 1366 // Check to ensure no foreign dependencies prevent deletion 1367 $one_to_one_relationships = $schema->getRelationships($table, 'one-to-one'); 1309 1368 $one_to_many_relationships = $schema->getRelationships($table, 'one-to-many'); 1310 1369 $many_to_many_relationships = $schema->getRelationships($table, 'many-to-many'); 1311 1370 1312 $relationships = array_merge($one_to_ many_relationships, $many_to_many_relationships);1371 $relationships = array_merge($one_to_one_relationships, $one_to_many_relationships, $many_to_many_relationships); 1313 1372 $records_sets_to_delete = array(); 1314 1373 1315 1374 $restriction_messages = array(); 1316 1375 1376 $this->cache['fActiveRecord::delete()::being_deleted'] = TRUE; 1377 1317 1378 foreach ($relationships as $relationship) { 1318 1379 1319 1380 // Figure out how to check for related records 1320 $type = (isset($relationship['join_table'])) ? 'many-to-many' : 'one-to-many';1381 $type = (isset($relationship['join_table'])) ? 'many-to-many' : 'one-to-many'; 1321 1382 $route = fORMSchema::getRouteNameFromRelationship($type, $relationship); 1322 1383 1323 $related_class = fORM::classize($relationship['related_table']); 1324 $related_objects = fGrammar::pluralize($related_class); 1325 $method = 'build' . $related_objects; 1326 1327 // Grab the related records 1328 $record_set = $this->$method($route); 1329 1330 // If there are none, we can just move on 1331 if (!$record_set->count()) { 1332 continue; 1333 } 1334 1335 if ($type == 'one-to-many' && $relationship['on_delete'] == 'cascade') { 1336 $records_sets_to_delete[] = $record_set; 1384 $related_class = fORM::classize($relationship['related_table']); 1385 $type = $type == 'one-to-many' && fORMSchema::isOneToOne($schema, $table, $relationship['related_table'], $route) ? 'one-to-one' : $type; 1386 1387 if ($type == 'one-to-one') { 1388 $method = 'create' . $related_class; 1389 $related_record = $this->$method($route); 1390 if (!$related_record->exists()) { 1391 continue; 1392 } 1393 1394 } else { 1395 $method = 'build' . fGrammar::pluralize($related_class); 1396 $record_set = $this->$method($route); 1397 if (!$record_set->count()) { 1398 continue; 1399 } 1400 1401 if ($type == 'one-to-many' && $relationship['on_delete'] == 'cascade') { 1402 $records_sets_to_delete[] = $record_set; 1403 } 1337 1404 } 1338 1405 1339 1406 if ($relationship['on_delete'] == 'restrict' || $relationship['on_delete'] == 'no_action') { 1340 1407 1341 // Otherwise we have a restriction 1342 $related_class_name = fORM::classize($relationship['related_table']); 1343 $related_record_name = fORM::getRecordName($related_class_name); 1344 $related_record_name = fGrammar::pluralize($related_record_name); 1408 // If we are focing the cascade we have to delete child records and join table entries before this record 1409 if ($force_cascade) { 1410 1411 if ($type == 'one-to-one') { 1412 $related_record->delete($force_cascade); 1413 1414 // For one-to-many we explicitly delete all of the records 1415 } elseif ($type == 'one-to-many') { 1416 foreach ($record_set as $record) { 1417 if ($record->exists()) { 1418 $record->delete($force_cascade); 1419 } 1420 } 1421 1422 // For many-to-many relationships we explicitly delete the join table entries 1423 } elseif ($type == 'many-to-many') { 1424 $join_column_placeholder = $schema->getColumnInfo($relationship['join_table'], $relationship['join_column'], 'placeholder'); 1425 $column_get_method = 'get' . fGrammar::camelize($relationship['column'], TRUE); 1426 1427 $db->translatedQuery( 1428 $db->escape( 1429 'DELETE FROM %r WHERE %r = ', 1430 $relationship['join_table'], 1431 $relationship['join_column'] 1432 ) . $join_column_placeholder, 1433 $this->$column_get_method() 1434 ); 1435 } 1345 1436 1346 $restriction_messages[] = self::compose("One or more %s references it", $related_record_name); 1437 // Otherwise we have a restriction and we can to create a nice error message for the user 1438 } else { 1439 $related_class_name = fORM::classize($relationship['related_table']); 1440 $related_record_name = fORM::getRecordName($related_class_name); 1441 1442 if ($type == 'one-to-one') { 1443 $restriction_messages[] = self::compose("A %s references it", $related_record_name); 1444 } else { 1445 $related_record_name = fGrammar::pluralize($related_record_name); 1446 $restriction_messages[] = self::compose("One or more %s references it", $related_record_name); 1447 } 1448 } 1347 1449 } 1348 1450 } … … 1363 1465 1364 1466 1365 // Delete related records 1467 // Delete related records to ensure any PHP-level cleanup is done 1366 1468 foreach ($records_sets_to_delete as $record_set) { 1367 1469 foreach ($record_set as $record) { 1368 1470 if ($record->exists()) { 1369 $record->delete( );1471 $record->delete($force_cascade); 1370 1472 } 1371 1473 } 1372 1474 } 1475 1476 unset($this->cache['fActiveRecord::delete()::being_deleted']); 1373 1477 1374 1478 fORM::callHookCallbacks( … … 1474 1578 protected function encode($column, $formatting=NULL) 1475 1579 { 1476 if (!array_key_exists($column, $this->values)) { 1580 $column_exists = array_key_exists($column, $this->values); 1581 $method_name = 'get' . fGrammar::camelize($column, TRUE); 1582 $method_exists = method_exists($this, $method_name); 1583 1584 if (!$column_exists && !$method_exists) { 1477 1585 throw new fProgrammerException( 1478 1586 'The column specified, %s, does not exist', … … 1481 1589 } 1482 1590 1483 $class = get_class($this); 1484 $schema = fORMSchema::retrieve($class); 1485 $table = fORM::tablize($class); 1486 $column_type = $schema->getColumnInfo($table, $column, 'type'); 1487 1488 // Ensure the programmer is calling the function properly 1489 if ($column_type == 'blob') { 1490 throw new fProgrammerException( 1491 'The column specified, %s, does not support forming because it is a blob column', 1492 $column 1493 ); 1494 } 1495 1496 if ($formatting !== NULL && in_array($column_type, array('boolean', 'integer'))) { 1497 throw new fProgrammerException( 1498 'The column specified, %s, does not support any formatting options', 1499 $column 1500 ); 1591 if ($column_exists) { 1592 $class = get_class($this); 1593 $schema = fORMSchema::retrieve($class); 1594 $table = fORM::tablize($class); 1595 $column_type = $schema->getColumnInfo($table, $column, 'type'); 1596 1597 // Ensure the programmer is calling the function properly 1598 if ($column_type == 'blob') { 1599 throw new fProgrammerException( 1600 'The column specified, %s, does not support forming because it is a blob column', 1601 $column 1602 ); 1603 } 1604 1605 if ($formatting !== NULL && in_array($column_type, array('boolean', 'integer'))) { 1606 throw new fProgrammerException( 1607 'The column specified, %s, does not support any formatting options', 1608 $column 1609 ); 1610 } 1611 1612 // If the column doesn't exist, we are just pulling the 1613 // value from a get method, so treat it as text 1614 } else { 1615 $column_type = 'text'; 1501 1616 } 1502 1617 1503 1618 // Grab the value for empty value checking 1504 $method_name = 'get' . fGrammar::camelize($column, TRUE); 1505 $value = $this->$method_name(); 1619 $value = $this->$method_name(); 1506 1620 1507 1621 // Date/time objects … … 1910 2024 protected function prepare($column, $formatting=NULL) 1911 2025 { 1912 if (!array_key_exists($column, $this->values)) { 2026 $column_exists = array_key_exists($column, $this->values); 2027 $method_name = 'get' . fGrammar::camelize($column, TRUE); 2028 $method_exists = method_exists($this, $method_name); 2029 2030 if (!$column_exists && !$method_exists) { 1913 2031 throw new fProgrammerException( 1914 2032 'The column specified, %s, does not exist', … … 1917 2035 } 1918 2036 1919 $class = get_class($this); 1920 $table = fORM::tablize($class); 1921 $schema = fORMSchema::retrieve($class); 1922 1923 $column_info = $schema->getColumnInfo($table, $column); 1924 $column_type = $column_info['type']; 1925 1926 // Ensure the programmer is calling the function properly 1927 if ($column_type == 'blob') { 1928 throw new fProgrammerException( 1929 'The column specified, %s, can not be prepared because it is a blob column', 1930 $column 1931 ); 1932 } 1933 1934 if ($formatting !== NULL && in_array($column_type, array('integer', 'boolean'))) { 1935 throw new fProgrammerException( 1936 'The column specified, %s, does not support any formatting options', 1937 $column 1938 ); 2037 if ($column_exists) { 2038 $class = get_class($this); 2039 $table = fORM::tablize($class); 2040 $schema = fORMSchema::retrieve($class); 2041 2042 $column_info = $schema->getColumnInfo($table, $column); 2043 $column_type = $column_info['type']; 2044 2045 // Ensure the programmer is calling the function properly 2046 if ($column_type == 'blob') { 2047 throw new fProgrammerException( 2048 'The column specified, %s, can not be prepared because it is a blob column', 2049 $column 2050 ); 2051 } 2052 2053 if ($formatting !== NULL && in_array($column_type, array('integer', 'boolean'))) { 2054 throw new fProgrammerException( 2055 'The column specified, %s, does not support any formatting options', 2056 $column 2057 ); 2058 } 2059 2060 // If the column doesn't exist, we are just pulling the 2061 // value from a get method, so treat it as text 2062 } else { 2063 $column_type = 'text'; 1939 2064 } 1940 2065 1941 2066 // Grab the value for empty value checking 1942 $method_name = 'get' . fGrammar::camelize($column, TRUE); 1943 $value = $this->$method_name(); 2067 $value = $this->$method_name(); 1944 2068 1945 2069 // Date/time objects … … 2449 2573 * @throws fValidationException When ::validate() throws an exception 2450 2574 * 2575 * @param boolean $force_cascade When storing related records, this will force deleting child records even if they have their own children in a relationship with an RESTRICT or NO ACTION for the ON DELETE clause 2451 2576 * @return fActiveRecord The record object, to allow for method chaining 2452 2577 */ 2453 public function store( )2578 public function store($force_cascade=FALSE) 2454 2579 { 2455 2580 $class = get_class($this); … … 2529 2654 2530 2655 // Storing *-to-many relationships 2531 fORMRelated::store($class, $this->values, $this->related_records );2656 fORMRelated::store($class, $this->values, $this->related_records, $force_cascade); 2532 2657 2533 2658 fORMRelated.php
r726 r735 Hide Line Numbers 13 13 * @link http://flourishlib.com/fORMRelated 14 14 * 15 * @version 1.0.0b20 15 * @version 1.0.0b21 16 * @changes 1.0.0b21 Added support for the $force_cascade parameter of fActiveRecord::store(), added ::hasRecords() and fixed a bug with creating non-existent one-to-one related records [wb, 2009-12-16] 16 17 * @changes 1.0.0b20 Updated code for the new fORMDatabase and fORMSchema APIs [wb, 2009-10-28] 17 18 * @changes 1.0.0b19 Internal Backwards Compatibility Break - Added the `$class` parameter to ::storeManyToMany() - also fixed ::countRecords() to work across all databases, changed SQL statements to use value placeholders, identifier escaping and support schemas [wb, 2009-10-22] … … 46 47 const getOrderBys = 'fORMRelated::getOrderBys'; 47 48 const getRelatedRecordName = 'fORMRelated::getRelatedRecordName'; 49 const hasRecords = 'fORMRelated::hasRecords'; 48 50 const linkRecords = 'fORMRelated::linkRecords'; 49 51 const overrideRelatedRecordName = 'fORMRelated::overrideRelatedRecordName'; … … 362 364 // If the value is NULL, don't pass it to the constructor because an fNotFoundException will be thrown 363 365 if ($values[$relationship['column']] !== NULL) { 364 $records = array(new $related_class(array($relationship['related_column'] => $values[$relationship['column']]))); 366 try { 367 $records = array(new $related_class(array($relationship['related_column'] => $values[$relationship['column']]))); 368 } catch (fNotFoundException $e) { 369 $records = array(); 370 } 365 371 } else { 366 372 $records = array(); … … 660 666 661 667 /** 668 * Indicates if a record has a one-to-one or any *-to-many related records 669 * 670 * @internal 671 * 672 * @param string $class The class to check related records for 673 * @param array &$values The values for the record we are checking 674 * @param array &$related_records The related records for the record we are checking 675 * @param string $related_class The related class we are checking for 676 * @param string $route The route to the related class 677 * @return void 678 */ 679 static public function hasRecords($class, &$values, &$related_records, $related_class, $route=NULL) 680 { 681 $table = fORM::tablize($class); 682 $related_table = fORM::tablize($related_class); 683 684 $schema = fORMSchema::retrieve($class); 685 $route = fORMSchema::getRouteName($schema, $table, $related_table, $route, '!many-to-one'); 686 687 if (!isset($related_records[$related_table][$route]['count'])) { 688 if (fORMSchema::isOneToOne($schema, $table, $related_table, $route)) { 689 self::createRecord($class, $values, $related_records, $related_class, $route); 690 } else { 691 self::countRecords($class, $values, $related_records, $related_class, $route); 692 } 693 } 694 695 return (boolean) $related_records[$related_table][$route]['count']; 696 } 697 698 699 /** 662 700 * Parses associations for many-to-many relationships from the page request 663 701 * … … 1246 1284 * @internal 1247 1285 * 1248 * @param string $class The class to store the related records for 1249 * @param array &$values The current values for the main record being stored 1250 * @param array &$related_records The related records array 1286 * @param string $class The class to store the related records for 1287 * @param array &$values The current values for the main record being stored 1288 * @param array &$related_records The related records array 1289 * @param boolean $force_cascade This flag will be passed to the fActiveRecord::delete() method on related records that are being deleted 1251 1290 * @return void 1252 1291 */ 1253 static public function store($class, &$values, &$related_records )1292 static public function store($class, &$values, &$related_records, $force_cascade) 1254 1293 { 1255 1294 $table = fORM::tablize($class); … … 1266 1305 fORMRelated::storeManyToMany($class, $values, $relationship, $related_info); 1267 1306 } else { 1268 fORMRelated::storeOneToStar($class, $values, $related_records, fORM::classize($related_table), $route );1307 fORMRelated::storeOneToStar($class, $values, $related_records, fORM::classize($related_table), $route, $force_cascade); 1269 1308 } 1270 1309 } … … 1355 1394 * @internal 1356 1395 * 1357 * @param string $class The class to store the related records for 1358 * @param array &$values The current values for the main record being stored 1359 * @param array &$related_records The related records array 1360 * @param string $related_class The related class being stored 1361 * @param string $route The route to the related class 1396 * @param string $class The class to store the related records for 1397 * @param array &$values The current values for the main record being stored 1398 * @param array &$related_records The related records array 1399 * @param string $related_class The related class being stored 1400 * @param string $route The route to the related class 1401 * @param boolean $force_cascade This flag will be passed to the fActiveRecord::delete() method on related records that are being deleted 1362 1402 * @return void 1363 1403 */ 1364 static public function storeOneToStar($class, &$values, &$related_records, $related_class, $route )1404 static public function storeOneToStar($class, &$values, &$related_records, $related_class, $route, $force_cascade) 1365 1405 { 1366 1406 $table = fORM::tablize($class); … … 1391 1431 foreach ($primary_keys_to_delete as $primary_key_to_delete) { 1392 1432 $object_to_delete = new $related_class($primary_key_to_delete); 1393 $object_to_delete->delete( );1433 $object_to_delete->delete($force_cascade); 1394 1434 } 1395 1435 fORMSchema.php
r726 r735 Hide Line Numbers 125 125 * @param string $related_table The related table we are trying to find the routes for 126 126 * @param string $route The route that was preselected, will be verified if present 127 * @param string $relationship_type The relationship type: `NULL`, `'*-to-many'`, `'*-to-one'`, `'!many-to-one'`, `'one-to-one'`, `'one-to-m eny'`, `'many-to-one'`, `'many-to-many'`127 * @param string $relationship_type The relationship type: `NULL`, `'*-to-many'`, `'*-to-one'`, `'!many-to-one'`, `'one-to-one'`, `'one-to-many'`, `'many-to-one'`, `'many-to-many'` 128 128 * @return string The only route from the main table to the related table 129 129 */ … … 227 227 * @param string $table The main table we are searching on behalf of 228 228 * @param string $related_table The related table we are trying to find the routes for 229 * @param string $relationship_type The relationship type: `NULL`, `'*-to-many'`, `'*-to-one'`, `'!many-to-one'`, `'one-to-one'`, `'one-to-m eny'`, `'many-to-one'`, `'many-to-many'`229 * @param string $relationship_type The relationship type: `NULL`, `'*-to-many'`, `'*-to-one'`, `'!many-to-one'`, `'one-to-one'`, `'one-to-many'`, `'many-to-one'`, `'many-to-many'` 230 230 * @return array All of the routes from the main table to the related table 231 231 */ fSchema.php
r730 r735 Hide Line Numbers 10 10 * @link http://flourishlib.com/fSchema 11 11 * 12 * @version 1.0.0b28 12 * @version 1.0.0b29 13 * @changes 1.0.0b29 Added on_delete and on_update elements to one-to-one relationship info retrieved by ::getRelationships() [wb, 2009-12-16] 13 14 * @changes 1.0.0b28 Fixed a bug with detecting some multi-column unique constraints in SQL Server databases [wb, 2009-11-13] 14 15 * @changes 1.0.0b27 Added a parameter to ::enableCaching() to provide a key token that will allow cached values to be shared between multiple databases with the same schema [wb, 2009-10-28] … … 1598 1599 $temp['related_table'] = $table; 1599 1600 $temp['related_column'] = $key['column']; 1600 if ($type == 'one-to-many') { 1601 $temp['on_delete'] = $key['on_delete']; 1602 $temp['on_update'] = $key['on_update']; 1603 } 1601 $temp['on_delete'] = $key['on_delete']; 1602 $temp['on_update'] = $key['on_update']; 1604 1603 $this->relationships[$key['foreign_table']][$type][] = $temp; 1605 1604 } … … 1622 1621 $temp['related_column'] = $key['foreign_column']; 1623 1622 $type = ($this->checkForSingleColumnUniqueKey($table, $key['column'])) ? 'one-to-one' : 'many-to-one'; 1623 if ($type == 'one-to-one') { 1624 $temp['on_delete'] = $key['on_delete']; 1625 $temp['on_update'] = $key['on_update']; 1626 } 1624 1627 $this->relationships[$table][$type][] = $temp; 1625 1628 } … … 1903 1906 * 'column' => (string) {the column in the specified table}, 1904 1907 * 'related_table' => (string) {the related table}, 1905 * 'related_column' => (string) {the related column} 1908 * 'related_column' => (string) {the related column}, 1909 * 'on_delete' => (string) {the ON DELETE action: 'no_action', 'restrict', 'cascade', 'set_null', or 'set_default'}, 1910 * 'on_update' => (string) {the ON UPDATE action: 'no_action', 'restrict', 'cascade', 'set_null', or 'set_default'} 1906 1911 * ), ... 1907 1912 * ),
