IT TIP

Laravel 컬렉션에서 특정 속성 만 가져옵니다.

itqueen 2021. 1. 10. 19:46
반응형

Laravel 컬렉션에서 특정 속성 만 가져옵니다.


Laravel Collections에 대한 문서와 API를 검토했지만 원하는 것을 찾지 못하는 것 같습니다.

컬렉션에서 모델 데이터가있는 배열을 검색하고 싶지만 지정된 속성 만 가져옵니다.

Users::toArray('id','name','email'), 컬렉션은 다른 곳에서 사용되기 때문에 실제로 사용자에 대한 모든 속성을 보유하지만이 특정 장소에서는 사용자 데이터와 지정된 속성 만있는 배열이 필요합니다.

라 라벨에 이것에 대한 도우미가없는 것 같습니까? -가장 쉬운 방법은 무엇입니까?


기존 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전달 된 콜백에 전달합니다. 콜백의 각 호출에서 반환 된 값 Collectionmap()메서드에 의해 생성 된 새 항목을 빌드합니다 .

collect($user->toArray())속성 에서 새롭고 임시로 구축하는 Collection것입니다 Users.

->only(['id', 'name', 'email'])Collection지정된 속성 만 임시 입니다.

->all()임시 Collection배열을 일반 배열로 되돌립니다.

모두 합치면 "사용자 컬렉션의 각 사용자에 대해 ID, 이름 및 이메일 속성의 배열 만 반환합니다."가 표시됩니다.


Laravel 5.5 업데이트

Laravel 5.5는 only기본적으로와 동일한 작업을 수행 하는 메서드를 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']);
});

이것을 라 라벨 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']);

use User::get(['id', 'name', 'email']), 지정된 열이있는 컬렉션을 반환하고 배열로 만들려면 toArray()다음 get()과 같은 메서드 다음에 사용 하십시오 .

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

대부분의 경우 컬렉션은 실제로 스테로이드의 배열이고 컬렉션을 조작하는 데 사용하기 쉬운 메서드가 있기 때문에 컬렉션을 배열로 변환 할 필요가 없습니다.


나는 이제 이것에 대한 자체 해결책을 생각해 냈습니다.

1. 배열에서 특정 속성을 추출하는 일반 함수 생성

아래 함수는 연관 배열 또는 연관 배열의 배열에서 특정 속성 만 추출합니다 (마지막은 Laravel에서 $ collection-> toArray ()를 수행 할 때 얻는 것입니다).

It can be used like this:

$data = array_extract( $collection->toArray(), ['id','url'] );

I am using the following functions:

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;   
}

This solution does not focus on performance implications on looping through the collections in large datasets.

2. Implement the above via a custom collection i Laravel

Since I would like to be able to simply do $collection->extract('id','url'); on any collection object, I have implemented a custom collection class.

First I created a general Model, which extends the Eloquent model, but uses a different collection class. All you models need to extend this custom model, and not the Eloquent Model then.

<?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 );
    }    
}
?>

Secondly I created the following custom collection class:

<?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 );
    }
}   
?>

Lastly, all models should then extend your custom model instead, like such:

<?php
namespace App\Models;
class Article extends Model
{
...

Now the functions from no. 1 above are neatly used by the collection to make the $collection->extract() method available.


  1. You need to define $hidden and $visible attributes. They'll be set global (that means always return all attributes from $visible array).

  2. Using method makeVisible($attribute) and makeHidden($attribute) you can dynamically change hidden and visible attributes. More: Eloquent: Serialization -> Temporarily Modifying Property Visibility


I had a similar issue where I needed to select values from a large array, but I wanted the resulting collection to only contain values of a single value.

pluck() could be used for this purpose (if only 1 key item is required)

you could also use reduce(). Something like this with reduce:

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

this is a follow up on the patricus [answer][1] above but for nested arrays:

$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();

this seems to work, but not sure if it's optimized for performance or not.

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

output:

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

$users = Users::get();

$subset = $users->map(function ($user) {
    return array_only(user, ['id', 'name', 'email']);
});

ReferenceURL : https://stackoverflow.com/questions/38412091/get-only-specific-attributes-with-from-laravel-collection

반응형