. */ namespace App\Commands; use App\Contracts\Favouritable; use App\Models\Album; use App\Models\Favourite; use App\Models\Playlist; use App\Models\ResourceUser; use App\Models\Track; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Notification; class ToggleFavouriteCommand extends CommandBase { private $_resourceType; private $_resourceId; public function __construct($resourceType, $resourceId) { $this->_resourceId = $resourceId; $this->_resourceType = $resourceType; } /** * @return bool */ public function authorize() { $user = Auth::user(); return $user != null; } private function getEntityBeingFavourited():Favouritable { switch ($this->_resourceType) { case 'track': return Track::find($this->_resourceId); case 'album': return Album::find($this->_resourceId); case 'playlist': return Playlist::find($this->_resourceId); default: throw new \InvalidArgumentException('Unknown resource type given!'); } } /** * @throws \Exception * @return CommandResponse */ public function execute() { $typeId = $this->_resourceType.'_id'; $existing = Favourite::where($typeId, '=', $this->_resourceId)->whereUserId(Auth::user()->id)->first(); $isFavourited = false; if ($existing) { $existing->delete(); } else { $fav = new Favourite(); $fav->$typeId = $this->_resourceId; $fav->user_id = Auth::user()->id; $fav->save(); $isFavourited = true; Notification::newFavourite($this->getEntityBeingFavourited(), $fav->user); } $resourceUser = ResourceUser::get(Auth::user()->id, $this->_resourceType, $this->_resourceId); $resourceUser->is_favourited = $isFavourited; $resourceUser->save(); $resourceTable = $this->_resourceType.'s'; // We do this to prevent a race condition. Sure I could simply increment the count columns and re-save back to the db // but that would require an additional SELECT and the operation would be non-atomic. If two log items are created // for the same resource at the same time, the cached values will still be correct with this method. DB::table($resourceTable)->whereId($this->_resourceId)->update([ 'favourite_count' => DB::raw('( SELECT COUNT(id) FROM favourites WHERE '. $typeId.' = '.$this->_resourceId.')'), ]); return CommandResponse::succeed(['is_favourited' => $isFavourited]); } }