diff --git a/src/Traits/Liker.php b/src/Traits/Liker.php index 449e748..fd70573 100644 --- a/src/Traits/Liker.php +++ b/src/Traits/Liker.php @@ -6,7 +6,10 @@ use Illuminate\Contracts\Pagination\Paginator; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Pagination\AbstractCursorPaginator; +use Illuminate\Pagination\AbstractPaginator; use Illuminate\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; use Illuminate\Support\Enumerable; use Illuminate\Support\LazyCollection; use Overtrue\LaravelLike\Like; @@ -101,7 +104,7 @@ public function likes(): HasMany /** * Get Query Builder for likes * - * @return Illuminate\Database\Eloquent\Builder + * @return \Illuminate\Database\Eloquent\Builder */ public function getLikedItems(string $model) { @@ -113,48 +116,41 @@ function ($q) { ); } - public function attachLikeStatus($likeables, callable $resolver = null) + public function attachLikeStatus(&$likeables, callable $resolver = null) { - $returnFirst = false; - $toArray = false; - - switch (true) { - case $likeables instanceof Model: - $returnFirst = true; - $likeables = \collect([$likeables]); - break; - case $likeables instanceof LengthAwarePaginator: - $likeables = $likeables->getCollection(); - break; - case $likeables instanceof Paginator: - case $likeables instanceof CursorPaginator: - $likeables = \collect($likeables->items()); - break; - case $likeables instanceof LazyCollection: - $likeables = \collect($likeables->all()); - break; - case \is_array($likeables): - $likeables = \collect($likeables); - $toArray = true; - break; - } - - \abort_if(!($likeables instanceof Enumerable), 422, 'Invalid $likeables type'); - - $liked = $this->likes()->get()->keyBy(function ($item) { + $likes = $this->likes()->get()->keyBy(function ($item) { return \sprintf('%s:%s', $item->likeable_type, $item->likeable_id); }); - $likeables->map(function ($likeable) use ($liked, $resolver) { + $attachStatus = function($likeable) use ($likes, $resolver) { $resolver = $resolver ?? fn ($m) => $m; $likeable = $resolver($likeable); if ($likeable && \in_array(Likeable::class, \class_uses_recursive($likeable))) { $key = \sprintf('%s:%s', $likeable->getMorphClass(), $likeable->getKey()); - $likeable->setAttribute('has_liked', $liked->has($key)); + $likeable->setAttribute('has_liked', $likes->has($key)); } - }); - return $returnFirst ? $likeables->first() : ($toArray ? $likeables->all() : $likeables); + return $likeable; + }; + + switch (true) { + case $likeables instanceof Model: + return $attachStatus($likeables); + case $likeables instanceof Collection: + return $likeables->each($attachStatus); + case $likeables instanceof LazyCollection: + return $likeables = $likeables->map($attachStatus); + case $likeables instanceof AbstractPaginator: + case $likeables instanceof AbstractCursorPaginator: + return $likeables->through($attachStatus); + case $likeables instanceof Paginator: + // custom paginator will return a collection + return collect($likeables->items())->transform($attachStatus); + case \is_array($likeables): + return \collect($likeables)->transform($attachStatus); + default: + throw new \InvalidArgumentException('Invalid argument type.'); + } } } diff --git a/tests/FeatureTest.php b/tests/FeatureTest.php index 4d3bf16..f3aee2f 100644 --- a/tests/FeatureTest.php +++ b/tests/FeatureTest.php @@ -182,21 +182,30 @@ public function test_liker_can_attach_like_status_to_votable_collection() $user->like($post1); $user->like($post2); + // model + $post1 = Post::find($post1->id); + $this->assertNull($post1->has_liked); + $user->attachLikeStatus($post1); + $this->assertTrue($post1->has_liked); + + // collection $posts = Post::oldest('id')->get(); $user->attachLikeStatus($posts); - $posts = $posts->toArray(); + $this->assertTrue($posts[0]['has_liked']); + $this->assertTrue($posts[1]['has_liked']); + $this->assertFalse($posts[2]['has_liked']); - // user has up liked post1 + // lazy collection + $posts = Post::oldest('id')->cursor(); + $user->attachLikeStatus($posts); + $posts = $posts->toArray(); $this->assertTrue($posts[0]['has_liked']); - // user has down liked post2 $this->assertTrue($posts[1]['has_liked']); - // user hasn't liked post3 $this->assertFalse($posts[2]['has_liked']); // paginator $posts = Post::oldest('id')->paginate(); $user->attachLikeStatus($posts); - $posts = $posts->toArray()['data']; $this->assertTrue($posts[0]['has_liked']); $this->assertTrue($posts[1]['has_liked']); $this->assertFalse($posts[2]['has_liked']); @@ -204,28 +213,23 @@ public function test_liker_can_attach_like_status_to_votable_collection() // cursor paginator $posts = Post::oldest('id')->cursorPaginate(); $user->attachLikeStatus($posts); - $posts = $posts->toArray()['data']; $this->assertTrue($posts[0]['has_liked']); $this->assertTrue($posts[1]['has_liked']); $this->assertFalse($posts[2]['has_liked']); - // cursor - $posts = Post::oldest('id')->cursor(); - $posts = $user->attachLikeStatus($posts); - $posts = $posts->toArray(); + // array + $posts = Post::oldest('id')->get()->all(); + $user->attachLikeStatus($posts); $this->assertTrue($posts[0]['has_liked']); $this->assertTrue($posts[1]['has_liked']); $this->assertFalse($posts[2]['has_liked']); // custom resolver $posts = [['post' => $post1], ['post' => $post2], ['post' => $post3]]; - $posts = $user->attachLikeStatus($posts, fn ($i) => $i['post']); + $user->attachLikeStatus($posts, fn ($i) => $i['post']); - // user has up liked post1 $this->assertTrue($posts[0]['post']['has_liked']); - // user has down liked post2 $this->assertTrue($posts[1]['post']['has_liked']); - // user hasn't liked post3 $this->assertFalse($posts[2]['post']['has_liked']); }