2121use Divergence \IO \Database \Query \Delete ;
2222use Divergence \IO \Database \Query \Insert ;
2323use Divergence \IO \Database \Query \Update ;
24- use Divergence \Models \Interfaces \ FieldSetMapper ;
25- use Divergence \Models \SetMappers \DefaultSetMapper ;
24+ use Divergence \Models \Mapping \ DefaultGetMapper ;
25+ use Divergence \Models \Mapping \DefaultSetMapper ;
2626
2727/**
2828 * ActiveRecord
@@ -290,9 +290,9 @@ class ActiveRecord implements JsonSerializable
290290 */
291291 protected $ _isUpdated ;
292292
293- /** Field Mapper */
294- protected ?FieldSetMapper $ fieldSetMapper ;
295293
294+ public const defaultSetMapper = DefaultSetMapper::class;
295+ public const defaultGetMapper = DefaultGetMapper::class;
296296 /**
297297 * __construct Instantiates a Model and returns.
298298 *
@@ -404,6 +404,11 @@ public function getPrimaryKeyValue()
404404 public static function init ()
405405 {
406406 $ className = get_called_class ();
407+
408+ $ className ::$ rootClass = $ className ::$ rootClass ?? $ className ;
409+ $ className ::$ defaultClass = $ className ::$ defaultClass ?? $ className ;
410+ $ className ::$ subClasses = $ className ::$ subClasses ?? [$ className ];
411+
407412 if (empty (static ::$ _fieldsDefined [$ className ])) {
408413 static ::_defineFields ();
409414 static ::_initFields ();
@@ -1118,7 +1123,7 @@ public static function _definedAttributeFields(): array
11181123 // skip these because they are built in
11191124 if (in_array ($ property ->getName (), [
11201125 '_classFields ' ,'_classRelationships ' ,'_classBeforeSave ' ,'_classAfterSave ' ,'_fieldsDefined ' ,'_relationshipsDefined ' ,'_eventsDefined ' ,'_record ' ,'_validator '
1121- ,'_validationErrors ' ,'_isDirty ' ,'_isValid ' ,'fieldSetMapper ' , ' _convertedValues ' ,'_originalValues ' ,'_isPhantom ' ,'_wasPhantom ' ,'_isNew ' ,'_isUpdated ' ,'_relatedObjects '
1126+ ,'_validationErrors ' ,'_isDirty ' ,'_isValid ' ,'_convertedValues ' ,'_originalValues ' ,'_isPhantom ' ,'_wasPhantom ' ,'_isNew ' ,'_isUpdated ' ,'_relatedObjects '
11221127 ])) {
11231128 continue ;
11241129 }
@@ -1245,8 +1250,21 @@ protected static function _cn($field)
12451250 }
12461251
12471252
1253+ private function applyNewValue ($ type , $ field , $ value )
1254+ {
1255+ if (!isset ($ this ->_convertedValues [$ field ])) {
1256+ if (is_null ($ value ) && !in_array ($ type , ['set ' ,'list ' ])) {
1257+ unset($ this ->_convertedValues [$ field ]);
1258+ return null ;
1259+ }
1260+ $ this ->_convertedValues [$ field ] = $ value ;
1261+ }
1262+ return $ this ->_convertedValues [$ field ];
1263+ }
1264+
12481265 /**
1249- * Retrieves given field's value
1266+ * Applies type-dependent transformations to the value in $this->_record[$fieldOptions['columnName']]
1267+ * Caches to $this->_convertedValues[$field] and returns the value in there.
12501268 * @param string $field Name of field
12511269 * @return mixed value
12521270 */
@@ -1257,81 +1275,34 @@ protected function _getFieldValue($field, $useDefault = true)
12571275 if (isset ($ this ->_record [$ fieldOptions ['columnName ' ]])) {
12581276 $ value = $ this ->_record [$ fieldOptions ['columnName ' ]];
12591277
1278+ $ defaultGetMapper = static ::defaultGetMapper;
1279+
12601280 // apply type-dependent transformations
12611281 switch ($ fieldOptions ['type ' ]) {
1262- case 'password ' :
1263- {
1264- return $ value ;
1265- }
1266-
12671282 case 'timestamp ' :
1268- {
1269- if (!isset ($ this ->_convertedValues [$ field ])) {
1270- if ($ value && is_string ($ value ) && $ value != '0000-00-00 00:00:00 ' ) {
1271- $ this ->_convertedValues [$ field ] = strtotime ($ value );
1272- } elseif (is_integer ($ value )) {
1273- $ this ->_convertedValues [$ field ] = $ value ;
1274- } else {
1275- unset($ this ->_convertedValues [$ field ]);
1276- }
1277- }
1283+ return $ this ->applyNewValue ($ fieldOptions ['type ' ], $ field , $ defaultGetMapper ::getTimestampValue ($ value ));
12781284
1279- return $ this ->_convertedValues [$ field ];
1280- }
12811285 case 'serialized ' :
1282- {
1283- if (!isset ($ this ->_convertedValues [$ field ])) {
1284- $ this ->_convertedValues [$ field ] = is_string ($ value ) ? unserialize ($ value ) : $ value ;
1285- }
1286+ return $ this ->applyNewValue ($ fieldOptions ['type ' ], $ field , $ defaultGetMapper ::getSerializedValue ($ value ));
12861287
1287- return $ this ->_convertedValues [$ field ];
1288- }
12891288 case 'set ' :
12901289 case 'list ' :
1291- {
1292- if (!isset ($ this ->_convertedValues [$ field ])) {
1293- $ delim = empty ($ fieldOptions ['delimiter ' ]) ? ', ' : $ fieldOptions ['delimiter ' ];
1294- $ this ->_convertedValues [$ field ] = array_filter (preg_split ('/\s* ' .$ delim .'\s*/ ' , $ value ));
1295- }
1296-
1297- return $ this ->_convertedValues [$ field ];
1298- }
1290+ return $ this ->applyNewValue ($ fieldOptions ['type ' ], $ field , $ defaultGetMapper ::getListValue ($ value , $ fieldOptions ['delimiter ' ]));
12991291
13001292 case 'int ' :
13011293 case 'integer ' :
13021294 case 'uint ' :
1303- if (!isset ($ this ->_convertedValues [$ field ])) {
1304- if (!$ fieldOptions ['notnull ' ] && is_null ($ value )) {
1305- $ this ->_convertedValues [$ field ] = $ value ;
1306- } else {
1307- $ this ->_convertedValues [$ field ] = intval ($ value );
1308- }
1309- }
1310- return $ this ->_convertedValues [$ field ];
1295+ return $ this ->applyNewValue ($ fieldOptions ['type ' ], $ field , $ defaultGetMapper ::getIntegerValue ($ value ));
13111296
13121297 case 'boolean ' :
1313- {
1314- if (!isset ($ this ->_convertedValues [$ field ])) {
1315- $ this ->_convertedValues [$ field ] = (bool )$ value ;
1316- }
1317-
1318- return $ this ->_convertedValues [$ field ];
1319- }
1298+ return $ this ->applyNewValue ($ fieldOptions ['type ' ], $ field , $ defaultGetMapper ::getBooleanValue ($ value ));
13201299
13211300 case 'decimal ' :
1322- if (!isset ($ this ->_convertedValues [$ field ])) {
1323- if (!$ fieldOptions ['notnull ' ] && is_null ($ value )) {
1324- $ this ->_convertedValues [$ field ] = $ value ;
1325- } else {
1326- $ this ->_convertedValues [$ field ] = floatval ($ value );
1327- }
1328- }
1329- return $ this ->_convertedValues [$ field ];
1301+ return $ this ->applyNewValue ($ fieldOptions ['type ' ], $ field , $ defaultGetMapper ::getDecimalValue ($ value ));
13301302
1303+ case 'password ' :
13311304 default :
1332- {
1333- return $ value ;
1334- }
1305+ return $ value ;
13351306 }
13361307 } elseif ($ useDefault && isset ($ fieldOptions ['default ' ])) {
13371308 // return default
@@ -1340,13 +1311,9 @@ protected function _getFieldValue($field, $useDefault = true)
13401311 switch ($ fieldOptions ['type ' ]) {
13411312 case 'set ' :
13421313 case 'list ' :
1343- {
1344- return [];
1345- }
1314+ return [];
13461315 default :
1347- {
1348- return null ;
1349- }
1316+ return null ;
13501317 }
13511318 }
13521319 }
@@ -1376,17 +1343,15 @@ protected function _setFieldValue($field, $value)
13761343 return false ;
13771344 }
13781345
1379- if (!isset ($ this ->fieldSetMapper )) {
1380- $ this ->fieldSetMapper = new DefaultSetMapper ();
1381- }
1346+ $ setMapper = static ::defaultSetMapper;
13821347
13831348 // pre-process value
13841349 $ forceDirty = false ;
13851350 switch ($ fieldOptions ['type ' ]) {
13861351 case 'clob ' :
13871352 case 'string ' :
13881353 {
1389- $ value = $ this -> fieldSetMapper -> setStringValue ($ value );
1354+ $ value = $ setMapper :: setStringValue ($ value );
13901355 if (!$ fieldOptions ['notnull ' ] && $ fieldOptions ['blankisnull ' ] && ($ value === '' || $ value === null )) {
13911356 $ value = null ;
13921357 }
@@ -1395,21 +1360,21 @@ protected function _setFieldValue($field, $value)
13951360
13961361 case 'boolean ' :
13971362 {
1398- $ value = $ this -> fieldSetMapper -> setBooleanValue ($ value );
1363+ $ value = $ setMapper :: setBooleanValue ($ value );
13991364 break ;
14001365 }
14011366
14021367 case 'decimal ' :
14031368 {
1404- $ value = $ this -> fieldSetMapper -> setDecimalValue ($ value );
1369+ $ value = $ setMapper :: setDecimalValue ($ value );
14051370 break ;
14061371 }
14071372
14081373 case 'int ' :
14091374 case 'uint ' :
14101375 case 'integer ' :
14111376 {
1412- $ value = $ this -> fieldSetMapper -> setIntegerValue ($ value );
1377+ $ value = $ setMapper :: setIntegerValue ($ value );
14131378 if (!$ fieldOptions ['notnull ' ] && ($ value === '' || is_null ($ value ))) {
14141379 $ value = null ;
14151380 }
@@ -1419,67 +1384,71 @@ protected function _setFieldValue($field, $value)
14191384 case 'timestamp ' :
14201385 {
14211386 unset($ this ->_convertedValues [$ field ]);
1422- $ value = $ this -> fieldSetMapper -> setTimestampValue ($ value );
1387+ $ value = $ setMapper :: setTimestampValue ($ value );
14231388 break ;
14241389 }
14251390
14261391 case 'date ' :
14271392 {
14281393 unset($ this ->_convertedValues [$ field ]);
1429- $ value = $ this -> fieldSetMapper -> setDateValue ($ value );
1394+ $ value = $ setMapper :: setDateValue ($ value );
14301395 break ;
14311396 }
14321397
1433- // these types are converted to strings from another PHP type on save
14341398 case 'serialized ' :
14351399 {
1436- // if the value is a string we assume it's already serialized data
14371400 if (!is_string ($ value )) {
1438- $ value = $ this -> fieldSetMapper -> setSerializedValue ($ value );
1401+ $ value = $ setMapper :: setSerializedValue ($ value );
14391402 }
14401403 break ;
14411404 }
14421405 case 'enum ' :
14431406 {
1444- $ value = $ this -> fieldSetMapper -> setEnumValue ($ fieldOptions ['values ' ], $ value );
1407+ $ value = $ setMapper :: setEnumValue ($ fieldOptions ['values ' ], $ value );
14451408 break ;
14461409 }
14471410 case 'set ' :
14481411 case 'list ' :
14491412 {
1450- $ value = $ this -> fieldSetMapper -> setListValue ($ value , isset ($ fieldOptions ['delimiter ' ]) ? $ fieldOptions ['delimiter ' ] : null );
1413+ $ value = $ setMapper :: setListValue ($ value , isset ($ fieldOptions ['delimiter ' ]) ? $ fieldOptions ['delimiter ' ] : null );
14511414 $ this ->_convertedValues [$ field ] = $ value ;
14521415 $ forceDirty = true ;
14531416 break ;
14541417 }
14551418 }
14561419
14571420 if ($ forceDirty || (empty ($ this ->_record [$ field ]) && isset ($ value )) || ($ this ->_record [$ field ] !== $ value )) {
1458- $ columnName = static ::_cn ($ field );
1459- if (isset ($ this ->_record [$ columnName ])) {
1460- $ this ->_originalValues [$ field ] = $ this ->_record [$ columnName ];
1461- }
1462- $ this ->_record [$ columnName ] = $ value ;
1463- // only set value if this is an attribute mapped field
1464- if (isset ($ this ->_classFields [get_called_class ()][$ columnName ]['attributeField ' ])) {
1465- $ this ->$ columnName = $ value ;
1466- }
1467- $ this ->_isDirty = true ;
1468-
1469- // unset invalidated relationships
1470- if (!empty ($ fieldOptions ['relationships ' ]) && static ::isRelational ()) {
1471- foreach ($ fieldOptions ['relationships ' ] as $ relationship => $ isCached ) {
1472- if ($ isCached ) {
1473- unset($ this ->_relatedObjects [$ relationship ]);
1474- }
1475- }
1476- }
1421+ $ this ->_setValueAndMarkDirty ($ field , $ value , $ fieldOptions );
14771422 return true ;
14781423 } else {
14791424 return false ;
14801425 }
14811426 }
14821427
1428+ protected function _setValueAndMarkDirty ($ field , $ value , $ fieldOptions )
1429+ {
1430+ $ columnName = static ::_cn ($ field );
1431+ if (isset ($ this ->_record [$ columnName ])) {
1432+ $ this ->_originalValues [$ field ] = $ this ->_record [$ columnName ];
1433+ }
1434+ $ this ->_record [$ columnName ] = $ value ;
1435+ // only set value if this is an attribute mapped field
1436+ if (isset (static ::$ _classFields [get_called_class ()][$ columnName ]['attributeField ' ])) {
1437+ $ this ->$ columnName = $ value ;
1438+ }
1439+ $ this ->_isDirty = true ;
1440+
1441+ // If a model has been modified we should clear the relationship cache
1442+ // TODO: this can be smarter by only looking at fields that are used in the relationship configuration
1443+ if (!empty ($ fieldOptions ['relationships ' ]) && static ::isRelational ()) {
1444+ foreach ($ fieldOptions ['relationships ' ] as $ relationship => $ isCached ) {
1445+ if ($ isCached ) {
1446+ unset($ this ->_relatedObjects [$ relationship ]);
1447+ }
1448+ }
1449+ }
1450+ }
1451+
14831452 protected function _prepareRecordValues ()
14841453 {
14851454 $ record = [];
0 commit comments