Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
### What's fixed
- CP forms only submit visible fields, in order to fix sometimes/required_if/etc validation rules. [#5101](https://github.com/statamic/cms/issues/5101) by @jesseleite

### What's changed
- Entries fieldtypes augment to query builders instead of collections. [#5238](https://github.com/statamic/cms/issues/5238) by @jasonvarga


## 3.2.32 (2022-01-26)
Expand Down
41 changes: 31 additions & 10 deletions src/Fieldtypes/Entries.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,23 +214,44 @@ protected function collect($value)
return new \Statamic\Entries\EntryCollection($value);
}

protected function augmentValue($value)
public function augment($values)
{
if (! is_object($value)) {
$value = Entry::find($value);
$site = Site::current()->handle();
if (($parent = $this->field()->parent()) && $parent instanceof Localization) {
$site = $parent->locale();
}

if ($value != null && $parent = $this->field()->parent()) {
$site = $parent instanceof Localization ? $parent->locale() : Site::current()->handle();
$value = $value->in($site);
}
$ids = Entry::query()
->whereIn('id', Arr::wrap($values))
->get()
->map(function ($entry) use ($site) {
return optional($entry->in($site))->id();
})
->filter()
->all();

$query = Entry::query()
->whereIn('id', $ids)
->where('status', 'published');

return ($value && $value->status() === 'published') ? $value : null;
return $this->config('max_items') === 1 ? $query->first() : $query;
}

protected function shallowAugmentValue($value)
public function shallowAugment($values)
{
return $value->toShallowAugmentedCollection();
$items = $this->augment($values);

if ($this->config('max_items') === 1) {
$items = collect([$items]);
} else {
$items = $items->get();
}

$items = $items->filter()->map(function ($item) {
return $item->toShallowAugmentedCollection();
});

return $this->config('max_items') === 1 ? $items->first() : $items;
}

public function getSelectionFilters()
Expand Down
5 changes: 5 additions & 0 deletions src/GraphQL/ResolvesValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Statamic\GraphQL;

use Statamic\Contracts\Query\Builder;
use Statamic\Fields\Value;

trait ResolvesValues
Expand All @@ -14,6 +15,10 @@ public function resolveGqlValue($field)
$value = $value->value();
}

if ($value instanceof Builder) {
$value = $value->get();
}

return $value;
}

Expand Down
10 changes: 8 additions & 2 deletions src/View/Antlers/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,10 @@ public function parseCallbackTags($text, $data)
// a callback. If it's a query builder instance, we want to use the Query tag's index
// method to handle the logic. We'll pass the builder into the builder parameter.
if (isset($data[$name])) {
if ($data[$name] instanceof Builder) {
$parameters['builder'] = $data[$name];
$value = $data[$name];
$value = $value instanceof Value ? $value->value() : $value;
if ($value instanceof Builder) {
$parameters['builder'] = $value;
$name = 'query';
}
}
Expand Down Expand Up @@ -1235,6 +1237,10 @@ protected function getVariableExistenceAndValue($key, $context)
$context = $context->value();
}

if ($context instanceof Builder) {
$context = $context->get();
}

if ($context instanceof Augmentable) {
$context = $context->toAugmentedArray();
}
Expand Down
244 changes: 234 additions & 10 deletions tests/Fieldtypes/EntriesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Statamic\Contracts\Entries\Entry;
use Statamic\Contracts\Query\Builder;
use Statamic\Data\AugmentedCollection;
use Statamic\Facades;
use Statamic\Facades\Site;
use Statamic\Fields\Field;
use Statamic\Fieldtypes\Entries;
use Tests\PreventSavingStacheItemsToDisk;
Expand All @@ -23,23 +25,39 @@ public function setUp(): void

Carbon::setTestNow(Carbon::parse('2021-01-02'));

$collection = tap(Facades\Collection::make('blog')->routes('blog/{slug}'))->dated(true)->pastDateBehavior('private')->futureDateBehavior('private')->save();
Site::setConfig(['sites' => [
'en' => ['url' => 'http://localhost/', 'locale' => 'en'],
'fr' => ['url' => 'http://localhost/fr/', 'locale' => 'fr'],
]]);

$collection = tap(Facades\Collection::make('blog')->routes('blog/{slug}'))->sites(['en', 'fr'])->dated(true)->pastDateBehavior('private')->futureDateBehavior('private')->save();

EntryFactory::id('123')->collection($collection)->slug('one')->data(['title' => 'One'])->date('2021-01-02')->create();
EntryFactory::id('456')->collection($collection)->slug('two')->data(['title' => 'Two'])->date('2021-01-02')->create();
EntryFactory::id('789')->collection($collection)->slug('three')->data(['title' => 'Three'])->date('2021-01-02')->create();
EntryFactory::id('910')->collection($collection)->slug('four')->data(['title' => 'Four'])->date('2021-01-02')->create();
EntryFactory::id('draft')->collection($collection)->slug('draft')->data(['title' => 'Draft'])->published(false)->create();
EntryFactory::id('scheduled')->collection($collection)->slug('scheduled')->data(['title' => 'Scheduled'])->date('2021-01-03')->create();
EntryFactory::id('expired')->collection($collection)->slug('expired')->data(['title' => 'Expired'])->date('2021-01-01')->create();
}

/** @test */
public function it_augments_to_a_collection_of_entries()
public function it_augments_to_a_query_builder()
{
$augmented = $this->fieldtype()->augment(['123', 'invalid', 456, 'draft', 'scheduled', 'expired']);

$this->assertInstanceOf(Collection::class, $augmented);
$this->assertEveryItemIsInstanceOf(Entry::class, $augmented);
$this->assertEquals(['one', 'two'], $augmented->map->slug()->all());
$this->assertInstanceOf(Builder::class, $augmented);
$this->assertEveryItemIsInstanceOf(Entry::class, $augmented->get());
$this->assertEquals(['one', 'two'], $augmented->get()->map->slug()->all());
}

/** @test */
public function it_augments_to_a_query_builder_when_theres_no_value()
{
$augmented = $this->fieldtype()->augment(null);

$this->assertInstanceOf(Builder::class, $augmented);
$this->assertCount(0, $augmented->get());
}

/** @test */
Expand All @@ -52,9 +70,88 @@ public function it_augments_to_a_single_asset_when_max_items_is_one()
}

/** @test */
public function it_shallow_augments_to_a_collection_of_enties()
public function it_localizes_the_augmented_items_to_the_parent_entrys_locale()
{
$augmented = $this->fieldtype()->shallowAugment(['123', '456']);
$parent = EntryFactory::id('parent')->collection('blog')->slug('theparent')->locale('fr')->create();

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();
EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->published(false)->create();
EntryFactory::id('910-fr')->origin('910')->locale('fr')->collection('blog')->slug('four-fr')->data(['title' => 'Le Four'])->date('2021-01-02')->create();

$augmented = $this->fieldtype([], $parent)->augment(['123', 'invalid', 456, 789, 910, 'draft', 'scheduled', 'expired']);

$this->assertInstanceOf(Builder::class, $augmented);
$this->assertEveryItemIsInstanceOf(Entry::class, $augmented->get());
$this->assertEquals(['one-fr', 'four-fr'], $augmented->get()->map->slug()->all()); // 456 isn't localized, and 789-fr is a draft.
}

/** @test */
public function it_localizes_the_augmented_item_to_the_parent_entrys_locale_when_max_items_is_one()
{
$parent = EntryFactory::id('parent')->collection('blog')->slug('theparent')->locale('fr')->create();

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();
EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->published(false)->create();

$fieldtype = $this->fieldtype(['max_items' => 1], $parent);

$augmented = $fieldtype->augment(['123']);
$this->assertInstanceOf(Entry::class, $augmented);
$this->assertEquals('one-fr', $augmented->slug());

$augmented = $fieldtype->augment(['456']);
$this->assertNull($augmented); // 456 isnt localized

$augmented = $fieldtype->augment(['789']);
$this->assertNull($augmented); // 789-fr is a draft
}

/** @test */
public function it_localizes_the_augmented_items_to_the_current_sites_locale_when_parent_is_not_localizable()
{
Site::setCurrent('fr');

$parent = new class
{
// Class does not implement "Localizable"
};

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();
EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->create();

$augmented = $this->fieldtype([], $parent)->augment(['123', 'invalid', 456, 789, 'draft', 'scheduled', 'expired']);

$this->assertInstanceOf(Builder::class, $augmented);
$this->assertEveryItemIsInstanceOf(Entry::class, $augmented->get());
$this->assertEquals(['one-fr', 'three-fr'], $augmented->get()->map->slug()->all()); // only 123 and 789 have localized versions
}

/** @test */
public function it_localizes_the_augmented_item_to_the_current_sites_locale_when_parent_is_not_localizable_when_max_items_is_one()
{
Site::setCurrent('fr');

$parent = new class
{
// Class does not implement "Localizable"
};

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();

$fieldtype = $this->fieldtype(['max_items' => 1], $parent);

$augmented = $fieldtype->augment(['123'], $parent);
$this->assertInstanceOf(Entry::class, $augmented);
$this->assertEquals('one-fr', $augmented->slug());

$augmented = $fieldtype->augment(['456'], $parent);
$this->assertNull($augmented); // 456 isnt localized
}

/** @test */
public function it_shallow_augments_to_a_collection_of_entries()
{
$augmented = $this->fieldtype()->shallowAugment(['123', 'invalid', 456, 'draft', 'scheduled', 'expired']);

$this->assertInstanceOf(Collection::class, $augmented);
$this->assertEveryItemIsInstanceOf(AugmentedCollection::class, $augmented);
Expand Down Expand Up @@ -91,10 +188,137 @@ public function it_shallow_augments_to_a_single_entry_when_max_items_is_one()
], $augmented->toArray());
}

public function fieldtype($config = [])
/** @test */
public function it_localizes_the_shallow_augmented_items_to_the_parent_entrys_locale()
{
return (new Entries)->setField(new Field('test', array_merge([
$parent = EntryFactory::id('parent')->collection('blog')->slug('theparent')->locale('fr')->create();

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();
EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->published(false)->create();
EntryFactory::id('910-fr')->origin('910')->locale('fr')->collection('blog')->slug('four-fr')->data(['title' => 'Le Four'])->date('2021-01-02')->create();

$augmented = $this->fieldtype([], $parent)->shallowAugment(['123', 'invalid', 456, 789, 910, 'draft', 'scheduled', 'expired']);

$this->assertInstanceOf(Collection::class, $augmented);
$this->assertEveryItemIsInstanceOf(AugmentedCollection::class, $augmented);
$this->assertEquals([
[
'id' => '123-fr',
'title' => 'Le One',
'url' => '/fr/blog/one-fr',
'permalink' => 'http://localhost/fr/blog/one-fr',
'api_url' => 'http://localhost/api/collections/blog/entries/123-fr',
],
[
'id' => '910-fr',
'title' => 'Le Four',
'url' => '/fr/blog/four-fr',
'permalink' => 'http://localhost/fr/blog/four-fr',
'api_url' => 'http://localhost/api/collections/blog/entries/910-fr',
],
], $augmented->toArray()); // 456 isn't localized, and 789-fr is a draft.
}

/** @test */
public function it_localizes_the_shallow_augmented_item_to_the_parent_entrys_locale_when_max_items_is_one()
{
$parent = EntryFactory::id('parent')->collection('blog')->slug('theparent')->locale('fr')->create();

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();
EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->published(false)->create();

$fieldtype = $this->fieldtype(['max_items' => 1], $parent);

$augmented = $fieldtype->shallowAugment(['123']);
$this->assertInstanceOf(AugmentedCollection::class, $augmented);
$this->assertEquals([
'id' => '123-fr',
'title' => 'Le One',
'url' => '/fr/blog/one-fr',
'permalink' => 'http://localhost/fr/blog/one-fr',
'api_url' => 'http://localhost/api/collections/blog/entries/123-fr',
], $augmented->toArray());

$augmented = $fieldtype->shallowAugment(['456']);
$this->assertNull($augmented); // 456 isnt localized

$augmented = $fieldtype->shallowAugment(['789']);
$this->assertNull($augmented); // 789-fr is a draft
}

/** @test */
public function it_localizes_the_shallow_augmented_items_to_the_current_sites_locale_when_parent_is_not_localizable()
{
Site::setCurrent('fr');

$parent = new class
{
// Class does not implement "Localizable"
};

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();
EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->create();

$augmented = $this->fieldtype([], $parent)->shallowAugment(['123', 'invalid', 456, 789, 'draft', 'scheduled', 'expired']);

$this->assertInstanceOf(Collection::class, $augmented);
$this->assertEveryItemIsInstanceOf(AugmentedCollection::class, $augmented);
$this->assertEquals([
[
'id' => '123-fr',
'title' => 'Le One',
'url' => '/fr/blog/one-fr',
'permalink' => 'http://localhost/fr/blog/one-fr',
'api_url' => 'http://localhost/api/collections/blog/entries/123-fr',
],
[
'id' => '789-fr',
'title' => 'Le Three',
'url' => '/fr/blog/three-fr',
'permalink' => 'http://localhost/fr/blog/three-fr',
'api_url' => 'http://localhost/api/collections/blog/entries/789-fr',
],
], $augmented->toArray()); // only 123 and 789 have localized versions
}

/** @test */
public function it_localizes_the_shallow_augmented_item_to_the_current_sites_locale_when_parent_is_not_localizable_when_max_items_is_one()
{
Site::setCurrent('fr');

$parent = new class
{
// Class does not implement "Localizable"
};

EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create();

$fieldtype = $this->fieldtype(['max_items' => 1], $parent);

$augmented = $fieldtype->shallowAugment(['123']);
$this->assertInstanceOf(AugmentedCollection::class, $augmented);
$this->assertEquals([
'id' => '123-fr',
'title' => 'Le One',
'url' => '/fr/blog/one-fr',
'permalink' => 'http://localhost/fr/blog/one-fr',
'api_url' => 'http://localhost/api/collections/blog/entries/123-fr',
], $augmented->toArray());

$augmented = $fieldtype->shallowAugment(['456']);
$this->assertNull($augmented); // 456 isnt localized
}

public function fieldtype($config = [], $parent = null)
{
$field = new Field('test', array_merge([
'type' => 'entries',
], $config)));
], $config));

if ($parent) {
$field->setParent($parent);
}

return (new Entries)->setField($field);
}
}
Loading