Skip to content
Open
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
17 changes: 16 additions & 1 deletion src/Data/AbstractAugmented.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Statamic\Data;

use ReflectionMethod;
use Statamic\Contracts\Data\Augmented;
use Statamic\Fields\Value;
use Statamic\Statamic;
Expand Down Expand Up @@ -97,11 +98,25 @@ private function methodExistsOnThisClass(string $method): bool

private function methodExistsOnData(string $handle, string $method): bool
{
return method_exists($this->data, $method)
// Non-public methods route through __call(), which re-augments the same handle forever
return $this->publicMethodExistsOnData($method)
&& collect($this->keys())->contains(Str::snake($handle))
&& ! in_array($handle, ['hook', 'value', 'entry']);
}

private function publicMethodExistsOnData(string $method): bool
{
static $cache = [];

if (! method_exists($this->data, $method)) {
return false;
}

$key = get_class($this->data).'::'.$method;

return $cache[$key] ??= (new ReflectionMethod($this->data, $method))->isPublic();
}

protected function getFromData($handle)
{
$value = method_exists($this->data, 'value') ? $this->data->value($handle) : $this->data->get($handle);
Expand Down
59 changes: 59 additions & 0 deletions tests/Data/AugmentedTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Statamic\Facades\Blueprint;
use Statamic\Fields\Fieldtype;
use Statamic\Fields\Value;
use Statamic\Support\Str;
use Tests\TestCase;

class AugmentedTest extends TestCase
Expand Down Expand Up @@ -332,6 +333,36 @@ public function no_infinite_loop_when_getting_keys_that_match_methods()
$this->assertEqualsValue('selected', $augmented->get('select'));
$this->assertEqualsValue('excepted', $augmented->get('except'));
}

#[Test]
public function it_ignores_non_public_methods_on_the_thing()
{
$thing = new ThingWithNonPublicMethods([
'protected_method' => 'protected data value',
'private_method' => 'private data value',
'public_method' => 'public data value',
]);

$augmented = new BaseAugmentedThing($thing);

$this->assertEqualsValue('protected data value', $augmented->get('protected_method'));
$this->assertEqualsValue('private data value', $augmented->get('private_method'));
$this->assertEqualsValue('from the public method', $augmented->get('public_method'));
}

#[Test]
public function it_uses_protected_methods_on_the_augmented_thing()
{
$augmented = new class($this->thing) extends BaseAugmentedThing
{
protected function foo()
{
return 'from the protected method';
}
};

$this->assertEqualsValue('from the protected method', $augmented->get('foo'));
}
}

class Thing
Expand Down Expand Up @@ -362,6 +393,34 @@ public function cantCallMe()
}
}

class ThingWithNonPublicMethods extends Thing
{
public function __call($method, $args)
{
return $this->augmentedValue(Str::snake($method));
}

public function augmentedValue($key)
{
return (new BaseAugmentedThing($this))->get($key);
}

public function publicMethod()
{
return 'from the public method';
}

protected function protectedMethod()
{
return 'from the protected method';
}

private function privateMethod()
{
return 'from the private method';
}
}

class BlueprintThing extends Thing
{
public function blueprint()
Expand Down
18 changes: 18 additions & 0 deletions tests/Data/Entries/AugmentedEntryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -251,4 +251,22 @@ public function it_doesnt_evaluated_computed_callbacks_when_getting_keys()
$augmented->get('computed');
$this->assertEquals(2, $computedCallbackCount);
}

#[Test]
public function it_gets_a_field_whose_name_matches_a_non_public_method_on_the_entry()
{
$blueprint = Blueprint::makeFromFields([
'cp_url' => ['type' => 'text'],
])->setHandle('test');
Blueprint::shouldReceive('in')->with('collections/test')->andReturn(collect(['test' => $blueprint]));

tap(Collection::make('test'))->save();

$entry = EntryFactory::collection('test')
->slug('entry-slug')
->data(['cp_url' => 'the stored value'])
->create();

$this->assertEquals('the stored value', $entry->augmentedValue('cp_url')->value());
}
}
Loading