diff --git a/src/Contracts/Data/Augmentable.php b/src/Contracts/Data/Augmentable.php index 3ef410e154..6fb1766f4d 100644 --- a/src/Contracts/Data/Augmentable.php +++ b/src/Contracts/Data/Augmentable.php @@ -2,7 +2,7 @@ namespace Statamic\Contracts\Data; -interface Augmentable +interface Augmentable extends \JsonSerializable { public function augmentedValue($key); diff --git a/src/Data/HasAugmentedData.php b/src/Data/HasAugmentedData.php index d1ba21606b..4fb055ea97 100644 --- a/src/Data/HasAugmentedData.php +++ b/src/Data/HasAugmentedData.php @@ -15,6 +15,14 @@ public function newAugmentedInstance(): Augmented public function augmentedArrayData() { - return method_exists($this, 'values') ? $this->values() : $this->data(); + if (method_exists($this, 'values')) { + return $this->values(); + } + + if (method_exists($this, 'data')) { + return $this->data(); + } + + throw new \Exception('Augmentable object must have a values() or data() method, or override the augmentedArrayData() method.'); } } diff --git a/src/Data/HasAugmentedInstance.php b/src/Data/HasAugmentedInstance.php index 635f54f927..e278c2e790 100644 --- a/src/Data/HasAugmentedInstance.php +++ b/src/Data/HasAugmentedInstance.php @@ -86,6 +86,11 @@ public function toArray() return $this->toEvaluatedAugmentedArray(); } + public function jsonSerialize(): mixed + { + return $this->toArray(); + } + public function __get($key) { $value = $this->augmentedValue($key); diff --git a/src/Fields/Value.php b/src/Fields/Value.php index 0ddd7b024b..b51ff8097f 100644 --- a/src/Fields/Value.php +++ b/src/Fields/Value.php @@ -8,6 +8,7 @@ use JsonSerializable; use Statamic\Contracts\Data\Augmentable; use Statamic\Contracts\View\Antlers\Parser; +use Statamic\Facades\Compare; use Statamic\Support\Str; use Statamic\View\Antlers\Language\Parser\DocumentTransformer; @@ -60,8 +61,12 @@ public function jsonSerialize($options = 0) { $value = $this->value(); + if (Compare::isQueryBuilder($value)) { + $value = $value->get(); + } + if ($value instanceof Augmentable || $value instanceof Collection) { - $value = $value->toAugmentedArray(); + $value = $value->toArray(); } return $value; diff --git a/src/Modifiers/CoreModifiers.php b/src/Modifiers/CoreModifiers.php index 00bc863338..d2efb0417f 100644 --- a/src/Modifiers/CoreModifiers.php +++ b/src/Modifiers/CoreModifiers.php @@ -2545,10 +2545,6 @@ public function toJson($value, $params) $value = $value->get(); } - if ($value instanceof Collection || $value instanceof Augmentable) { - $value = $value->toAugmentedArray(); - } - return json_encode($value, $options); } diff --git a/tests/Data/AugmentedCollectionTest.php b/tests/Data/AugmentedCollectionTest.php index c600791f0b..50271578bf 100644 --- a/tests/Data/AugmentedCollectionTest.php +++ b/tests/Data/AugmentedCollectionTest.php @@ -7,20 +7,15 @@ use Illuminate\Database\Query\Builder as LaravelQueryBuilder; use JsonSerializable; use Mockery as m; -use PHPUnit\Framework\TestCase; use Statamic\Contracts\Data\Augmentable; use Statamic\Contracts\Query\Builder as StatamicQueryBuilder; use Statamic\Data\AugmentedCollection; use Statamic\Data\HasAugmentedData; use Statamic\Fields\Value; +use Tests\TestCase; class AugmentedCollectionTest extends TestCase { - public function tearDown(): void - { - m::close(); - } - /** @test */ public function it_calls_toArray_on_each_item() { @@ -147,7 +142,7 @@ public function it_json_serializes() new TestArrayableObject, new TestJsonableObject, new TestJsonSerializeObject, - $augmentable = new TestAugmentableObject, + $augmentable = new TestAugmentableObject(['foo' => 'bar']), 'baz', $value, ]); @@ -156,7 +151,7 @@ public function it_json_serializes() ['foo' => 'bar'], ['foo' => 'bar'], ['foo' => 'bar'], - $augmentable, + ['foo' => 'bar'], 'baz', 'value json serialized', ], $c->jsonSerialize()); @@ -172,7 +167,7 @@ public function augmentables_get_shallow_augmented_when_json_serializing_with_fl new TestArrayableObject, new TestJsonableObject, new TestJsonSerializeObject, - new TestAugmentableObject, + new TestAugmentableObject(['foo' => 'bar']), 'baz', $value, ]); @@ -217,6 +212,16 @@ class TestAugmentableObject implements Augmentable { use HasAugmentedData; + public function __construct(private $data) + { + + } + + public function augmentedArrayData() + { + return $this->data; + } + public function toShallowAugmentedArray() { return ['shallow augmented augmentable']; diff --git a/tests/Modifiers/ToJsonTest.php b/tests/Modifiers/ToJsonTest.php new file mode 100644 index 0000000000..14d2d2f3fd --- /dev/null +++ b/tests/Modifiers/ToJsonTest.php @@ -0,0 +1,89 @@ +modify(value($input)); + + $this->assertEquals($expected, $modified); + } + + /** + * @test + * + * @dataProvider bourneJsonBourneProvider + */ + public function it_pretty_prints($input, $expected): void + { + $modified = $this->modify(value($input), ['pretty']); + + $this->assertEquals(json_encode(json_decode($expected, true), JSON_PRETTY_PRINT), $modified); + } + + private function modify($value, $options = []) + { + return Modify::value($value)->toJson($options)->fetch(); + } + + public static function bourneJsonBourneProvider(): array + { + return [ + 'empty array' => [[], '[]'], + 'array' => [['book' => 'All The Places You\'ll Go'], '{"book":"All The Places You\'ll Go"}'], + 'string' => ['foo bar baz', '"foo bar baz"'], + 'null' => [null, 'null'], + 'collection' => [collect(['book' => 'All The Places You\'ll Go']), '{"book":"All The Places You\'ll Go"}'], + 'collection with JsonSerializables' => [ + collect([ + new class implements \JsonSerializable + { + public function jsonSerialize(): array + { + return ['book' => 'All The Places You\'ll Go']; + } + }, + new class implements \JsonSerializable + { + public function jsonSerialize(): array + { + return ['book' => 'Oh, The Places You\'ll Go']; + } + }, + ]), '[{"book":"All The Places You\'ll Go"},{"book":"Oh, The Places You\'ll Go"}]', + ], + 'JsonSerializable object' => [ + new class implements \JsonSerializable + { + public function jsonSerialize(): array + { + return ['book' => 'All The Places You\'ll Go']; + } + }, '{"book":"All The Places You\'ll Go"}', + ], + 'query builder' => [ + function () { + EntryFactory::collection('blog')->data(['title' => 'Post One'])->create(); + EntryFactory::collection('blog')->data(['title' => 'Post Two'])->create(); + + return Entry::query()->get(['title']); + }, '[{"title":"Post One"},{"title":"Post Two"}]', + ], + ]; + } +}