From 21799401e496ec0bc1b456b8edcc0af28acb298f Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 29 May 2024 10:32:04 -0400 Subject: [PATCH 1/3] bring back modifier --- src/Modifiers/CoreModifiers.php | 35 +++++ tests/Modifiers/SelectTest.php | 270 ++++++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 tests/Modifiers/SelectTest.php diff --git a/src/Modifiers/CoreModifiers.php b/src/Modifiers/CoreModifiers.php index 1fd5e8af4e8..d68d2d42ecc 100644 --- a/src/Modifiers/CoreModifiers.php +++ b/src/Modifiers/CoreModifiers.php @@ -1816,6 +1816,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 00000000000..2a8b5cd58f4 --- /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(); + } +} From 9a4787f3821ef788aec31f3a4b4c1fc07d8d7564 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 29 May 2024 14:43:06 -0400 Subject: [PATCH 2/3] add test --- tests/Tags/StructureTagTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Tags/StructureTagTest.php b/tests/Tags/StructureTagTest.php index b37c39071d3..45ec7a8952c 100644 --- a/tests/Tags/StructureTagTest.php +++ b/tests/Tags/StructureTagTest.php @@ -80,6 +80,19 @@ public function it_renders_a_nav() ])); } + /** @test */ + public function it_renders_a_nav_with_selected_fields() + { + // At the moment we are only concerned with the tag not erroring. + // Todo: write a test that _actually_ tests for the select="" param working as expected. + + $this->createCollectionAndNav(); + + $template = '{{ nav:test select="title" }}{{ *recursive children* }}{{ /nav:test }}'; + + $this->assertNotNull(Antlers::parse($template)); + } + /** @test */ public function it_renders_a_nav_with_scope() { From 33ac17511e43063287dffe102bce3794ac1e287a Mon Sep 17 00:00:00 2001 From: John Koster Date: Thu, 30 May 2024 19:12:36 -0500 Subject: [PATCH 3/3] Removes over-aggressive modifier check TODO comment removed to address in separate PR --- src/View/Antlers/Language/Runtime/NodeProcessor.php | 2 +- tests/Tags/StructureTagTest.php | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/View/Antlers/Language/Runtime/NodeProcessor.php b/src/View/Antlers/Language/Runtime/NodeProcessor.php index 733e60dfee5..c4e420bc996 100644 --- a/src/View/Antlers/Language/Runtime/NodeProcessor.php +++ b/src/View/Antlers/Language/Runtime/NodeProcessor.php @@ -1399,7 +1399,7 @@ public function reduce($processNodes) if (! empty($recursiveParent->parameters)) { $lockData = $this->data; foreach ($recursiveParent->parameters as $param) { - if (ModifierManager::isModifier($param)) { + if ($param->name === 'scope') { $childDataToUse = $this->runModifier($param->name, $parentParameterValues, $childDataToUse, $rootData); } } diff --git a/tests/Tags/StructureTagTest.php b/tests/Tags/StructureTagTest.php index 45ec7a8952c..6293b68558d 100644 --- a/tests/Tags/StructureTagTest.php +++ b/tests/Tags/StructureTagTest.php @@ -83,9 +83,6 @@ public function it_renders_a_nav() /** @test */ public function it_renders_a_nav_with_selected_fields() { - // At the moment we are only concerned with the tag not erroring. - // Todo: write a test that _actually_ tests for the select="" param working as expected. - $this->createCollectionAndNav(); $template = '{{ nav:test select="title" }}{{ *recursive children* }}{{ /nav:test }}';