做蛋糕网站,编程网站scratch,即墨市网站建设,网站开发框架的主要作用教程#xff1a;Hyperf
属性类型转换 Hyperf\Database\Model\Concerns\HasAttributes::casts被HasAttributes::setAttribute()、HasAttributes::getAttribute()调用#xff0c;执行类型转换。 HasAttributes::casts为数组类型可设置基本类型或类的实例。默认设置主键id为int…教程Hyperf
属性类型转换 Hyperf\Database\Model\Concerns\HasAttributes::casts被HasAttributes::setAttribute()、HasAttributes::getAttribute()调用执行类型转换。 HasAttributes::casts为数组类型可设置基本类型或类的实例。默认设置主键id为int。 内置的基本强制转换类型
jsonarray, json, object, collection日期date, datetime整数int\integer浮点数 real\float\double数字decimal字符串string布尔bool/boolean自定义时间custom_datetime时间戳timestamp decimal 可设置小数位数格式decimal:小数位数通过number_format()实现。
一 自定义类型转换
通过继承接口implementsHyperf\Contract\CastsAttributes定义好后使用其类名称将其附加到HasAttributes::casts。
1.1 值对象类型转换
将值转换成对象。通过get()获取时设置为对象、set()设置时将值设置到对象中。
执行save()之前需要设置相应的对象。官网例子中是先获取在设置这样获取之后数据结构中自带类。
更改数据结构中类对象值后因为缓存原因其类的值不会通过HasAttributes::getAttributes()获得刷新使用HasAttributes::syncAttributes()通过缓存和属性值合并可获取设置后的更新数据。
1.2 入站类型转换
设置set()实现入站类型转换。
1.3 类型参数转换
使用“:”设置参数。
protected $casts [secret Hash::class.:sha256,];
1.4 测试
获取
#App\Controlle\TestController
public function testmodifier() {$r Article::query()-find(2);$article $r-article;$istop $r-is_top;var_dump($istop);$r-article-intro test1;$info1 $r-getAttributes();$info2 $r-syncAttributes()-getAttributes();$r-intro test2;$info3 $r-getAttributes();var_dump($article, $info1, $info2, $info3);
}
#App1\Model\Article
protected $casts [id integer,created_at datetime,updated_at datetime,is_top boolean,article ArticleCasts::class,];
#App1\Attributes\Article
namespace App1\Attributes;class Article {public $title;public $content;public $intro;public function __construct($title, $intro, $content) {$this-title $title;$this-content $content;$this-intro $intro;}
}
#App1\Casts\ArticleCasts
namespace App1\Casts;use App1\Attributes\Article;
use Hyperf\Contract\CastsAttributes;class ArticleCasts implements CastsAttributes {/*** 将取出的数据进行转换*/public function get($model, $key, $value, $attributes): Article {return new Article($attributes[title],$attributes[intro],$attributes[content]);}/*** 转换成将要进行存储的值*/public function set($model, $key, $value, $attributes) {return [title $value-title,intro $value-intro,content $value-content,];}
} 测试结果
bool(false)
object(App1\Attributes\Article)#1213 (3) {[title]string(5) test2[content]NULL[intro]string(5) test1
}
array(10) {[id]int(2)[user_id]int(1)[title]string(5) test2[created_at]string(19) 2024-01-13 10:06:04[updated_at]string(19) 2024-01-13 10:06:06[deleted_at]NULL[pv_num]int(0)[intro]NULL[content]NULL[is_top]int(0)
}
array(10) {[id]int(2)[user_id]int(1)[title]string(5) test2[created_at]string(19) 2024-01-13 10:06:04[updated_at]string(19) 2024-01-13 10:06:06[deleted_at]NULL[pv_num]int(0)[intro]string(5) test1[content]NULL[is_top]int(0)
}
array(10) {[id]int(2)[user_id]int(1)[title]string(5) test2[created_at]string(19) 2024-01-13 10:06:04[updated_at]string(19) 2024-01-13 10:06:06[deleted_at]NULL[pv_num]int(0)[intro]string(5) test2[content]NULL[is_top]int(0)
} 写入
#App\Controlle\TestController
public function testmodifier() {$r Article::query()-find(2);$r-is_top 1;$r-article-intro test2;$attr $r-getAttributes();var_dump($attr);$r-save();$attr $r-getAttributes();var_dump($attr);
} 测试结果
array(10) {[id]int(2)[user_id]int(1)[title]string(5) test2[created_at]string(19) 2024-01-13 10:06:04[updated_at]string(19) 2024-03-25 09:47:00[deleted_at]NULL[pv_num]int(0)[intro]string(5) test1[content]NULL[is_top]int(1)
}
array(10) {[id]int(2)[user_id]int(1)[title]string(5) test2[created_at]string(19) 2024-01-13 10:06:04[updated_at]string(16) 2024-03-25 09:48[deleted_at]NULL[pv_num]int(0)[intro]string(5) test2[content]NULL[is_top]int(1)
}
1.5 源码
转换类型
#Hyperf\Database\Model\Concerns\HasAttributes
public function getAttribute($key){if (!$key) {return;}// If the attribute exists in the attribute array or has a get mutator we will// get the attributes value. Otherwise, we will proceed as if the developers// are asking for a relationships value. This covers both types of values.if (array_key_exists($key, $this-getAttributes())|| $this-hasGetMutator($key)|| $this-isClassCastable($key)) {return $this-getAttributeValue($key);}// Here we will determine if the model base class itself contains this given key// since we dont want to treat any of those methods as relationships because// they are all intended as helper methods and none of these are relations.if (method_exists(self::class, $key)) {return;}return $this-getRelationValue($key);}
protected function castAttribute($key, $value){$castType $this-getCastType($key);if (is_null($value) in_array($castType, static::$primitiveCastTypes)) {return $value;}switch ($castType) {case int:case integer:return (int) $value;case real:case float:case double:return $this-fromFloat($value);case decimal:return $this-asDecimal($value, explode(:, $this-getCasts()[$key], 2)[1]);case string:return (string) $value;case bool:case boolean:return (bool) $value;case object:return $this-fromJson($value, true);case array:case json:return $this-fromJson($value);case collection:return new BaseCollection($this-fromJson($value));case date:return $this-asDate($value);case datetime:case custom_datetime:return $this-asDateTime($value);case timestamp:return $this-asTimestamp($value);}if ($this-isClassCastable($key)) {return $this-getClassCastableAttributeValue($key, $value);}return $value;}
protected function asDecimal($value, $decimals){return number_format((float) $value, (int) $decimals, ., );}
protected function isDateCastable($key){return $this-hasCast($key, [date, datetime]);}
protected function isJsonCastable($key){return $this-hasCast($key, [array, json, object, collection]);}
public function getAttributeValue($key){return $this-transformModelValue($key, $this-getAttributeFromArray($key));}
protected function transformModelValue($key, $value){// If the attribute has a get mutator, we will call that then return what// it returns as the value, which is useful for transforming values on// retrieval from the model to a form that is more useful for usage.if ($this-hasGetMutator($key)) {return $this-mutateAttribute($key, $value);}// If the attribute exists within the cast array, we will convert it to// an appropriate native PHP type dependent upon the associated value// given with the key in the pair. Dayle made this comment line up.if ($this-hasCast($key)) {return $this-castAttribute($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.if ($value ! null \in_array($key, $this-getDates(), false)) {return $this-asDateTime($value);}return $value;}
数据更新
#Hyperf\Database\Model\Concerns\HasAttributes
public function syncAttributes(){$this-mergeAttributesFromClassCasts();return $this;}
protected function mergeAttributesFromClassCasts(){foreach ($this-classCastCache as $key $value) {if ($value instanceof Synchronized $value-isSynchronized()) {continue;}$caster $this-resolveCasterClass($key);$this-attributes array_merge($this-attributes,$caster instanceof CastsInboundAttributes? [$key $value]: $this-normalizeCastClassResponse($key, $caster-set($this, $key, $value, $this-attributes)));}}
二 数组和json转换
数据库存json数据库字段为text或json数据获取时转变为数组。
获取时使用 Hyperf\Database\Model\Model::__get()调用Hyperf\Database\Model\Concerns\HasAttributes::getAttribute()。
设置时使用Model::__set()调用HasAttributes::setAttribute()。
判断是否可为json数据则使用json_encode()转化为json数据保存。
根据源码HasAttributes::casts数组中设置字段类型为array, json, object, collection中的类型可为json字符串保存。
2.1 测试
#App\Controller\TestController
public function testmodifier() { $article Article::query()-find(2);$options $article-content;var_dump($options);if (empty($options)) {$article-content [intro test, content test1];$article-save();$options $article-content;}var_dump($options);
}测试结果
NULL
array(2) {[intro]string(4) test[content]string(5) test1
}
select content from articles where id2{intro:test,content:test1} 2.2 源码
getAttribute()源码详见1.5源码。
#Hyperf\Database\Model\Concerns\HasAttributes
public function setAttribute($key, $value) {// First we will check for the presence of a mutator for the set operation// which simply lets the developers tweak the attribute as it is set on// the model, such as json_encoding an listing of data for storage.if ($this-hasSetMutator($key)) {return $this-setMutatedAttributeValue($key, $value);}// If an attribute is listed as a date, well convert it from a DateTime// instance into a form proper for storage on the database tables using// the connection grammars date format. We will auto set the values.if ($value $this-isDateAttribute($key)) {$value $this-fromDateTime($value);}if ($this-isClassCastable($key)) {$this-setClassCastableAttribute($key, $value);return $this;}if ($this-isJsonCastable($key) !is_null($value)) {$value $this-castAttributeAsJson($key, $value);}// If this attribute contains a JSON -, well set the proper value in the// attributes underlying array. This takes care of properly nesting an// attribute in the arrays value in the case of deeply nested items.if (Str::contains($key, -)) {return $this-fillJsonAttribute($key, $value);}$this-attributes[$key] $value;return $this;}
protected function isJsonCastable($key) {return $this-hasCast($key, [array, json, object, collection]);}
public function hasCast($key, $types null) {if (array_key_exists($key, $this-getCasts())) {return $types ? in_array($this-getCastType($key), (array) $types, true) : true;}return false;}
public function getCasts() {if ($this-getIncrementing()) {return array_merge([$this-getKeyName() $this-getKeyType()], $this-casts);}return $this-casts;}
protected function castAttributeAsJson($key, $value) {$value $this-asJson($value);if ($value false) {throw JsonEncodingException::forAttribute($this,$key,json_last_error_msg());}return $value;}
三 Date类型转换
在设置的时候若不是Hyperf\Database\Model\Model::CREATED_AT,Model::UPDATED_AT即字段不为created_at或updated_at且设置参数如日期格式则不会调用转换。
因为判断是否可转换的时候被过滤掉。像官网设置created_at不会被转换可能和版本有关系。
再说获取。
直接获取对应属性即运行Hyperf\Database\Model\Model::__get()。 转换类型会被判断为custom_datetime转换为Carbon类。
但是设置的格式未被解析还是需要手动设置格式。使用Hyperf\Database\Model\Concerns\HasAttributes::getAttributes()获取直接获取HasAttributes::attributes属性。
这两种对与设置的格式都不会解析返回都是根据HasAttributes::dateFormat其默认值都是Y-m-d H:i:s。
使用HasAttributes::attributesToArray()会调用HasAttributes::addCastAttributesToArray()会判断是否为custom_datetime。
是custom_datetime类型则会调用php系统类自带函数format()通过解析参数获得格式化数据。
其实和自己使用format()运行原理一样效果也一样。
3.1 测试
#App\Controller\TestController
public function testmodifier() {$pr PushRecode::query()-find(1);$pr-push_time date(Y-m-d H:i:s);var_dump($pr-push_time);$pr $pr-syncAttributes();var_dump($pr-push_time-format(Y-m-d H:00:00));$pr-created_at date(Y-m-d H:i:s);$info $pr-syncAttributes()-getAttributes();var_dump($info);$info $pr-syncAttributes()-attributesToArray();var_dump($info);
}
测试结果
object(Carbon\Carbon)#1151 (19) {[endOfTime:protected]bool(false)[startOfTime:protected]bool(false)[constructedObjectId:protected]string(32) 00000000607fdc84000000003fa11939[localMonthsOverflow:protected]NULL[localYearsOverflow:protected]NULL[localStrictModeEnabled:protected]NULL[localHumanDiffOptions:protected]NULL[localToStringFormat:protected]NULL[localSerializer:protected]NULL[localMacros:protected]NULL[localGenericMacros:protected]NULL[localFormatFunction:protected]NULL[localTranslator:protected]NULL[dumpProperties:protected]array(3) {[0]string(4) date[1]string(13) timezone_type[2]string(8) timezone}[dumpLocale:protected]NULL[dumpDateProperties:protected]NULL[date]string(26) 2024-04-11 09:30:03.000000[timezone_type]int(3)[timezone]string(3) UTC
}
string(19) 2024-04-11 09:00:00
array(4) {[id]int(1)[is_push]int(1)[push_time]string(19) 2024-04-11 09:30:03[created_at]string(19) 2024-04-11 09:30:03
}
array(4) {[id]int(1)[is_push]int(1)[push_time]string(10) 2024-04-11[created_at]string(10) 2024-04-11
}
3.2 源码
Hyperf\Database\Model\Model::getAttribute()内容详见1.5源码。
Hyperf\Database\Model\Model::setAttribute()内容详见2.2源码。
#Hyperf\Database\Model\Concerns\HasAttributes
protected function isClassCastable($key) {return array_key_exists($key, $this-getCasts()) class_exists($class $this-parseCasterClass($this-getCasts()[$key])) !in_array($class, static::$primitiveCastTypes);}
protected function parseCasterClass($class) {return strpos($class, :) false? $class: explode(:, $class, 2)[0];}
protected static $primitiveCastTypes [array,bool,boolean,collection,custom_datetime,date,datetime,decimal,double,float,int,integer,json,object,real,string,timestamp,];
public function getCasts() {if ($this-getIncrementing()) {return array_merge([$this-getKeyName() $this-getKeyType()], $this-casts);}return $this-casts;}public function getAttributes() {return $this-attributes;}protected function isDateAttribute($key) {return in_array($key, $this-getDates(), true)|| $this-isDateCastable($key);}
protected function isDateCastable($key) {return $this-hasCast($key, [date, datetime]);}public function getAttributeValue($key) {return $this-transformModelValue($key, $this-getAttributeFromArray($key));}
protected function transformModelValue($key, $value) {// If the attribute has a get mutator, we will call that then return what// it returns as the value, which is useful for transforming values on// retrieval from the model to a form that is more useful for usage.if ($this-hasGetMutator($key)) {return $this-mutateAttribute($key, $value);}// If the attribute exists within the cast array, we will convert it to// an appropriate native PHP type dependent upon the associated value// given with the key in the pair. Dayle made this comment line up.if ($this-hasCast($key)) {return $this-castAttribute($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.if ($value ! null \in_array($key, $this-getDates(), false)) {return $this-asDateTime($value);}return $value;}
protected function castAttribute($key, $value) {$castType $this-getCastType($key);if (is_null($value) in_array($castType, static::$primitiveCastTypes)) {return $value;}switch ($castType) {case int:case integer:return (int) $value;case real:case float:case double:return $this-fromFloat($value);case decimal:return $this-asDecimal($value, explode(:, $this-getCasts()[$key], 2)[1]);case string:return (string) $value;case bool:case boolean:return (bool) $value;case object:return $this-fromJson($value, true);case array:case json:return $this-fromJson($value);case collection:return new BaseCollection($this-fromJson($value));case date:return $this-asDate($value);case datetime:case custom_datetime:return $this-asDateTime($value);case timestamp:return $this-asTimestamp($value);}if ($this-isClassCastable($key)) {return $this-getClassCastableAttributeValue($key, $value);}return $value;}
protected function getCastType($key) {if ($this-isCustomDateTimeCast($this-getCasts()[$key])) {return custom_datetime;}if ($this-isDecimalCast($this-getCasts()[$key])) {return decimal;}return trim(strtolower($this-getCasts()[$key]));}
protected function asDateTime($value) {// If this value is already a Carbon instance, we shall just return it as is.// This prevents us having to re-instantiate a Carbon instance when we know// it already is one, which wouldnt be fulfilled by the DateTime check.if ($value instanceof Carbon || $value instanceof CarbonInterface) {return Carbon::instance($value);}// If the value is already a DateTime instance, we will just skip the rest of// these checks since they will be a waste of time, and hinder performance// when checking the field. We will just return the DateTime right away.if ($value instanceof DateTimeInterface) {return Carbon::parse($value-format(Y-m-d H:i:s.u),$value-getTimezone());}// If this value is an integer, we will assume it is a UNIX timestamps value// and format a Carbon object from this timestamp. This allows flexibility// when defining your date fields as they might be UNIX timestamps here.if (is_numeric($value)) {return Carbon::createFromTimestamp($value);}// If the value is in simply year, month, day format, we will instantiate the// Carbon instances from that format. Again, this provides for simple date// fields on the database, while still supporting Carbonized conversion.if ($this-isStandardDateFormat($value)) {return Carbon::instance(Carbon::createFromFormat(Y-m-d, $value)-startOfDay());}$format $this-getDateFormat();// Finally, we will just assume this date is in the format used by default on// the database connection and use that format to create the Carbon object// that is returned back out to the developers after we convert it here.if (Carbon::hasFormat($value, $format)) {return Carbon::createFromFormat($format, $value);}return Carbon::parse($value);}
protected function isCustomDateTimeCast($cast) {return strncmp($cast, date:, 5) 0|| strncmp($cast, datetime:, 9) 0;}
根据源码判断array_key_exists($key, $this-getCasts())、class_exists($class $this-parseCasterClass($this-getCasts()[$key]))应为true!in_array($class, static::$primitiveCastTypes)为false所以isClassCastable()为false。
isDateAttribute()结果应该也为false。
之后执行getAttributeValue()获取castType为custom_datetime最终转换为Carbon\Carbon类。
#Hyperf\Database\Model\Concerns\HasAttributes
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.$attributes $this-addDateAttributesToArray($attributes $this-getArrayableAttributes());$attributes $this-addMutatedAttributesToArray($attributes,$mutatedAttributes $this-getMutatedAttributes());// Next we will handle any casts that have been setup for this model and cast// the values to their appropriate type. If the attribute has a mutator we// will not perform the cast on those attributes to avoid any confusion.$attributes $this-addCastAttributesToArray($attributes,$mutatedAttributes);// Here we will grab all of the appended, calculated attributes to this model// as these attributes are not really in the attributes array, but are run// when we need to array or JSON the model for convenience to the coder.foreach ($this-getArrayableAppends() as $key) {$attributes[$key] $this-mutateAttributeForArray($key, null);}return $attributes;}
protected function addCastAttributesToArray(array $attributes, array $mutatedAttributes) {foreach ($this-getCasts() as $key $value) {if (!array_key_exists($key, $attributes) || in_array($key, $mutatedAttributes)) {continue;}// Here we will cast the attribute. Then, if the cast is a date or datetime cast// then we will serialize the date for the array. This will convert the dates// to strings based on the date format specified for these Model models.$attributes[$key] $this-castAttribute($key,$attributes[$key]);// If the attribute cast was a date or a datetime, we will serialize the date as// a string. This allows the developers to customize how dates are serialized// into an array without affecting how they are persisted into the storage.if ($attributes[$key] ($value date || $value datetime)) {$attributes[$key] $this-serializeDate($attributes[$key]);}if ($attributes[$key] $this-isCustomDateTimeCast($value)) {$attributes[$key] $attributes[$key]-format(explode(:, $value, 2)[1]);}if ($attributes[$key] instanceof Arrayable) {$attributes[$key] $attributes[$key]-toArray();}}return $attributes;}官网打不开了……后续内容等官网好了再说吧……