Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] JSON Serialization #9672

Merged
merged 6 commits into from
Apr 12, 2024
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: 1 addition & 1 deletion src/Contracts/Data/Augmentable.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Statamic\Contracts\Data;

interface Augmentable
interface Augmentable extends \JsonSerializable
{
public function augmentedValue($key);

Expand Down
10 changes: 9 additions & 1 deletion src/Data/HasAugmentedData.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
}
}
5 changes: 5 additions & 0 deletions src/Data/HasAugmentedInstance.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion src/Fields/Value.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
4 changes: 0 additions & 4 deletions src/Modifiers/CoreModifiers.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
23 changes: 14 additions & 9 deletions tests/Data/AugmentedCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -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,
]);
Expand All @@ -156,7 +151,7 @@ public function it_json_serializes()
['foo' => 'bar'],
['foo' => 'bar'],
['foo' => 'bar'],
$augmentable,
['foo' => 'bar'],
'baz',
'value json serialized',
], $c->jsonSerialize());
Expand All @@ -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,
]);
Expand Down Expand Up @@ -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'];
Expand Down
89 changes: 89 additions & 0 deletions tests/Modifiers/ToJsonTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace Modifiers;

use Facades\Tests\Factories\EntryFactory;
use Statamic\Facades\Entry;
use Statamic\Modifiers\Modify;
use Tests\PreventSavingStacheItemsToDisk;
use Tests\TestCase;

class ToJsonTest extends TestCase
{
use PreventSavingStacheItemsToDisk;

/**
* @test
*
* @dataProvider bourneJsonBourneProvider
*/
public function it_converts_to_json($input, $expected): void
{
$modified = $this->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"}]',
],
];
}
}
Loading