2016-07-16 44 views
15

我一直在檢討Laravel類別的文檔和API,但似乎並沒有找到我在尋找:從Laravel收集獲取,只有特定的屬性

我想檢索與模型的數組來自集合的數據,但只獲取指定的屬性。

I.e.類似Users::toArray('id','name','email'),其中集合實際上包含用戶的所有屬性,因爲它們在其他地方使用,但在此特定位置我需要一個包含userdata的數組,並且只包含指定的屬性。

Laravel似乎沒有這方面的幫手嗎? - 我怎樣才能做到這一點最簡單的方法?

回答

40

您可以使用現有的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每個項目在回調通過。從每個回調調用返回的值將生成由map()方法生成的新的Collection

collect($user->toArray())只是在Users屬性中構建了一個新的臨時Collection

->only(['id', 'name', 'email'])將臨時Collection減少到僅指定的那些屬性。

->all()將暫時的Collection變成一個普通數組。

把它放在一起,你會得到「對於用戶集合中的每個用戶,返回一個只包含id,name和email屬性的數組。

+0

謝謝!我已經將此標記爲公認的答案,因爲它具有現有Laravel功能的魅力。 - 現在,可以通過自定義集合類將其提供給集合,就像我在替代解決方案中描述的那樣。 – preyz

1
  1. 您需要定義$hidden$visible屬性。他們將被設置爲全局(這意味着總是返回來自$visible數組的所有屬性)。

  2. 使用方法makeVisible($attribute)makeHidden($attribute)您可以動態更改隱藏和可見屬性。更多:Eloquent: Serialization -> Temporarily Modifying Property Visibility

+0

我不希望這是全球性的,但選擇要動態從集合中提取的屬性。 – preyz

5

使用User::get(['id', 'name', 'email']),它會回報你一個集合與指定的列,如果你想成爲一個數組,只需使用toArray()get()方法,像這樣經過:

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

大多數情況下,您不需要將集合轉換爲數組,因爲集合實際上是類固醇上的數組,並且您有易於使用的方法來操作集合。

+0

該集合已由先前的查詢創建,其中需要更多屬性。因此我需要生成一個只有特定屬性的數據數組。 – preyz

+0

你可以讓你的查詢動態地傳遞一列數組來返回,或者你可以做另一個' - > get(['id','email','name'])'',它不會重新查詢數據庫,但它將僅返回一個僅包含選定值的新集合。諸如pluck/lists,get,first等方法在查詢構建器類和集合類中都具有相同的名稱。 – Ruffles

+0

荷葉邊,在Laravel 5.3中不起作用。 - 查詢生成器「get」方法事實上確實需要列,但它也執行另一個查詢。該集合的「get」方法可以通過集合中的鍵提取特定的模型,這不是我在這之後所做的。 – preyz

2

我現在已經想出了一個自己的解決這一:

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模型,但使用了不同的集合類。你所有的模型都需要擴展這個自定義模型,而不是擴展模型。

<?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 App\Models; 
class Article extends Model 
{ 
... 

現在的功能沒有:

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

最後,所有車型應該再擴展您的自定義模型,而不是像這樣。上面的1被整齊地用於收集以使$collection->extract()方法可用。

+0

查看有關擴展集合的Laravel文檔:https://laravel.com/docs/5.5/collections#extending-collections –

0

這似乎工作,但不知道它是否優化的性能與否。

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

輸出:

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

我假設你有設置你的數據庫連接,並建立查詢中的一切控制器秩序。

你可以做這個... :)

$user_details = User::get(['id','username','email']); 

dd($user_details); 
0

我有,我需要從一個大陣選擇值的類似的問題,但我想結果集合只包含一個單一的值值。

pluck()可以用於此目的(如果只有1次關鍵項目是必需的)

你也可以使用reduce()。類似這樣的減少:

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