-
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.
added overtrue/laravel-favorite package
- Loading branch information
1 parent
a1be948
commit 00627e4
Showing
10 changed files
with
315 additions
and
5 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Favorite\Events; | ||
|
||
use Illuminate\Database\Eloquent\Model; | ||
|
||
class Event | ||
{ | ||
public Model $favorite; | ||
|
||
public function __construct(Model $favorite) | ||
{ | ||
$this->favorite = $favorite; | ||
} | ||
} |
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\Favorite\Events; | ||
|
||
class Favorited 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\Favorite\Events; | ||
|
||
class Unfavorited 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,65 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Favorite; | ||
|
||
use Illuminate\Database\Eloquent\Builder; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Support\Str; | ||
use Obydul\Larable\Favorite\Events\Favorited; | ||
use Obydul\Larable\Favorite\Events\Unfavorited; | ||
|
||
/** | ||
* @property \Illuminate\Database\Eloquent\Model $user | ||
* @property \Illuminate\Database\Eloquent\Model $favoriter | ||
* @property \Illuminate\Database\Eloquent\Model $favoriteable | ||
*/ | ||
class Favorite extends Model | ||
{ | ||
protected $guarded = []; | ||
|
||
protected $dispatchesEvents = [ | ||
'created' => Favorited::class, | ||
'deleted' => Unfavorited::class, | ||
]; | ||
|
||
public function __construct(array $attributes = []) | ||
{ | ||
$this->table = \config('larable_favorite.favorites_table'); | ||
|
||
parent::__construct($attributes); | ||
} | ||
|
||
protected static function boot() | ||
{ | ||
parent::boot(); | ||
|
||
self::saving(function ($favorite) { | ||
$userForeignKey = \config('larable_favorite.user_foreign_key'); | ||
$favorite->{$userForeignKey} = $favorite->{$userForeignKey} ?: auth()->id(); | ||
|
||
if (\config('larable_favorite.uuids')) { | ||
$favorite->{$favorite->getKeyName()} = $favorite->{$favorite->getKeyName()} ?: (string) Str::orderedUuid(); | ||
} | ||
}); | ||
} | ||
|
||
public function favoriteable(): \Illuminate\Database\Eloquent\Relations\MorphTo | ||
{ | ||
return $this->morphTo(); | ||
} | ||
|
||
public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo | ||
{ | ||
return $this->belongsTo(\config('auth.providers.users.model'), \config('larable_favorite.user_foreign_key')); | ||
} | ||
|
||
public function favoriter(): \Illuminate\Database\Eloquent\Relations\BelongsTo | ||
{ | ||
return $this->user(); | ||
} | ||
|
||
public function scopeWithType(Builder $query, string $type): Builder | ||
{ | ||
return $query->where('favoriteable_type', app($type)->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,55 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Favorite\Traits; | ||
|
||
use Illuminate\Database\Eloquent\Model; | ||
|
||
/** | ||
* @property \Illuminate\Database\Eloquent\Collection $favoriters | ||
* @property \Illuminate\Database\Eloquent\Collection $favorites | ||
*/ | ||
trait Favoriteable | ||
{ | ||
/** | ||
* @deprecated renamed to `hasBeenFavoritedBy`, will be removed at 5.0 | ||
*/ | ||
public function isFavoritedBy(Model $user) | ||
{ | ||
return $this->hasBeenFavoritedBy($user); | ||
} | ||
|
||
public function hasFavoriter(Model $user): bool | ||
{ | ||
return $this->hasBeenFavoritedBy($user); | ||
} | ||
|
||
public function hasBeenFavoritedBy(Model $user): bool | ||
{ | ||
if (\is_a($user, config('auth.providers.users.model'))) { | ||
if ($this->relationLoaded('favoriters')) { | ||
return $this->favoriters->contains($user); | ||
} | ||
|
||
return ($this->relationLoaded('favorites') ? $this->favorites : $this->favorites()) | ||
->where(\config('larable_favorite.user_foreign_key'), $user->getKey())->count() > 0; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public function favorites(): \Illuminate\Database\Eloquent\Relations\MorphMany | ||
{ | ||
return $this->morphMany(config('larable_favorite.favorite_model'), 'favoriteable'); | ||
} | ||
|
||
public function favoriters(): \Illuminate\Database\Eloquent\Relations\BelongsToMany | ||
{ | ||
return $this->belongsToMany( | ||
config('auth.providers.users.model'), | ||
config('larable_favorite.favorites_table'), | ||
'favoriteable_id', | ||
config('larable_favorite.user_foreign_key') | ||
) | ||
->where('favoriteable_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,107 @@ | ||
<?php | ||
|
||
namespace Obydul\Larable\Favorite\Traits; | ||
|
||
use Illuminate\Contracts\Pagination\Paginator; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Pagination\AbstractCursorPaginator; | ||
use Illuminate\Pagination\AbstractPaginator; | ||
use Illuminate\Support\Collection; | ||
use Illuminate\Support\LazyCollection; | ||
|
||
/** | ||
* @property \Illuminate\Database\Eloquent\Collection $favorites | ||
*/ | ||
trait Favoriter | ||
{ | ||
public function favorite(Model $object): void | ||
{ | ||
/* @var \Overtrue\LaravelFavorite\Traits\Favoriteable|Model $object */ | ||
if (! $this->hasFavorited($object)) { | ||
$favorite = app(config('larable_favorite.favorite_model')); | ||
$favorite->{config('larable_favorite.user_foreign_key')} = $this->getKey(); | ||
|
||
$object->favorites()->save($favorite); | ||
} | ||
} | ||
|
||
public function unfavorite(Model $object): void | ||
{ | ||
/* @var \Overtrue\LaravelFavorite\Traits\Favoriteable $object */ | ||
$relation = $object->favorites() | ||
->where('favoriteable_id', $object->getKey()) | ||
->where('favoriteable_type', $object->getMorphClass()) | ||
->where(config('larable_favorite.user_foreign_key'), $this->getKey()) | ||
->first(); | ||
|
||
if ($relation) { | ||
$relation->delete(); | ||
} | ||
} | ||
|
||
public function toggleFavorite(Model $object): void | ||
{ | ||
$this->hasFavorited($object) ? $this->unfavorite($object) : $this->favorite($object); | ||
} | ||
|
||
public function hasFavorited(Model $object): bool | ||
{ | ||
return ($this->relationLoaded('favorites') ? $this->favorites : $this->favorites()) | ||
->where('favoriteable_id', $object->getKey()) | ||
->where('favoriteable_type', $object->getMorphClass()) | ||
->count() > 0; | ||
} | ||
|
||
public function favorites(): \Illuminate\Database\Eloquent\Relations\HasMany | ||
{ | ||
return $this->hasMany(config('larable_favorite.favorite_model'), config('larable_favorite.user_foreign_key'), $this->getKeyName()); | ||
} | ||
|
||
public function attachFavoriteStatus(&$favoriteables, callable $resolver = null) | ||
{ | ||
$favorites = $this->favorites()->get()->keyBy(function ($item) { | ||
return \sprintf('%s-%s', $item->favoriteable_type, $item->favoriteable_id); | ||
}); | ||
|
||
$attachStatus = function ($favoriteable) use ($favorites, $resolver) { | ||
$resolver = $resolver ?? fn ($m) => $m; | ||
$favoriteable = $resolver($favoriteable); | ||
|
||
if (\in_array(Favoriteable::class, \class_uses($favoriteable))) { | ||
$key = \sprintf('%s-%s', $favoriteable->getMorphClass(), $favoriteable->getKey()); | ||
$favoriteable->setAttribute('has_favorited', $favorites->has($key)); | ||
} | ||
|
||
return $favoriteable; | ||
}; | ||
|
||
switch (true) { | ||
case $favoriteables instanceof Model: | ||
return $attachStatus($favoriteables); | ||
case $favoriteables instanceof Collection: | ||
return $favoriteables->each($attachStatus); | ||
case $favoriteables instanceof LazyCollection: | ||
return $favoriteables = $favoriteables->map($attachStatus); | ||
case $favoriteables instanceof AbstractPaginator: | ||
case $favoriteables instanceof AbstractCursorPaginator: | ||
return $favoriteables->through($attachStatus); | ||
case $favoriteables instanceof Paginator: | ||
// custom paginator will return a collection | ||
return collect($favoriteables->items())->transform($attachStatus); | ||
case \is_array($favoriteables): | ||
return \collect($favoriteables)->transform($attachStatus); | ||
default: | ||
throw new \InvalidArgumentException('Invalid argument type.'); | ||
} | ||
} | ||
|
||
public function getFavoriteItems(string $model) | ||
{ | ||
return app($model)->whereHas( | ||
'favoriters', | ||
function ($q) { | ||
return $q->where(config('larable_favorite.user_foreign_key'), $this->getKey()); | ||
} | ||
); | ||
} | ||
} |
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 favorites records. | ||
*/ | ||
'favorites_table' => 'larable_favorites', | ||
|
||
/* | ||
* Model name for favorite record. | ||
*/ | ||
'favorite_model' => Obydul\Larable\Favorite\Favorite::class, | ||
]; |
29 changes: 29 additions & 0 deletions
29
src/Favorite/migrations/2023_03_25_000000_create_favorites_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; | ||
|
||
return new class extends Migration | ||
{ | ||
/** | ||
* Run the migrations. | ||
*/ | ||
public function up() | ||
{ | ||
Schema::create(config('larable_favorite.favorites_table', 'larable_favorites'), function (Blueprint $table) { | ||
$table->id(); | ||
$table->unsignedBigInteger(config('larable_favorite.user_foreign_key'))->index()->comment('user_id'); | ||
$table->morphs('favoriteable'); | ||
$table->timestamps(); | ||
}); | ||
} | ||
|
||
/** | ||
* Reverse the migrations. | ||
*/ | ||
public function down() | ||
{ | ||
Schema::dropIfExists(config('larable_favorite.favorites_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