Skip to content

Commit 9f3dcd6

Browse files
committed
add additional tests
1 parent 34c2668 commit 9f3dcd6

File tree

8 files changed

+461
-85
lines changed

8 files changed

+461
-85
lines changed

docs/source/handling_meta.rst

+12-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,18 @@ You can enforce that any meta attached to a particular key is always of a partic
149149
'children' => 'collection:\App\ExampleMetable',
150150
];
151151

152-
//...
152+
// equivalent to:
153+
protected function metaCasts(): array
154+
{
155+
return [
156+
'optin' => 'boolean',
157+
'age' => 'integer',
158+
'secret' => 'encrypted:string',
159+
'parent' => ExampleMetable::class,
160+
'children' => 'collection:\App\ExampleMetable',
161+
];
162+
}
163+
153164
}
154165

155166
All `cast types supported by Eloquent<https://laravel.com/docs/11.x/eloquent-mutators#attribute-casting>`_ are supported, with the following modifications:

src/Metable.php

+82-39
Original file line numberDiff line numberDiff line change
@@ -844,58 +844,22 @@ protected function castMetaValueIfNeeded(string $key, mixed $value): mixed
844844
protected function castMetaValue(string $key, mixed $value, string $cast): mixed
845845
{
846846
if ($cast == 'array' || $cast == 'object') {
847-
$assoc = $cast == 'array';
848-
if (is_string($value)) {
849-
$value = json_decode($value, $assoc, 512, JSON_THROW_ON_ERROR);
850-
}
851-
return json_decode(
852-
json_encode($value, JSON_THROW_ON_ERROR),
853-
$assoc,
854-
512,
855-
JSON_THROW_ON_ERROR
856-
);
847+
return $this->castMetaToJson($cast, $value);
857848
}
858849

859850
if ($cast == 'hashed') {
860851
return $this->castAttributeAsHashedString($key, $value);
861852
}
862853

863854
if ($cast == 'collection' || str_starts_with($cast, 'collection:')) {
864-
if ($value instanceof \Illuminate\Support\Collection) {
865-
$collection = $value;
866-
} elseif ($value instanceof Model) {
867-
$collection = $value->newCollection([$value]);
868-
} else {
869-
$collection = collect($value);
870-
}
871-
872-
if (str_starts_with($cast, 'collection:')) {
873-
$class = substr($cast, 11);
874-
$collection->each(function ($item) use ($class): void {
875-
if (!$item instanceof $class) {
876-
throw CastException::invalidClassCast($class, $item);
877-
}
878-
});
879-
}
880-
881-
return $collection;
855+
return $this->castMetaToCollection($cast, $value);
882856
}
883857

884858
if (class_exists($cast)
885859
&& !is_a($cast, Castable::class, true)
886860
&& $cast != 'datetime'
887861
) {
888-
if ($value instanceof $cast) {
889-
return $value;
890-
}
891-
892-
if (is_a($cast, Model::class, true)
893-
&& (is_string($value) || is_int($value))
894-
) {
895-
return $cast::find($value);
896-
}
897-
898-
throw CastException::invalidClassCast($cast, $value);
862+
return $this->castMetaToClass($value, $cast);
899863
}
900864

901865
// leverage Eloquent built-in casting functionality
@@ -1005,4 +969,83 @@ abstract public function load($relations);
1005969
abstract public function relationLoaded($key);
1006970

1007971
abstract protected function castAttributeAsHashedString($key, $value);
972+
973+
/**
974+
* @param mixed $value
975+
* @param string $cast
976+
* @return Collection|\Illuminate\Support\Collection
977+
*/
978+
protected function castMetaToCollection(string $cast, mixed $value): \Illuminate\Support\Collection
979+
{
980+
if ($value instanceof \Illuminate\Support\Collection) {
981+
$collection = $value;
982+
} elseif ($value instanceof Model) {
983+
$collection = $value->newCollection([$value]);
984+
} elseif (is_iterable($value)) {
985+
$isEloquentModels = true;
986+
$notEmpty = false;
987+
988+
foreach ($value as $item) {
989+
$notEmpty = true;
990+
if (!$item instanceof Model) {
991+
$isEloquentModels = false;
992+
break;
993+
}
994+
}
995+
$collection = $isEloquentModels && $notEmpty
996+
? $value[0]->newCollection($value)
997+
: collect($value);
998+
}
999+
1000+
if (str_starts_with($cast, 'collection:')) {
1001+
$class = substr($cast, 11);
1002+
$collection->each(function ($item) use ($class): void {
1003+
if (!$item instanceof $class) {
1004+
throw CastException::invalidClassCast($class, $item);
1005+
}
1006+
});
1007+
}
1008+
1009+
return $collection;
1010+
}
1011+
1012+
/**
1013+
* @param string $cast
1014+
* @param mixed $value
1015+
* @return mixed
1016+
* @throws \JsonException
1017+
*/
1018+
protected function castMetaToJson(string $cast, mixed $value): mixed
1019+
{
1020+
$assoc = $cast == 'array';
1021+
if (is_string($value)) {
1022+
$value = json_decode($value, $assoc, 512, JSON_THROW_ON_ERROR);
1023+
}
1024+
return json_decode(
1025+
json_encode($value, JSON_THROW_ON_ERROR),
1026+
$assoc,
1027+
512,
1028+
JSON_THROW_ON_ERROR
1029+
);
1030+
}
1031+
1032+
/**
1033+
* @param mixed $value
1034+
* @param string $cast
1035+
* @return mixed
1036+
*/
1037+
protected function castMetaToClass(mixed $value, string $cast): mixed
1038+
{
1039+
if ($value instanceof $cast) {
1040+
return $value;
1041+
}
1042+
1043+
if (is_a($cast, Model::class, true)
1044+
&& (is_string($value) || is_int($value))
1045+
) {
1046+
return $cast::findOrFail($value);
1047+
}
1048+
1049+
throw CastException::invalidClassCast($cast, $value);
1050+
}
10081051
}

src/MetableAttributes.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function offsetExists($key): bool
5252
return $this->hasMeta($this->metaAttributeToKey($key));
5353
}
5454

55-
return parent::isset($key);
55+
return parent::offsetExists($key);
5656
}
5757

5858
public function offsetUnset($key): void
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Plank\Metable\Tests\Integration\DataType;
4+
5+
use Plank\Metable\DataType\BackedEnumHandler;
6+
use Plank\Metable\DataType\PureEnumHandler;
7+
use Plank\Metable\Tests\TestCase;
8+
9+
class EnumHandlerTest extends TestCase
10+
{
11+
public function test_back_enum_handles_unknown_class()
12+
{
13+
$handler = new BackedEnumHandler();
14+
$this->assertNull($handler->unserializeValue('baz#value'));
15+
}
16+
17+
public function test_back_enum_handles_non_enum()
18+
{
19+
$handler = new BackedEnumHandler();
20+
$this->assertNull($handler->unserializeValue('stdClass#value'));
21+
}
22+
23+
public function test_pure_enum_handles_unknown_class()
24+
{
25+
$handler = new PureEnumHandler();
26+
$this->assertNull($handler->unserializeValue('baz#value'));
27+
}
28+
29+
public function test_pure_enum_handles_non_enum()
30+
{
31+
$handler = new PureEnumHandler();
32+
$this->assertNull($handler->unserializeValue('stdClass#value'));
33+
}
34+
}

tests/Integration/MetaTest.php

+7
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ public function test_it_can_encrypt_its_value(): void
8686
$this->assertEquals($hmac, $meta->hmac);
8787
$this->assertEquals('encrypted:string', $meta->type);
8888
$this->assertNull($meta->numeric_value);
89+
90+
91+
$rawValue = $meta->getRawValue();
92+
// should not re-encrypt
93+
$meta->encrypt();
94+
$this->assertEquals($rawValue, $meta->getRawValue());
95+
$this->assertEquals('encrypted:string', $meta->type);
8996
}
9097

9198
private function makeMeta(array $attributes = []): Meta

tests/Integration/MetableAttributesTest.php

+14-4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public function test_it_doesnt_overwrite_existing_attributes()
5252

5353
$model->setAttribute('meta_attribute', 'baz');
5454
$this->assertFalse($model->hasMeta('attribute'));
55+
56+
$model->meta_attribute = 'qux';
57+
$this->assertTrue($model->offsetExists('meta_attribute'));
58+
$model->offsetUnset('meta_attribute');
59+
$this->assertNull($model->meta_attribute);
5560
}
5661

5762
public function test_it_converts_to_array()
@@ -72,21 +77,26 @@ public function test_it_converts_to_array()
7277

7378
$model->makeHidden('meta_var2', 'created_at', 'updated_at', 'meta');
7479

75-
$array = $model->toArray();
7680
$this->assertEquals([
7781
'meta_attribute' => '',
7882
'id' => $model->getKey(),
7983
'meta_foo' => 'bar',
8084
'meta_var' => 'foo'
81-
], $array);
85+
], $model->toArray());
86+
87+
$model->includeMetaInArray = false;
88+
$this->assertEquals([
89+
'meta_attribute' => '',
90+
'id' => $model->getKey(),
91+
], $model->toArray());
8292

93+
$model->includeMetaInArray = true;
8394
$model->makeMetaHidden();
8495

85-
$array = $model->toArray();
8696
$this->assertEquals([
8797
'meta_attribute' => '',
8898
'id' => $model->getKey(),
89-
], $array);
99+
], $model->toArray());
90100
}
91101

92102
private function createMetable(array $attributes = []): SampleMetable

0 commit comments

Comments
 (0)