UnionOfRAD/lithium — pull request #855 by al-the-x (2013-03-08 22:45:27+00:00)
Title: `\lithium\data\source\Database::_cast()` should delegate to vendor-specific adapters when casting column types such as `timestamp` to their native values

MySQL, for example, recognizes the constant `CURRENT_TIMESTAMP` for `timestamp` columns, but if you set that as a value on a model field, li3 currently bungles it into an invalid timestamp representation.

Granted, no one is likely to ever set a field to `(string) CURRENT_TIMESTAMP` explicitly, but if that value is registered as the default for the column (i.e. `created_on timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP`), then schema introspection will do it for you on save, update, etc.

I believe strongly that 29d51203c091f15c833b6274513420553546aaaa introduced this bug. You'll note that the check for `(string) CURRENT_TIMESTAMP` in `lithium\data\source\Database` was removed in favor of `_cast()` (a better implementation, IMO). The test for the same was changed to check for `(object) CURRENT_TIMESTAMP` returning `(string) CURRENT_TIMESTAMP`, but I'm not sure when (if ever) the default value for a column would ever get set to `(object) CURRENT_TIMESTAMP` as a part of schema reflection.

The problem as I see it exists in `Database::_cast():965-967`:

```php
$column = $this->_columns[$type];

switch ($column['formatter']) {
case 'date':
return $column['formatter']($column['format'], strtotime($value));
default:
return $column['formatter']($value);
}
```

If you stare long enough at the code, you'll realize that `$column['formatter']` is the string `date` for all the standard date and time columns and gets treated as the PHP function `date()` in this case. That's not really the problem, though, it's the call to `date($column['format'], strtotime($value))`:

# `strtotime('CURRENT_TIMESTAMP') === false`
# `date('Y-m-d H:i:s', false) === "1970-01-01 00:00:00"`
# [MySQL recognizes the start of the epoch as `1970-01-01 00:00:01`](http://dev.mysql.com/doc/refman/5.5/en/datetime.html) (note the `01`)

So PHP's epoch is actually an invalid timestamp string, resulting in `0000-00-00 00:00:00` being inserted into the column for any field set to `CURRENT_TIMESTAMP`.

To solve this problem, _I recommend delegating to the vendor-specific adapter_ within `\lithium\data\source\Database::_cast()` instead (see attached). I know there are no tests to support that change yet; I'm still writing them.