deefour / transformer
将原始输入数据转换为一致、不可变的PHP对象
Requires
- php: >=5.5.0
Requires (Dev)
- friendsofphp/php-cs-fixer: 2.1.0
- phpspec/phpspec: ^3.1
README
将原始输入数据转换为一致、不可变的传输对象。
入门指南
运行以下命令将 Transfromer 添加到项目的 composer.json
。有关特定版本,请参阅 Packagist。
composer require deefour/transformer
需要 >=PHP5.5.0
。
概览
- 所有转换器都扩展了抽象类
Deefour\Transformer\Transformer
。 - 转换器在实例化时接受一个包含数据的数组。
- 输入源上的属性可以被转换为特定类型。
- 可以为每个属性创建一个获取器来定义其原始值的转换。
- 可以创建方法来提供额外的自定义属性。
- 转换器上的输入源是不可变的。
- 可以通过查询转换器来检索从源数据或整个数据集中转换后的单个属性的版本。
示例
假设以下输入数据是通过 POST
请求提交的,以创建一个新的 Book
。
$input = [ 'title' => 'a whole new world', 'price' => '29.95', 'publication_date' => '2010-12-09', 'author' => 'Jason Daly', ];
假设我们想要确保书籍的标题已经正确地进行了标题化,价格是一个浮点值,出版日期是一个 Carbon\Carbon
日期时间对象。可以使用转换器将这些原始 $input
的属性格式化为特定、一致的形式。
use Deefour\Transformer\Transformer; use Carbon\Carbon; class BookTransformer extends Transformer { protected $casts [ 'price' => 'float', ]; public function title() { return trim(ucwords($this->raw('title'))); } public function publicationDate() { return Carbon::parse($this->raw('publication_date')); } }
方法是可选的,每个方法都具有公共可见性,并且名称与属性名称的驼峰式版本相匹配。当从转换器请求这些属性时,将调用这些方法。
$transform = new BookTransformer($input); $transform->get('title'); //=> 'A Whole New World' $transform->get('price'); //=> 29.95 (cast to a float) $transform->get('publication_date'); //=> Carbon\Carbon instance
类型转换
可以在转换器中添加受保护的 $casts
属性,它由属性名称作为键,转换器应将其转换为标量类型的值作为值组成。当从转换器返回属性时,将检查此映射,将它们转换为所需类型。
class BookTransformer extends Transformer { protected $casts [ 'price' => 'float', ]; } $attributes = [ 'price' => '3.23' ]; $transformer = new BookTransformer($attributes); $transformer->price; //=> 3.23 (cast to a float)
注意:类型 'object' 和 'array' 的转换将使用
json_encode
转换为 JSON。
隐藏原始输入
可以在转换器中添加受保护的 $hidden
属性,列出将省略从批量请求信息(如 toArray()
、all()
和 jsonSerialize()
)中的属性。
class CarTransformer extends Transformer { protected $hidden = [ 'cylinders' ]; } $attributes = [ 'make' => 'Subaru', 'model' => 'WRX', 'cylinders' => 4 ]; $transformer = new Transformer($attributes); $transformer->cylinders; //=> 4 $transformer->has('cylinders'); //=> true $transformer->all(); //=> [ 'make' => 'Subaru', 'model' => 'WRX' ] $transform->except('make'); // [ 'model' => 'WRX' ]
回退(默认值)
可以在转换器中添加受保护的 $fallbacks
属性,它由属性名称作为键,默认值作为值组成。当从转换器请求属性但无法在源数据中找到或在值是 NULL
时,将检查此映射。
接受 NULL
值
如果源上的属性具有 NULL
值,并且通常在 $fallbacks
映射中接受默认值,可以通过以下方式为所有转换器的请求生命周期启用此功能:
Deefour\Transformer\Transformer::preferNullValues();
为了说明差异
class BookTransformer extends Transformer { protected $fallbacks [ 'category' => 'Miscellaneous', ]; } $attributes = [ 'category' => null ]; $transformer = new BookTransformer($attributes); $transformer->category; //=> Miscellaneous Deefour\Transformer\Transformer::preferNullValues(); $transformer->category; //=> null
方法属性
在其文档块中标记为 @attribute
的公共方法被视为转换器的 $attributes
源上的属性。
class BookTransformer extends Transformer { /** * Is the book considered old? * * @attribute * @return string */ public function isOld() { return $this->publication_date < Carbon::now()->subYears(10); } /** * Is the book nonfiction? * * @return boolean */ public function internalSlug() { return sha1($this->title . (string)$this->publication_date); } }
isOld
方法在 docblock 中被标记为 @attribute
注释,导致转换器表现得好像源数据上存在一个 is_old
属性。可以直接调用 internalSlug()
,但它不会被当作一个 internal_slug
属性来处理,因为它没有被正确地标记为 docblock 注释。
$transform = new BookTransformer([ 'title' => 'A Whole New World' ]); $transform->get('title'); //=> 'A Whole New World' $transform->get('is_old') //=> false $transformer->get('internal_slug') //=> null $transform->all(); //=> [ 'title' => 'A Whole New World', 'is_old' => false ]
访问数据
可以使用 get()
获取单个转换后的属性。
$transform->get('title');
一个魔法 __get()
实现提供了对转换后属性的属性访问。
$transform->title;
一个魔法 __call()
实现提供了方法访问。
$transformer->title();
可以通过 __isset()
或 API 检查属性是否存在。
isset($transform->title); $transform->exists('title'); $transform->has('title'); $transform->contains('title');
转换器也实现了 ArrayAccess
(尝试设置或取消设置将抛出异常)。
$transform['title'];
可以一次性检索所有转换后的属性。
$transform->all();
并且可以一次性检索一组特定的键。
$transform->only('title', 'price', 'internal_slug'); //=> [ 'title' => 'A Whole New World', 'price' => 29.95, 'internal_slug' => null ]
$transform->intersect('title', 'price', 'internal_slug'); //=> [ 'title' => 'A Whole New World', 'price' => 29.95 ]
$transform->except('secret_key'); //=> everything except the 'secret_key' attribute. $transform->omit('secret_key');
还实现了 JsonSerializable
接口。
json_encode($transform); //=> "{'title':'A Whole New World', 'price':29.95, 'publication_date':'2010-12-09 00:00:00', 'author':'Jason Daly'}"
可以检索单个原始属性或整个原始源数据。
$transform->raw('title'); //=> 'a whole new world' $transform->raw(); //=> [ 'title' => 'a whole new world', 'price' => '29.95', 'publication_date' => '2010-12-09', 'author' => 'Jason Daly' ]
get()
可以提供一个默认值作为第二个参数。如果默认值是可调用的,它将在返回之前被评估。
$transformer->get('invalid-attribute', 'Not Available'); //=> 'Not Available' $transformer->get('invalid-attribte', function() { return 'Oops!'; }); //=> 'Oops!'
可变转换器
在基本转换器中,__set()
、offsetSet
和 offsetUnset
都是空方法。这种行为(缺乏行为)保持了底层源数据的不变性。
存在一个 MutableTransformer
类实现了这些方法,允许向转换器实例添加额外的属性或修改现有属性。
也可以使用 __call()
方法来设置/修改转换器上的属性。
$transformer = new MutableTransformer([ 'foo' => '1234' ]); $transformer->foo('abcd'); $transformer->get('foo'); //=> 'abcd'
实例化和数据访问方式与基本转换器相同。
跟踪更改
在可变转换器上修改属性时,会保留其原始值。可以查询转换器以确定属性在构造后是否已被修改,或检索更改列表。
$transformer = new MutableTransformer([ 'foo' => 'AAA', 'bar' => 'BBB' ]); $transformer->isDirty(); //=> false $transformer->foo = 'new value'; $transformer->isDirty(); //=> true $transformer->dirty(); //=> [ 'foo' ] $transformer->get('foo'); //=> 'new value' $transformer->original('foo'); //=> 'AAA' $transformer->changes(); //=> [ 'foo' => 'new value' ]
贡献
变更日志
1.7.0 - 2017年3月2日
- 添加了对批量访问器隐藏属性的支持。
1.6.0 - 2017年2月14日
jsonSerialize()
现在将调用实现了JsonSerializable
的属性的jsonSerialize()
,允许转换器递归地编码为 JSON。
1.5.0 - 2016年10月20日
- 将库中的
default()
重命名为fallback()
,以兼容所有 PHP 版本。
1.4.0 - 2016年10月20日
- 支持在类的新的
$fallbacks
属性上设置默认属性。当请求的属性不存在或为NULL
时,将检查此组默认值。感谢 @dgallinari #2
1.3.0 - 2016年10月16日
@attribute
注释只需设置在您希望被视为属性的方法上,这些属性不是原始输入源上属性驼峰式的版本。- 已添加
omit()
和without()
作为except()
的别名。 - 已添加
has()
和contains()
作为exists()
的别名。
1.0.1 - 2015年10月29日
- 添加了
except()
方法。
1.0.0 - 2015年10月7日
- 发布 1.0.0。
0.4.0 - 2015年9月7日
- 支持添加了“属性方法” - 这是指其蛇形名称在
$attributes
源中不存在的方法,但它们仍然被视为在$attributes
源中存在的任何其他属性。 - 不应被视为“属性方法”的
protected
方法现在应在它们的docblock中标记为@internal
。
0.3.0 - 2015年9月4日
- 新的变更跟踪,灵感来源于yammer/model_attribute
0.2.6 - 2015年6月5日
- 现在遵循PSR-2。
0.2.5 - 2015年6月3日
- 新增了
__call()
功能,提供对属性的魔法方法访问。 get()
现在处理默认值,包括闭包。
0.2.4 - 2015年6月2日
- 修复了与嵌套属性相关的
only()
方法中的错误。
0.2.2 - 2015年5月30日
- 如果没有指定任何
$attribute
,则raw()
将返回完整、未转换的源。 - 现在可以不带任何参数传递给构造函数来实例化
MutableTransformer
。
0.2.1 - 2015年5月25日
- 改进了代码格式。
0.2.0 - 2015年5月5日
- 将基本转换器更改为常规类(它曾经是抽象的)。
- 添加了新的
MutableTransformer
。
0.1.0 - 2015年4月22日
- 初始版本。
许可证
版权所有 (c) 2016 Jason Daly (deefour)。在MIT许可证下发布。