Skip to content

Commit

Permalink
[5.x] Dictionary tag (#10885)
Browse files Browse the repository at this point in the history
Co-authored-by: Jason Varga <jason@pixelfear.com>
  • Loading branch information
ryanmitchell and jasonvarga authored Oct 4, 2024
1 parent 69e78eb commit 3956ab1
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/Dictionaries/BasicDictionary.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ public function get(string $key): ?Item
}

public function options(?string $search = null): array
{
return collect($this->optionItems($search))
->mapWithKeys(fn (Item $item) => [$item->value() => $item->label()])
->all();
}

public function optionItems(?string $search = null): array
{
return $this
->getFilteredItems()
->when($search, fn ($collection) => $collection->filter(fn ($item) => $this->matchesSearchQuery($search, $item)))
->mapWithKeys(fn (Item $item) => [$item->value() => $item->label()])
->all();
}

Expand Down
7 changes: 7 additions & 0 deletions src/Dictionaries/Dictionary.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,11 @@ private function getInferredGqlType($value)

return GraphQL::string();
}

public function optionItems(?string $search = null): array
{
return collect($this->options($search))
->map(fn ($label, $value) => new Item($value, $label, $this->get($value)->extra()))
->all();
}
}
1 change: 1 addition & 0 deletions src/Providers/ExtensionServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class ExtensionServiceProvider extends ServiceProvider
Tags\Collection\Collection::class,
Tags\Cookie::class,
Tags\Dd::class,
Tags\Dictionary\Dictionary::class,
Tags\Dump::class,
Tags\GetContent::class,
Tags\GetError::class,
Expand Down
62 changes: 62 additions & 0 deletions src/Tags/Dictionary/Dictionary.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Statamic\Tags\Dictionary;

use Statamic\Data\DataCollection;
use Statamic\Exceptions\DictionaryNotFoundException;
use Statamic\Facades\Dictionary as Dictionaries;
use Statamic\Query\ItemQueryBuilder;
use Statamic\Tags\Concerns;
use Statamic\Tags\Tags;

class Dictionary extends Tags
{
use Concerns\GetsQueryResults,
Concerns\OutputsItems,
Concerns\QueriesConditions,
Concerns\QueriesOrderBys,
Concerns\QueriesScopes;

protected $defaultAsKey = 'options';

/**
* {{ dictionary:* }} ... {{ /dictionary:* }}.
*/
public function wildcard($tag)
{
return $this->loop($tag);
}

/**
* {{ dictionary handle="" }} ... {{ /dictionary }}.
*/
public function index()
{
return $this->loop($this->params->pull('handle'));
}

private function loop($handle)
{
if (! $handle) {
return [];
}

$search = $this->params->pull('search');

if (! $dictionary = Dictionaries::find($handle, $this->params->all())) {
throw new DictionaryNotFoundException($handle);
}

$options = (new DataCollection($dictionary->optionItems($search)))
->map(fn ($item) => new DictionaryItem($item->toArray()))
->values();

$query = (new ItemQueryBuilder)->withItems($options);

$this->queryConditions($query);
$this->queryOrderBys($query);
$this->queryScopes($query);

return $this->output($this->results($query));
}
}
26 changes: 26 additions & 0 deletions src/Tags/Dictionary/DictionaryItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Statamic\Tags\Dictionary;

use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Arr;
use Statamic\Data\ContainsSupplementalData;

class DictionaryItem implements Arrayable
{
use ContainsSupplementalData;

public function __construct(public array $data)
{
}

public function get($key, $default = null)
{
return Arr::get($this->toArray(), $key, $default);
}

public function toArray()
{
return array_merge($this->data, $this->supplements ?? []);
}
}
97 changes: 97 additions & 0 deletions tests/Tags/DictionaryTagTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

namespace Tests\Tags;

use PHPUnit\Framework\Attributes\Test;
use Statamic\Facades\Parse;
use Statamic\Query\Scopes\Scope;
use Tests\PreventSavingStacheItemsToDisk;
use Tests\TestCase;

class DictionaryTagTest extends TestCase
{
use PreventSavingStacheItemsToDisk;

#[Test]
public function it_gets_countries()
{
$template = '{{ dictionary:countries limit="1" }}{{ value }}{{ /dictionary:countries }}';

$this->assertEquals('AFG', $this->tag($template));
}

#[Test]
public function it_gets_dictionary_by_handle()
{
$template = '{{ dictionary handle="countries" limit="1" }}{{ value }}{{ /dictionary }}';

$this->assertEquals('AFG', $this->tag($template));
}

#[Test]
public function it_gets_timezones()
{
$template = '{{ dictionary:timezones limit="1" }}{{ value }}{{ /dictionary:timezones }}';

$this->assertEquals('Africa/Abidjan', $this->tag($template));
}

#[Test]
public function it_can_search()
{
$template = '{{ dictionary:countries search="Alg" }}{{ value }}{{ /dictionary:countries }}';

$this->assertEquals('DZA', $this->tag($template));
}

#[Test]
public function it_pulls_extra_data_data()
{
$template = '{{ dictionary:countries search="Alg" }}{{ region }} - {{ iso2 }}{{ /dictionary:countries }}';

$this->assertEquals('Africa - DZ', $this->tag($template));
}

#[Test]
public function it_can_paginate()
{
$template = '{{ dictionary:countries paginate="4" }}{{ options | count }}{{ /dictionary:countries }}';

$this->assertEquals('4', $this->tag($template));

$template = '{{ dictionary:countries paginate="4" as="countries" }}{{ countries | count }}{{ /dictionary:countries }}';

$this->assertEquals('4', $this->tag($template));
}

#[Test]
public function it_can_be_filtered_using_conditions()
{
$template = '{{ dictionary:countries iso3:is="AUS" }}{{ name }}{{ /dictionary:countries }}';

$this->assertEquals('Australia', $this->tag($template));
}

#[Test]
public function it_can_be_filtered_using_a_query_scope()
{
app('statamic.scopes')[TestScope::handle()] = TestScope::class;

$template = '{{ dictionary:countries query_scope="test_scope" }}{{ name }}{{ /dictionary:countries }}';

$this->assertEquals('Australia', $this->tag($template));
}

private function tag($tag, $data = [])
{
return (string) Parse::template($tag, $data);
}
}

class TestScope extends Scope
{
public function apply($query, $params)
{
$query->where('iso3', 'AUS');
}
}

0 comments on commit 3956ab1

Please sign in to comment.