Skip to content

Commit 1f0cc82

Browse files
committed
Add casting to Eloquent
1 parent e54204b commit 1f0cc82

File tree

2 files changed

+121
-26
lines changed

2 files changed

+121
-26
lines changed

src/Illuminate/Database/Eloquent/Model.php

Lines changed: 117 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ abstract class Model implements ArrayAccess, ArrayableInterface, JsonableInterfa
129129
*/
130130
protected $dates = array();
131131

132+
/**
133+
* Attributes to cast to their proper type.
134+
*
135+
* @var array
136+
*/
137+
protected $casts = array();
138+
132139
/**
133140
* The relationships that should be touched on save.
134141
*
@@ -213,6 +220,13 @@ abstract class Model implements ArrayAccess, ArrayableInterface, JsonableInterfa
213220
*/
214221
protected static $mutatorCache = array();
215222

223+
/**
224+
* The cache of the cast array for each class.
225+
*
226+
* @var array
227+
*/
228+
protected static $castsCache = array();
229+
216230
/**
217231
* The many to many relationship methods.
218232
*
@@ -295,6 +309,8 @@ protected static function boot()
295309
}
296310

297311
static::bootTraits();
312+
313+
static::cacheCasts();
298314
}
299315

300316
/**
@@ -2167,11 +2183,12 @@ public function attributesToArray()
21672183
// If an attribute is a date, we will cast it to a string after converting it
21682184
// to a DateTime / Carbon instance. This is so we will get some consistent
21692185
// formatting while accessing attributes vs. arraying / JSONing a model.
2170-
foreach ($this->getDates() as $key)
2186+
foreach ($attributes as $key => $value)
21712187
{
2172-
if ( ! isset($attributes[$key])) continue;
2173-
2174-
$attributes[$key] = (string) $this->asDateTime($attributes[$key]);
2188+
if ($value instanceof DateTime)
2189+
{
2190+
$attributes[$key] = (string) $value;
2191+
}
21752192
}
21762193

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

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

@@ -2440,18 +2449,7 @@ public function setAttribute($key, $value)
24402449
return $this->{$method}($value);
24412450
}
24422451

2443-
// If an attribute is listed as a "date", we'll convert it from a DateTime
2444-
// instance into a form proper for storage on the database tables using
2445-
// the connection grammar's date format. We will auto set the values.
2446-
elseif (in_array($key, $this->getDates()))
2447-
{
2448-
if ($value)
2449-
{
2450-
$value = $this->fromDateTime($value);
2451-
}
2452-
}
2453-
2454-
$this->attributes[$key] = $value;
2452+
$this->setRawAttribute($key, $value);
24552453
}
24562454

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

2466+
/**
2467+
* Cache the cast array for legacy support.
2468+
*
2469+
* @return void
2470+
*/
2471+
static protected function cacheCasts()
2472+
{
2473+
$class = get_class($instance = new static);
2474+
2475+
static::$castsCache[$class] = $instance->casts;
2476+
2477+
foreach ($instance->getDates() as $key)
2478+
{
2479+
static::$castsCache[$class][$key] = 'date';
2480+
}
2481+
}
2482+
2483+
/**
2484+
* Add an attribute to the cast array.
2485+
*
2486+
* @param string $attribute
2487+
* @param string $type
2488+
*/
2489+
protected function addCast($attribute, $type)
2490+
{
2491+
$class = get_class($this);
2492+
2493+
static::$castsCache[$class][$attribute] = $type;
2494+
}
2495+
2496+
/**
2497+
* Get the cast type for a given attribute.
2498+
*
2499+
* @param string $attribute
2500+
* @return string|null
2501+
*/
2502+
protected function getCastType($attribute)
2503+
{
2504+
$casts = $this->getCasts();
2505+
2506+
if (array_key_exists($attribute, $casts))
2507+
{
2508+
return $casts[$attribute];
2509+
}
2510+
}
2511+
2512+
/**
2513+
* Get the casts array for the current class.
2514+
*
2515+
* @return array
2516+
*/
2517+
protected function getCasts()
2518+
{
2519+
return static::$castsCache[get_class($this)];
2520+
}
2521+
24682522
/**
24692523
* Get the attributes that should be converted to dates.
24702524
*
@@ -2594,19 +2648,56 @@ public function getAttributes()
25942648
}
25952649

25962650
/**
2597-
* Set the array of model attributes. No checking is done.
2651+
* Set the array of model attributes. No mutators are called.
25982652
*
25992653
* @param array $attributes
26002654
* @param bool $sync
26012655
* @return void
26022656
*/
26032657
public function setRawAttributes(array $attributes, $sync = false)
26042658
{
2605-
$this->attributes = $attributes;
2659+
$this->attributes = [];
2660+
2661+
foreach ($attributes as $key => $value)
2662+
{
2663+
$this->setRawAttribute($key, $value);
2664+
}
26062665

26072666
if ($sync) $this->syncOriginal();
26082667
}
26092668

2669+
/**
2670+
* Set a given attribute on the model. No mutators are called.
2671+
*
2672+
* @param string $key
2673+
* @param mixed $value
2674+
* @return void
2675+
*/
2676+
protected function setRawAttribute($key, $value)
2677+
{
2678+
$this->attributes[$key] = $this->castAttribute($key, $value);
2679+
}
2680+
2681+
/**
2682+
* Cast an attribute to its proper type.
2683+
*
2684+
* @param string $key
2685+
* @param mixed $value
2686+
* @return mixed
2687+
*/
2688+
protected function castAttribute($key, $value)
2689+
{
2690+
if (is_null($value)) return null;
2691+
2692+
if (is_null($type = $this->getCastType($key))) return $value;
2693+
2694+
if ($type == 'date') return $this->asDateTime($value);
2695+
2696+
settype($value, $type);
2697+
2698+
return $value;
2699+
}
2700+
26102701
/**
26112702
* Get the model's original attribute values.
26122703
*

src/Illuminate/Database/Eloquent/SoftDeletingTrait.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ trait SoftDeletingTrait {
1717
public static function bootSoftDeletingTrait()
1818
{
1919
static::addGlobalScope(new SoftDeletingScope);
20+
21+
$instance = new static;
22+
23+
$instance->addCast($instance->getDeletedAtColumn(), 'date');
2024
}
2125

2226
/**

0 commit comments

Comments
 (0)