仅从Laravel Collection获取特定属性

时间:2016-07-16 14:18:15

标签: php laravel

我一直在审阅Laravel Collections的文档和API,但似乎找不到我想要的内容:

我想从集合中检索包含模型数据的数组,但只获取指定的属性。

即。像Users::toArray('id','name','email')之类的东西,其中集合实际上包含用户的所有属性,因为它们在别处使用,但在这个特定的地方我需要一个带有userdata的数组,只有指定的属性。

在Laravel中似乎没有帮助吗? - 我怎样才能以最简单的方式做到这一点?

11 个答案:

答案 0 :(得分:92)

您可以使用现有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变回普通数组。

将所有内容放在一起,您就可以获得&#34;对于users集合中的每个用户,返回一个仅包含id,name和email属性的数组。&#34;

Laravel 5.5更新

Laravel 5.5在模型上添加了一个only方法,基本上和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中引入的"higher order messaging" for collections结合使用,可以进一步简化:

// 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']);

答案 1 :(得分:11)

使用User::get(['id', 'name', 'email']),它会返回一个包含指定列的集合,如果你想让它成为一个数组,只需在toArray()方法之后使用get(),如下所示:

User::get(['id', 'name', 'email'])->toArray()

大多数情况下,您不需要将集合转换为数组,因为集合实际上是类固体上的数组,并且您可以使用易于使用的方法来操作集合。

答案 2 :(得分:3)

下面的方法也可以。

$users = User::all()->map(function ($user) {
  return collect($user)->only(['id', 'name', 'email']);
});

答案 3 :(得分:1)

我现在想出了一个自己的解决方案:

<强> 1。创建了一个通用函数来从数组中提取特定属性

下面的函数只从关联数组或关联数组数组中提取特定属性(最后一个是在Laravel中执行$ collection-&gt; 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。通过自定义集合i Laravel

实现上述功能

由于我希望能够对任何集合对象执行$collection->extract('id','url');,因此我实现了自定义集合类。

首先,我创建了一个通用模型,它扩展了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()方法可用。

答案 4 :(得分:0)

  1. 您需要定义$hidden$visible属性。它们将被设置为全局(这意味着始终返回$visible数组中的所有属性)。

  2. 使用方法makeVisible($attribute)makeHidden($attribute),您可以动态更改隐藏和可见属性。更多:Eloquent: Serialization -> Temporarily Modifying Property Visibility

答案 5 :(得分:0)

我有一个类似的问题,我需要从大数组中选择值,但我希望结果集合只包含单个值的值。

pluck()可用于此目的(如果只需要1个关键项)

你也可以使用reduce()。像reduce这样的东西:

$result = $items->reduce(function($carry, $item) {
    return $carry->push($item->getCode());
}, collect());

答案 6 :(得分:0)

这是对上面的父本[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();

答案 7 :(得分:0)

上下文

例如,假设您想显示一个用于在系统中创建新用户的表单,其中用户具有一个角色并且该角色可用于多个用户。

用户模型看起来像这样

class User extends Authenticatable
{   
    /**
     * User attributes.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password', 'role_id'
    ];


    /**
     * Role of the user
     *
     * @return \App\Role
     */
    public function role()
    {
        return $this->belongsTo(Role::class);
    }
...

和角色模型

class Role extends Model
{
    /**
     * Role attributes.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'description'
    ];
    
    /**
     * Users of the role
     *
     * @return void
     */
    public function users()
    {
        return $this->hasMany(User::class);
    }
}

如何只获取特定的属性?

在我们要创建的特定表单中,您需要来自 Role 的数据,但实际上并不需要描述。

/**
 * Create user
 *
 * @param  \App\Role  $model
 * @return \Illuminate\View\View
 */
public function create(Role $role)
{
    return view('users.create', ['roles' => $role->get(['id', 'name'])]);
}

请注意,我们使用 $role->get(['id', 'name']) 来指定我们不需要描述。

答案 8 :(得分:-1)

这似乎有效,但不确定它是否针对性能进行了优化。

$request->user()->get(['id'])->groupBy('id')->keys()->all();

输出:

array:2 [
  0 => 4
  1 => 1
]

答案 9 :(得分:-1)

mutable_gpu_options()

答案 10 :(得分:-1)

DB::table('roles')->pluck('title', 'name');

参考文献:https://laravel.com/docs/5.8/queries#retrieving-results(寻找摘心)