Skip to content

Commit

Permalink
morphable extended support
Browse files Browse the repository at this point in the history
  • Loading branch information
AnourValar committed Nov 16, 2024
1 parent 6d7a868 commit 756c123
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 6 deletions.
78 changes: 74 additions & 4 deletions src/Grammars/ModelGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,24 @@ protected function unpack(\AnourValar\EloquentSerialize\Package $package): \Illu
*/
private function setup(): void
{
\Illuminate\Database\Eloquent\Relations\Relation::macro('importExtraParametersForSerialize', function (array $params) {
$serializeMorphableEager = fn ($value) => $this->serializeMorphableEager($value);
$unserializeMorphableEager = fn ($value) => $this->unserializeMorphableEager($value);

\Illuminate\Database\Eloquent\Relations\Relation::macro('importExtraParametersForSerialize', function (array $params) use ($unserializeMorphableEager) {
foreach ($params as $key => $value) {
if ($key == 'morphableEagerLoads' || $key == 'morphableEagerLoadCounts') {
$value = $unserializeMorphableEager($value);
}

$this->$key = $value;
}
});

\Illuminate\Database\Eloquent\Relations\Relation::macro('exportExtraParametersForSerialize', function () {
\Illuminate\Database\Eloquent\Relations\Relation::macro('exportExtraParametersForSerialize', function () use ($serializeMorphableEager) {
if ($this instanceof \Illuminate\Database\Eloquent\Relations\MorphTo) {
return [
'morphableEagerLoads' => $this->morphableEagerLoads,
'morphableEagerLoadCounts' => $this->morphableEagerLoadCounts,
'morphableEagerLoads' => $serializeMorphableEager($this->morphableEagerLoads),
'morphableEagerLoadCounts' => $serializeMorphableEager($this->morphableEagerLoadCounts),
'morphableConstraints' => $this->morphableConstraints,
];
}
Expand All @@ -77,4 +84,67 @@ private function setup(): void
return null;
});
}

/**
* @param array $value
* @return array
* @psalm-suppress UndefinedClass
*/
private function serializeMorphableEager(array $value): array
{
foreach ($value as $class => &$items) {
foreach ($items as $relation => &$item) {
if (! is_callable($item)) {
continue;
}

if (! method_exists($class, $relation)) {
throw new \RuntimeException("Serialization error. Does relation '{$relation}' exists in the model '{$class}' ?");
}

// ALT: $obj->cleanStaticConstraints($item['builder'], $obj->packQueryBuilder((new $class)->getQuery()->getQuery()));
$eloquentBuilder = (new $class())->$relation()->getModel()->newQuery();
$item($eloquentBuilder);

$item = [
'eloquent' => $this->packEloquentBuilder($eloquentBuilder),
'builder' => $this->packQueryBuilder($eloquentBuilder->getQuery()),
];
}
unset($item);
}
unset($items);

return $value;
}

/**
* @param array $value
* @return array
*/
private function unserializeMorphableEager(array $value): array
{
foreach ($value as &$items) {
foreach ($items as &$item) {
if (! is_array($item)) {
continue;
}

$item = function ($query) use ($item) {
if ($query instanceof \Illuminate\Database\Eloquent\Builder) {
$this->unpackEloquentBuilder($item['eloquent'], $query);
$this->unpackQueryBuilder($item['builder'], $query->getQuery());
} else {
$eloquent = $query->getQuery();
$this->unpackEloquentBuilder($item['eloquent'], $eloquent);
$this->unpackQueryBuilder($item['builder'], $query->getBaseQuery());
}
};
}
unset($item);
}
unset($items);

return $value;
}
}
2 changes: 1 addition & 1 deletion tests/AbstractSuite.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected function setUpSeeder()
factory(File::class)->times(40)->create();

factory(Post::class)->times(10)->create();
factory(Tag::class)->times(10)->create();
factory(Tag::class)->times(30)->create();
}

/**
Expand Down
28 changes: 28 additions & 0 deletions tests/EagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ public function testMorphTo()
Tag::with(['taggable' => function (\Illuminate\Database\Eloquent\Relations\MorphTo $morphTo) {
$morphTo->morphWith([
Post::class => ['user'],
UserPhone::class => ['userPhoneNote'],
]);
}])
);
Expand All @@ -342,6 +343,7 @@ public function testMorphTo()
Tag::with(['taggable' => function (\Illuminate\Database\Eloquent\Relations\MorphTo $morphTo) {
$morphTo->morphWithCount([
Post::class => ['user'],
UserPhone::class => ['userPhoneNote'],
]);
}])
);
Expand All @@ -352,6 +354,32 @@ public function testMorphTo()
$morphOne->with('taggable');
}])
);

// Nested - closure
$this->compare(
Tag::with(['taggable' => function (\Illuminate\Database\Eloquent\Relations\MorphTo $morphTo) {
$morphTo->morphWith([
Post::class => [
'user' => fn ($query) => $query->with('userPhones')->where('id', '>', 0)->whereIn('sort', [1, 2, 3, 4, 5]),
'tag' => fn ($query) => $query->where('id', '>', 5),
],
UserPhone::class => ['user', 'userPhoneNote' => fn ($query) => $query->whereNotNull('note')],
]);
}])
);

// Nested count - closure
$this->compare(
Tag::with(['taggable' => function (\Illuminate\Database\Eloquent\Relations\MorphTo $morphTo) {
$morphTo->morphWithCount([
Post::class => [
'user' => fn ($query) => $query->with('userPhones')->where('id', '>', 0)->whereIn('sort', [1, 2, 3, 4, 5]),
'tag' => fn ($query) => $query->where('id', '>', 5),
],
UserPhone::class => ['user', 'userPhoneNote' => fn ($query) => $query->whereNotNull('note')],
]);
}])
);
}

/**
Expand Down
5 changes: 5 additions & 0 deletions tests/Models/UserPhone.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

class UserPhone extends \Illuminate\Database\Eloquent\Model
{
public function tag()
{
return $this->morphOne(Tag::class, 'taggable');
}

/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
Expand Down
2 changes: 1 addition & 1 deletion tests/factories/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@
'taggable_id' => function () use ($posts) {
return $posts->shuffle()->first();
},
'taggable_type' => Post::class,
'taggable_type' => $faker->randomElement([Post::class, UserPhone::class]),
];
});

0 comments on commit 756c123

Please sign in to comment.