Skip to content

Commit

Permalink
added overtrue/laravel-favorite package
Browse files Browse the repository at this point in the history
  • Loading branch information
mdobydullah committed Mar 25, 2023
1 parent a1be948 commit 00627e4
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 5 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ php artisan vendor:publish --provider="Obydul\\Larable\\LarableServiceProvider"

The available morphable packages/features.

| Service Name | Feature/Package | Description |
|--------------|-----------------------------------------------------------------------------|-------------------------------------|
| Like | [overtrue/laravel-like](https://github.com/overtrue/laravel-like) | User like feature feature. |
| Follow | [overtrue/laravel-follow](https://github.com/overtrue/laravel-follow) | User follow unfollow feature . |
| Subscribe | [overtrue/laravel-subscribe](https://github.com/overtrue/laravel-subscribe) | User subscribe unsubscribe feature. |
| Service Name | Feature/Package | Description |
|--------------|---------------------------------------------------------------------------|-------------------------------------|
| Like | [laravel-like:v5.1.1](https://github.com/overtrue/laravel-like) | User like feature feature. |
| Follow | [laravel-follow:v5.1.0](https://github.com/overtrue/laravel-follow) | User follow unfollow feature . |
| Subscribe | [laravel-subscribe:v4.2.0](https://github.com/overtrue/laravel-subscribe) | User subscribe unsubscribe feature. |
| Favorite | [laravel-favorite:v5.1.0](https://github.com/overtrue/laravel-favorite) | User favorite unfavorite feature. |

## Cleanup Unused Services

Expand Down
15 changes: 15 additions & 0 deletions src/Favorite/Events/Event.php
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;
}
}
7 changes: 7 additions & 0 deletions src/Favorite/Events/Favorited.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Obydul\Larable\Favorite\Events;

class Favorited extends Event
{
}
7 changes: 7 additions & 0 deletions src/Favorite/Events/Unfavorited.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Obydul\Larable\Favorite\Events;

class Unfavorited extends Event
{
}
65 changes: 65 additions & 0 deletions src/Favorite/Favorite.php
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());
}
}
55 changes: 55 additions & 0 deletions src/Favorite/Traits/Favoriteable.php
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());
}
}
107 changes: 107 additions & 0 deletions src/Favorite/Traits/Favoriter.php
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());
}
);
}
}
23 changes: 23 additions & 0 deletions src/Favorite/config.php
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,
];
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'));
}
};
1 change: 1 addition & 0 deletions src/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public function services(): array
'Like',
'Follow',
'Subscribe',
'Favorite',
];

// read root composer.json
Expand Down

0 comments on commit 00627e4

Please sign in to comment.