Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add casting to Eloquent #5004

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 117 additions & 26 deletions src/Illuminate/Database/Eloquent/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ abstract class Model implements ArrayAccess, ArrayableInterface, JsonableInterfa
*/
protected $dates = array();

/**
* Attributes to cast to their proper type.
*
* @var array
*/
protected $casts = array();

/**
* The relationships that should be touched on save.
*
Expand Down Expand Up @@ -213,6 +220,13 @@ abstract class Model implements ArrayAccess, ArrayableInterface, JsonableInterfa
*/
protected static $mutatorCache = array();

/**
* The cache of the cast array for each class.
*
* @var array
*/
protected static $castsCache = array();

/**
* The many to many relationship methods.
*
Expand Down Expand Up @@ -295,6 +309,8 @@ protected static function boot()
}

static::bootTraits();

static::cacheCasts();
}

/**
Expand Down Expand Up @@ -2167,11 +2183,12 @@ public function attributesToArray()
// If an attribute is a date, we will cast it to a string after converting it
// to a DateTime / Carbon instance. This is so we will get some consistent
// formatting while accessing attributes vs. arraying / JSONing a model.
foreach ($this->getDates() as $key)
foreach ($attributes as $key => $value)
{
if ( ! isset($attributes[$key])) continue;

$attributes[$key] = (string) $this->asDateTime($attributes[$key]);
if ($value instanceof DateTime)
{
$attributes[$key] = (string) $value;
}
}

// We want to spin through all the mutated attributes for this model and call
Expand Down Expand Up @@ -2337,14 +2354,6 @@ protected function getAttributeValue($key)
return $this->mutateAttribute($key, $value);
}

// If the attribute is listed as a date, we will convert it to a DateTime
// instance on retrieval, which makes it quite convenient to work with
// date fields without having to create a mutator for each property.
elseif (in_array($key, $this->getDates()))
{
if ($value) return $this->asDateTime($value);
}

return $value;
}

Expand Down Expand Up @@ -2440,18 +2449,7 @@ public function setAttribute($key, $value)
return $this->{$method}($value);
}

// If an attribute is listed as a "date", we'll convert it from a DateTime
// instance into a form proper for storage on the database tables using
// the connection grammar's date format. We will auto set the values.
elseif (in_array($key, $this->getDates()))
{
if ($value)
{
$value = $this->fromDateTime($value);
}
}

$this->attributes[$key] = $value;
$this->setRawAttribute($key, $value);
}

/**
Expand All @@ -2465,6 +2463,62 @@ public function hasSetMutator($key)
return method_exists($this, 'set'.studly_case($key).'Attribute');
}

/**
* Cache the cast array for legacy support.
*
* @return void
*/
static protected function cacheCasts()
{
$class = get_class($instance = new static);

static::$castsCache[$class] = $instance->casts;

foreach ($instance->getDates() as $key)
{
static::$castsCache[$class][$key] = 'date';
}
}

/**
* Add an attribute to the cast array.
*
* @param string $attribute
* @param string $type
*/
protected function addCast($attribute, $type)
{
$class = get_class($this);

static::$castsCache[$class][$attribute] = $type;
}

/**
* Get the cast type for a given attribute.
*
* @param string $attribute
* @return string|null
*/
protected function getCastType($attribute)
{
$casts = $this->getCasts();

if (array_key_exists($attribute, $casts))
{
return $casts[$attribute];
}
}

/**
* Get the casts array for the current class.
*
* @return array
*/
protected function getCasts()
{
return static::$castsCache[get_class($this)];
}

/**
* Get the attributes that should be converted to dates.
*
Expand Down Expand Up @@ -2594,19 +2648,56 @@ public function getAttributes()
}

/**
* Set the array of model attributes. No checking is done.
* Set the array of model attributes. No mutators are called.
*
* @param array $attributes
* @param bool $sync
* @return void
*/
public function setRawAttributes(array $attributes, $sync = false)
{
$this->attributes = $attributes;
$this->attributes = [];

foreach ($attributes as $key => $value)
{
$this->setRawAttribute($key, $value);
}

if ($sync) $this->syncOriginal();
}

/**
* Set a given attribute on the model. No mutators are called.
*
* @param string $key
* @param mixed $value
* @return void
*/
protected function setRawAttribute($key, $value)
{
$this->attributes[$key] = $this->castAttribute($key, $value);
}

/**
* Cast an attribute to its proper type.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function castAttribute($key, $value)
{
if (is_null($value)) return null;

if (is_null($type = $this->getCastType($key))) return $value;

if ($type == 'date') return $this->asDateTime($value);

settype($value, $type);

return $value;
}

/**
* Get the model's original attribute values.
*
Expand Down
4 changes: 4 additions & 0 deletions src/Illuminate/Database/Eloquent/SoftDeletingTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ trait SoftDeletingTrait {
public static function bootSoftDeletingTrait()
{
static::addGlobalScope(new SoftDeletingScope);

$instance = new static;

$instance->addCast($instance->getDeletedAtColumn(), 'date');
}

/**
Expand Down