22
33namespace Illuminate \Database \Eloquent \Concerns ;
44
5+ use Illuminate \Container \Container ;
6+ use Illuminate \Contracts \Container \BindingResolutionException ;
7+ use Illuminate \Contracts \Database \Eloquent \Castable ;
58use Illuminate \Contracts \Support \Arrayable ;
69use Illuminate \Database \Eloquent \JsonEncodingException ;
710use Illuminate \Support \Collection ;
@@ -25,11 +28,13 @@ trait HasCasts
2528 */
2629 public function hasCast ($ key , $ types = null )
2730 {
28- if (array_key_exists ($ key , $ this ->getCasts ())) {
29- return $ types ? in_array ( $ this -> getCastType ( $ key ), ( array ) $ types , true ) : true ;
31+ if (! array_key_exists ($ key , $ this ->getCasts ())) {
32+ return false ;
3033 }
3134
32- return false ;
35+ return $ types
36+ ? in_array ($ this ->getCastType ($ key ), (array ) $ types , true )
37+ : true ;
3338 }
3439
3540 /**
@@ -39,11 +44,14 @@ public function hasCast($key, $types = null)
3944 */
4045 public function getCasts ()
4146 {
42- if ($ this ->getIncrementing ()) {
43- return array_merge ([$ this ->getKeyName () => $ this ->getKeyType ()], $ this ->casts );
44- }
47+ return $ this ->getIncrementing ()
48+ ? array_merge ([$ this ->getKeyName () => $ this ->getKeyType ()], $ this ->casts )
49+ : $ this ->casts ;
50+ }
4551
46- return $ this ->casts ;
52+ public function getCast ($ key )
53+ {
54+ return $ this ->getCasts ()[$ key ] ?? null ;
4755 }
4856
4957 /**
@@ -52,6 +60,8 @@ public function getCasts()
5260 * @param string $key
5361 * @param mixed $current
5462 *
63+ * @throws BindingResolutionException
64+ *
5565 * @return bool
5666 */
5767 public function originalIsEquivalent ($ key , $ current )
@@ -87,6 +97,8 @@ public function originalIsEquivalent($key, $current)
8797 * @param array $attributes
8898 * @param array $mutatedAttributes
8999 *
100+ * @throws BindingResolutionException
101+ *
90102 * @return array
91103 */
92104 protected function addCastAttributesToArray (array $ attributes , array $ mutatedAttributes )
@@ -106,12 +118,11 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt
106118 // If the attribute cast was a date or a datetime, we will serialize the date as
107119 // a string. This allows the developers to customize how dates are serialized
108120 // into an array without affecting how they are persisted into the storage.
109- if ($ attributes [$ key ] &&
110- ($ value === 'date ' || $ value === 'datetime ' )) {
121+ if (($ value === 'date ' || $ value === 'datetime ' )) {
111122 $ attributes [$ key ] = $ this ->serializeDate ($ attributes [$ key ]);
112123 }
113124
114- if ($ attributes [ $ key ] && $ this ->isCustomDateTimeCast ($ value )) {
125+ if ($ this ->isCustomDateTimeCast ($ value )) {
115126 $ attributes [$ key ] = $ attributes [$ key ]->format (explode (': ' , $ value , 2 )[1 ]);
116127 }
117128
@@ -129,9 +140,11 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt
129140 * @param string $key
130141 * @param mixed $value
131142 *
143+ * @throws BindingResolutionException
144+ *
132145 * @return mixed
133146 */
134- protected function castAttribute ($ key , $ value )
147+ protected function castAttribute ($ key , $ value = null )
135148 {
136149 if (is_null ($ value )) {
137150 return $ value ;
@@ -146,7 +159,7 @@ protected function castAttribute($key, $value)
146159 case 'double ' :
147160 return $ this ->fromFloat ($ value );
148161 case 'decimal ' :
149- return $ this ->asDecimal ($ value , explode (': ' , $ this ->getCasts ()[ $ key] , 2 )[1 ]);
162+ return $ this ->asDecimal ($ value , explode (': ' , $ this ->getCast ( $ key) , 2 )[1 ]);
150163 case 'string ' :
151164 return (string ) $ value ;
152165 case 'bool ' :
@@ -167,7 +180,9 @@ protected function castAttribute($key, $value)
167180 case 'timestamp ' :
168181 return $ this ->asTimestamp ($ value );
169182 default :
170- return $ value ;
183+ return $ this ->isCustomCastable ($ key )
184+ ? $ this ->fromCustomCastable ($ key , $ value )
185+ : $ value ;
171186 }
172187 }
173188
@@ -180,15 +195,17 @@ protected function castAttribute($key, $value)
180195 */
181196 protected function getCastType ($ key )
182197 {
183- if ($ this ->isCustomDateTimeCast ($ this ->getCasts ()[$ key ])) {
198+ $ cast = $ this ->getCast ($ key );
199+
200+ if ($ this ->isCustomDateTimeCast ($ cast )) {
184201 return 'custom_datetime ' ;
185202 }
186203
187- if ($ this ->isDecimalCast ($ this -> getCasts ()[ $ key ] )) {
204+ if ($ this ->isDecimalCast ($ cast )) {
188205 return 'decimal ' ;
189206 }
190207
191- return trim (strtolower ($ this -> getCasts ()[ $ key ] ));
208+ return trim (strtolower ($ cast ));
192209 }
193210
194211 /**
@@ -250,6 +267,22 @@ protected function isDateAttribute($key)
250267 $ this ->isDateCastable ($ key );
251268 }
252269
270+ /**
271+ * Is the checked value a custom Cast.
272+ *
273+ * @param string $key
274+ *
275+ * @return bool
276+ */
277+ protected function isCustomCastable ($ key )
278+ {
279+ if ($ cast = $ this ->getCast ($ key )) {
280+ return is_subclass_of ($ cast , Castable::class);
281+ }
282+
283+ return false ;
284+ }
285+
253286 /**
254287 * Determine whether a value is Date / DateTime castable for inbound manipulation.
255288 *
@@ -273,4 +306,49 @@ protected function isJsonCastable($key)
273306 {
274307 return $ this ->hasCast ($ key , ['array ' , 'json ' , 'object ' , 'collection ' ]);
275308 }
309+
310+ /**
311+ * Getting the execution result from a user Cast object.
312+ *
313+ * @param string $key
314+ * @param null $value
315+ *
316+ * @throws BindingResolutionException
317+ *
318+ * @return mixed
319+ */
320+ protected function fromCustomCastable ($ key , $ value = null )
321+ {
322+ return $ this
323+ ->normalizeHandlerToCallable ($ key )
324+ ->get ($ value );
325+ }
326+
327+ /**
328+ * @param $key
329+ * @param null $value
330+ *
331+ * @throws BindingResolutionException
332+ *
333+ * @return mixed
334+ */
335+ protected function toCustomCastable ($ key , $ value = null )
336+ {
337+ return $ this
338+ ->normalizeHandlerToCallable ($ key )
339+ ->set ($ value );
340+ }
341+
342+ /**
343+ * @param string $key
344+ *
345+ * @throws BindingResolutionException
346+ *
347+ * @return Castable
348+ */
349+ protected function normalizeHandlerToCallable ($ key )
350+ {
351+ return Container::getInstance ()
352+ ->make ($ this ->getCast ($ key ));
353+ }
276354}
0 commit comments