-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bee3c8d
commit a1be948
Showing
10 changed files
with
339 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Like\Events; | ||
|
||
use Illuminate\Database\Eloquent\Model; | ||
|
||
class Event | ||
{ | ||
/** | ||
* @var \Illuminate\Database\Eloquent\Model | ||
*/ | ||
public $like; | ||
|
||
/** | ||
* Event constructor. | ||
*/ | ||
public function __construct(Model $like) | ||
{ | ||
$this->like = $like; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Like\Events; | ||
|
||
class Liked extends Event | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Like\Events; | ||
|
||
class Unliked extends Event | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Like; | ||
|
||
use Illuminate\Database\Eloquent\Builder; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Support\Str; | ||
use Obydul\Larable\Like\Events\Liked; | ||
use Obydul\Larable\Like\Events\Unliked; | ||
|
||
class Like extends Model | ||
{ | ||
protected $guarded = []; | ||
|
||
protected $dispatchesEvents = [ | ||
'created' => Liked::class, | ||
'deleted' => Unliked::class, | ||
]; | ||
|
||
public function __construct(array $attributes = []) | ||
{ | ||
$this->table = \config('larable_like.likes_table'); | ||
|
||
parent::__construct($attributes); | ||
} | ||
|
||
protected static function boot() | ||
{ | ||
parent::boot(); | ||
|
||
self::saving(function ($like) { | ||
$userForeignKey = \config('larable_like.user_foreign_key'); | ||
$like->{$userForeignKey} = $like->{$userForeignKey} ?: auth()->id(); | ||
|
||
if (\config('larable_like.uuids')) { | ||
$like->{$like->getKeyName()} = $like->{$like->getKeyName()} ?: (string) Str::orderedUuid(); | ||
} | ||
}); | ||
} | ||
|
||
public function likeable(): \Illuminate\Database\Eloquent\Relations\MorphTo | ||
{ | ||
return $this->morphTo(); | ||
} | ||
|
||
/** | ||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo | ||
*/ | ||
public function user() | ||
{ | ||
return $this->belongsTo(\config('auth.providers.users.model'), \config('larable_like.user_foreign_key')); | ||
} | ||
|
||
/** | ||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo | ||
*/ | ||
public function liker() | ||
{ | ||
return $this->user(); | ||
} | ||
|
||
/** | ||
* @return \Illuminate\Database\Eloquent\Builder | ||
*/ | ||
public function scopeWithType(Builder $query, string $type) | ||
{ | ||
return $query->where('likeable_type', app($type)->getMorphClass()); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/Like/Migrations/2023_03_25_000000_create_likes_table.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
use Illuminate\Database\Migrations\Migration; | ||
use Illuminate\Database\Schema\Blueprint; | ||
use Illuminate\Support\Facades\Schema; | ||
|
||
class CreateLikesTable extends Migration | ||
{ | ||
/** | ||
* Run the migrations. | ||
*/ | ||
public function up() | ||
{ | ||
Schema::create(config('larable_like.likes_table', 'larable_likes'), function (Blueprint $table) { | ||
$table->bigIncrements('id'); | ||
$table->unsignedBigInteger(config('larable_like.user_foreign_key'))->index()->comment('user_id'); | ||
$table->morphs('likeable'); | ||
$table->timestamps(); | ||
}); | ||
} | ||
|
||
/** | ||
* Reverse the migrations. | ||
*/ | ||
public function down() | ||
{ | ||
Schema::dropIfExists(config('larable_like.likes_table')); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Like\Traits; | ||
|
||
use Illuminate\Database\Eloquent\Model; | ||
|
||
trait Likeable | ||
{ | ||
public function isLikedBy(Model $user): bool | ||
{ | ||
if (\is_a($user, config('auth.providers.users.model'))) { | ||
if ($this->relationLoaded('likers')) { | ||
return $this->likers->contains($user); | ||
} | ||
|
||
return $this->likers()->where(\config('larable_like.user_foreign_key'), $user->getKey())->exists(); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Return followers. | ||
*/ | ||
public function likers(): \Illuminate\Database\Eloquent\Relations\BelongsToMany | ||
{ | ||
return $this->belongsToMany( | ||
config('auth.providers.users.model'), | ||
config('larable_like.likes_table'), | ||
'likeable_id', | ||
config('larable_like.user_foreign_key') | ||
) | ||
->where('likeable_type', $this->getMorphClass()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Like\Traits; | ||
|
||
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\Support\Collection; | ||
use Illuminate\Support\LazyCollection; | ||
use Obydul\Larable\Like\Like; | ||
|
||
trait Liker | ||
{ | ||
public function like(Model $object): Like | ||
{ | ||
$attributes = [ | ||
'likeable_type' => $object->getMorphClass(), | ||
'likeable_id' => $object->getKey(), | ||
config('larable_like.user_foreign_key') => $this->getKey(), | ||
]; | ||
|
||
/* @var \Illuminate\Database\Eloquent\Model $like */ | ||
$like = \app(config('larable_like.like_model')); | ||
|
||
/* @var \Overtrue\LaravelLike\Traits\Likeable|\Illuminate\Database\Eloquent\Model $object */ | ||
return $like->where($attributes)->firstOr( | ||
function () use ($like, $attributes) { | ||
return $like->unguarded(function () use ($like, $attributes) { | ||
if ($this->relationLoaded('likes')) { | ||
$this->unsetRelation('likes'); | ||
} | ||
|
||
return $like->create($attributes); | ||
}); | ||
} | ||
); | ||
} | ||
|
||
/** | ||
* @throws \Exception | ||
*/ | ||
public function unlike(Model $object): bool | ||
{ | ||
/* @var \Overtrue\LaravelLike\Like $relation */ | ||
$relation = \app(config('larable_like.like_model')) | ||
->where('likeable_id', $object->getKey()) | ||
->where('likeable_type', $object->getMorphClass()) | ||
->where(config('larable_like.user_foreign_key'), $this->getKey()) | ||
->first(); | ||
|
||
if ($relation) { | ||
if ($this->relationLoaded('likes')) { | ||
$this->unsetRelation('likes'); | ||
} | ||
|
||
return $relation->delete(); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* @return Like|null | ||
* | ||
* @throws \Exception | ||
*/ | ||
public function toggleLike(Model $object) | ||
{ | ||
return $this->hasLiked($object) ? $this->unlike($object) : $this->like($object); | ||
} | ||
|
||
public function hasLiked(Model $object): bool | ||
{ | ||
return ($this->relationLoaded('likes') ? $this->likes : $this->likes()) | ||
->where('likeable_id', $object->getKey()) | ||
->where('likeable_type', $object->getMorphClass()) | ||
->count() > 0; | ||
} | ||
|
||
public function likes(): HasMany | ||
{ | ||
return $this->hasMany(config('larable_like.like_model'), config('larable_like.user_foreign_key'), $this->getKeyName()); | ||
} | ||
|
||
/** | ||
* Get Query Builder for likes | ||
* | ||
* @return \Illuminate\Database\Eloquent\Builder | ||
*/ | ||
public function getLikedItems(string $model) | ||
{ | ||
return app($model)->whereHas( | ||
'likers', | ||
function ($q) { | ||
return $q->where(config('larable_like.user_foreign_key'), $this->getKey()); | ||
} | ||
); | ||
} | ||
|
||
public function attachLikeStatus(&$likeables, callable $resolver = null) | ||
{ | ||
$likes = $this->likes()->get()->keyBy(function ($item) { | ||
return \sprintf('%s:%s', $item->likeable_type, $item->likeable_id); | ||
}); | ||
|
||
$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', $likes->has($key)); | ||
} | ||
|
||
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.'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
return [ | ||
/** | ||
* Use uuid as primary key. | ||
*/ | ||
'uuids' => false, | ||
|
||
/* | ||
* User tables foreign key name. | ||
*/ | ||
'user_foreign_key' => 'user_id', | ||
|
||
/* | ||
* Table name for likes records. | ||
*/ | ||
'likes_table' => 'larable_likes', | ||
|
||
/* | ||
* Model name for like record. | ||
*/ | ||
'like_model' => \Obydul\Larable\Like\Like::class, | ||
]; |