我一直在查看Laravel Collections的文档和API,但似乎找不到我想要的东西:
我想从集合中检索带有模型数据的数组,但只能获取指定的属性。
也就是说,类似Users::toArray('id','name','email')
,其中集合实际上为用户保留了所有属性,因为它们在其他地方使用,但是在这个特定的地方,我需要一个包含userdata的数组,并且只包含指定的属性。
Laravel中似乎没有这个的帮助者?-如何最简单地做到这一点?
Answers:
您可以结合使用现有Collection
方法来执行此操作。一开始可能很难理解,但是应该很容易分解。
// get your main collection with all the attributes...
$users = Users::get();
// build your second collection with a subset of attributes. this new
// collection will be a collection of plain arrays, not Users models.
$subset = $users->map(function ($user) {
return collect($user->toArray())
->only(['id', 'name', 'email'])
->all();
});
说明
首先,该map()
方法基本上只是遍历Collection
,然后将中的每个项目Collection
传递给传入的回调。从回调的每次调用返回的值将构建Collection
该map()
方法生成的新值。
collect($user->toArray())
只是Collection
在Users
属性之外建立一个新的临时属性。
->only(['id', 'name', 'email'])
将临时Collection
属性减少为仅指定的那些属性。
->all()
将临时文件Collection
转回普通数组。
将所有内容放在一起,您将获得“对于用户集合中的每个用户,仅返回ID,名称和电子邮件属性的数组。”
Laravel 5.5only
在Model上添加了一个方法,该方法与基本上具有相同的作用collect($user->toArray())->only([...])->all()
,因此可以在5.5+中将其稍微简化为:
// get your main collection with all the attributes...
$users = Users::get();
// build your second collection with a subset of attributes. this new
// collection will be a collection of plain arrays, not Users models.
$subset = $users->map(function ($user) {
return $user->only(['id', 'name', 'email']);
});
如果将此与Laravel 5.4中引入的集合的“高级消息传递”结合使用,则可以进一步简化该过程:
// get your main collection with all the attributes...
$users = Users::get();
// build your second collection with a subset of attributes. this new
// collection will be a collection of plain arrays, not Users models.
$subset = $users->map->only(['id', 'name', 'email']);
::get([ 'fields', 'array' ])
行为。基本上,这对于“转储”会很方便。
$newArray = Arr::only($initialArray, [ 'id', 'name' /* allowed keys list */ ]);
$users->map->only(['column', ...])
use User::get(['id', 'name', 'email'])
,它将返回具有指定列的集合,如果要使其成为数组,只需toArray()
在如下get()
方法之后使用:
User::get(['id', 'name', 'email'])->toArray()
在大多数情况下,您不需要将集合转换为数组,因为集合实际上是类固醇上的数组,并且您具有易于使用的方法来操纵集合。
->get(['id', 'email', 'name'])
不会重新查询数据库的查询,但是它将返回仅包含选定值的新集合。查询构建器类和集合类中的方法如pluck / lists,get,first等都具有相同的名称。
我现在提出了自己的解决方案:
1.创建一个通用函数以从数组中提取特定属性
下面的函数仅从关联数组或关联数组数组中提取特定属性(最后一个是在Laravel中执行$ collection-> toArray()时获得的结果)。
可以这样使用:
$data = array_extract( $collection->toArray(), ['id','url'] );
我正在使用以下功能:
function array_is_assoc( $array )
{
return is_array( $array ) && array_diff_key( $array, array_keys(array_keys($array)) );
}
function array_extract( $array, $attributes )
{
$data = [];
if ( array_is_assoc( $array ) )
{
foreach ( $attributes as $attribute )
{
$data[ $attribute ] = $array[ $attribute ];
}
}
else
{
foreach ( $array as $key => $values )
{
$data[ $key ] = [];
foreach ( $attributes as $attribute )
{
$data[ $key ][ $attribute ] = $values[ $attribute ];
}
}
}
return $data;
}
该解决方案不关注循环遍历大型数据集中的集合的性能。
2.通过自定义集合Laravel实现以上内容
由于我希望能够简单地$collection->extract('id','url');
对任何集合对象执行操作,因此我实现了一个自定义集合类。
首先,我创建了一个通用模型,该模型扩展了Eloquent模型,但是使用了一个不同的集合类。您所有的模型都需要扩展此自定义模型,而不是Eloquent模型。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model as EloquentModel;
use Lib\Collection;
class Model extends EloquentModel
{
public function newCollection(array $models = [])
{
return new Collection( $models );
}
}
?>
其次,我创建了以下自定义集合类:
<?php
namespace Lib;
use Illuminate\Support\Collection as EloquentCollection;
class Collection extends EloquentCollection
{
public function extract()
{
$attributes = func_get_args();
return array_extract( $this->toArray(), $attributes );
}
}
?>
最后,所有模型都应该扩展自定义模型,例如:
<?php
namespace App\Models;
class Article extends Model
{
...
现在的功能从无到有。集合巧妙地使用上述1来使该$collection->extract()
方法可用。
您需要定义$hidden
和$visible
属性。它们将设置为全局(这意味着始终从$visible
数组返回所有属性)。
使用方法makeVisible($attribute)
,makeHidden($attribute)
您可以动态更改隐藏和可见属性。更多:雄辩的:序列化->临时修改属性可见性
这是上述父级[answer] [1]的后续版本,但对于嵌套数组:
$topLevelFields = ['id','status'];
$userFields = ['first_name','last_name','email','phone_number','op_city_id'];
return $onlineShoppers->map(function ($user) {
return collect($user)->only($topLevelFields)
->merge(collect($user['user'])->only($userFields))->all();
})->all();
DB::table('roles')->pluck('title', 'name');
参考资料:https : //laravel.com/docs/5.8/queries#retrieving-results(搜索摘录)
Collection::implode()
。它可以采用属性并将其从集合中的所有对象中提取。这并不能完全回答这个问题,但对像我一样从Google来到这里的其他人可能有用。laravel.com/docs/5.7/collections#method-implode