Skip to content

Commit

Permalink
[5.x] Add select modifier (#10183)
Browse files Browse the repository at this point in the history
  • Loading branch information
godismyjudge95 authored May 23, 2024
1 parent f18fdf7 commit a621e1f
Show file tree
Hide file tree
Showing 2 changed files with 305 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/Modifiers/CoreModifiers.php
Original file line number Diff line number Diff line change
Expand Up @@ -1801,6 +1801,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.
*
Expand Down
270 changes: 270 additions & 0 deletions tests/Modifiers/SelectTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
<?php

namespace Tests\Modifiers;

use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Mockery;
use Statamic\Contracts\Query\Builder;
use Statamic\Entries\EntryCollection;
use Statamic\Modifiers\Modify;
use Tests\TestCase;

class SelectTest extends TestCase
{
/** @test */
public function it_selects_certain_values_from_array_of_items()
{
$items = $this->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();
}
}

0 comments on commit a621e1f

Please sign in to comment.