diff --git a/src/Modifiers/CoreModifiers.php b/src/Modifiers/CoreModifiers.php index 36f9ff6bf0..6de21c971c 100644 --- a/src/Modifiers/CoreModifiers.php +++ b/src/Modifiers/CoreModifiers.php @@ -1754,6 +1754,41 @@ public function pluck($value, $params) return $wasArray ? $items->all() : $items; } + /** + * Selects certain values from each item in a collection. + * + * @param array|Collection $value + * @param array $params + * @return array|Collection + */ + public function select($value, $params) + { + $keys = Arr::wrap($params); + + if ($wasArray = is_array($value)) { + $value = collect($value); + } + + if (Compare::isQueryBuilder($value)) { + $value = $value->get(); + } + + $items = $value->map(function ($item) use ($keys) { + return collect($keys)->mapWithKeys(function ($key) use ($item) { + $value = null; + if (is_array($item) || $item instanceof ArrayAccess) { + $value = Arr::get($item, $key); + } else { + $value = method_exists($item, 'value') ? $item->value($key) : $item->get($key); + } + + return [$key => $value]; + })->all(); + }); + + return $wasArray ? $items->all() : $items; + } + /** * Get the plural form of an English word with access to $context. * diff --git a/tests/Modifiers/SelectTest.php b/tests/Modifiers/SelectTest.php new file mode 100644 index 0000000000..2a8b5cd58f --- /dev/null +++ b/tests/Modifiers/SelectTest.php @@ -0,0 +1,270 @@ +items(); + + $modified = $this->modify($items, ['title', 'type']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ], + $modified, + ); + + $modified = $this->modify($items, ['title', 'stock']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ], + $modified, + ); + } + + /** @test */ + public function it_selects_certain_values_from_collections_of_items() + { + $items = Collection::make($this->items()); + + $modified = $this->modify($items, ['title', 'type']); + $this->assertInstanceOf(Collection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ], + $modified->all(), + ); + + $modified = $this->modify($items, ['title', 'stock']); + $this->assertInstanceOf(Collection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ], + $modified->all(), + ); + } + + /** @test */ + public function it_selects_certain_values_from_query_builder() + { + $builder = Mockery::mock(Builder::class); + $builder->shouldReceive('get')->andReturn(Collection::make($this->items())); + + $modified = $this->modify($builder, ['title', 'type']); + $this->assertInstanceOf(Collection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ], + $modified->all(), + ); + + $modified = $this->modify($builder, ['title', 'stock']); + $this->assertInstanceOf(Collection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ], + $modified->all(), + ); + } + + /** @test */ + public function it_selects_certain_values_from_array_of_items_with_origins() + { + $items = $this->itemsWithOrigins(); + + $modified = $this->modify($items, ['title', 'type']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Pan', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ['title' => 'Cafe', 'type' => 'drink'], + ], + $modified, + ); + + $modified = $this->modify($items, ['title', 'stock']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Pan', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ['title' => 'Cafe', 'stock' => 2], + ], + $modified, + ); + } + + /** @test */ + public function it_selects_certain_values_from_collections_of_items_with_origins() + { + $items = EntryCollection::make($this->itemsWithOrigins()); + + $modified = $this->modify($items, ['title', 'type']); + $this->assertInstanceOf(EntryCollection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Pan', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ['title' => 'Cafe', 'type' => 'drink'], + ], + $modified->all(), + ); + + $modified = $this->modify($items, ['title', 'stock']); + $this->assertInstanceOf(EntryCollection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Pan', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ['title' => 'Cafe', 'stock' => 2], + ], + $modified->all(), + ); + } + + /** @test */ + public function it_selects_certain_values_from_array_of_items_of_type_array() + { + $items = $this->itemsOfTypeArray(); + + $modified = $this->modify($items, ['title', 'type']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ], + $modified, + ); + + $modified = $this->modify($items, ['title', 'stock']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ], + $modified, + ); + } + + /** @test */ + public function it_selects_certain_values_from_collections_of_items_of_type_array() + { + $items = EntryCollection::make($this->itemsOfTypeArray()); + + $modified = $this->modify($items, ['title', 'type']); + $this->assertInstanceOf(EntryCollection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ], + $modified->all(), + ); + + $modified = $this->modify($items, ['title', 'stock']); + $this->assertInstanceOf(EntryCollection::class, $modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ], + $modified->all(), + ); + } + + /** @test */ + public function it_selects_certain_values_from_array_of_items_of_type_arrayaccess() + { + $items = $this->itemsOfTypeArrayAccess(); + + $modified = $this->modify($items, ['title', 'type']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'type' => 'food'], + ['title' => 'Coffee', 'type' => 'drink'], + ], + $modified, + ); + + $modified = $this->modify($items, ['title', 'stock']); + $this->assertIsArray($modified); + $this->assertEquals( + [ + ['title' => 'Bread', 'stock' => 1], + ['title' => 'Coffee', 'stock' => 2], + ], + $modified, + ); + } + + private function items() + { + return [ + new Item(['title' => 'Bread', 'type' => 'food', 'stock' => 1]), + new Item(['title' => 'Coffee', 'type' => 'drink', 'stock' => 2]), + ]; + } + + private function itemsWithOrigins() + { + return [ + $breadEn = new ItemWithOrigin(['title' => 'Bread', 'type' => 'food', 'stock' => 1]), + $breadEs = new ItemWithOrigin(['title' => 'Pan'], $breadEn), + $coffeeEn = new ItemWithOrigin(['title' => 'Coffee', 'type' => 'drink', 'stock' => 2]), + $coffeeEs = new ItemWithOrigin(['title' => 'Cafe'], $coffeeEn), + ]; + } + + private function itemsOfTypeArray() + { + return [ + ['title' => 'Bread', 'type' => 'food', 'stock' => 1], + ['title' => 'Coffee', 'type' => 'drink', 'stock' => 2], + ]; + } + + private function itemsOfTypeArrayAccess() + { + return [ + new ArrayAccessType(['title' => 'Bread', 'type' => 'food', 'stock' => 1]), + new ArrayAccessType(['title' => 'Coffee', 'type' => 'drink', 'stock' => 2]), + ]; + } + + private function modify($value, ...$keys) + { + return Modify::value($value)->select(Arr::flatten($keys))->fetch(); + } +}