Skip to content

Commit

Permalink
Add casting to Eloquent
Browse files Browse the repository at this point in the history
  • Loading branch information
JosephSilber committed Jul 9, 2014
1 parent e54204b commit 1f0cc82
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 26 deletions.
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

0 comments on commit 1f0cc82

Please sign in to comment.