mirror of
https://github.com/koel/koel
synced 2024-11-24 13:13:05 +00:00
Use a service for Interaction
This commit is contained in:
parent
181357f3de
commit
1d5c8e84b6
7 changed files with 225 additions and 97 deletions
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Controllers\API\Interaction;
|
||||
|
||||
use App\Http\Requests\API\BatchInteractionRequest;
|
||||
use App\Models\Interaction;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class BatchLikeController extends Controller
|
||||
|
@ -17,7 +16,9 @@ class BatchLikeController extends Controller
|
|||
*/
|
||||
public function store(BatchInteractionRequest $request)
|
||||
{
|
||||
return response()->json(Interaction::batchLike((array) $request->songs, $request->user()));
|
||||
$interactions = $this->interactionService->batchLike((array) $request->songs, $request->user());
|
||||
|
||||
return response()->json($interactions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,6 +30,8 @@ class BatchLikeController extends Controller
|
|||
*/
|
||||
public function destroy(BatchInteractionRequest $request)
|
||||
{
|
||||
return response()->json(Interaction::batchUnlike((array) $request->songs, $request->user()));
|
||||
$this->interactionService->batchUnlike((array) $request->songs, $request->user());
|
||||
|
||||
return response()->json();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,14 @@
|
|||
namespace App\Http\Controllers\API\Interaction;
|
||||
|
||||
use App\Http\Controllers\Controller as BaseController;
|
||||
use App\Services\InteractionService;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
protected $interactionService;
|
||||
|
||||
public function __construct(InteractionService $interactionService)
|
||||
{
|
||||
$this->interactionService = $interactionService;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Http\Controllers\API\Interaction;
|
||||
|
||||
use App\Http\Requests\API\SongLikeRequest;
|
||||
use App\Models\Interaction;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class LikeController extends Controller
|
||||
|
@ -17,6 +16,6 @@ class LikeController extends Controller
|
|||
*/
|
||||
public function store(SongLikeRequest $request)
|
||||
{
|
||||
return response()->json(Interaction::toggleLike($request->song, $request->user()));
|
||||
return response()->json($this->interactionService->toggleLike($request->song, $request->user()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Http\Controllers\API\Interaction;
|
|||
|
||||
use App\Events\SongStartedPlaying;
|
||||
use App\Http\Requests\API\Interaction\StorePlayCountRequest;
|
||||
use App\Models\Interaction;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class PlayCountController extends Controller
|
||||
|
@ -18,7 +17,8 @@ class PlayCountController extends Controller
|
|||
*/
|
||||
public function store(StorePlayCountRequest $request)
|
||||
{
|
||||
$interaction = Interaction::increasePlayCount($request->song, $request->user());
|
||||
$interaction = $this->interactionService->increasePlayCount($request->song, $request->user());
|
||||
|
||||
if ($interaction) {
|
||||
event(new SongStartedPlaying($interaction->song, $interaction->user));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Events\SongLikeToggled;
|
||||
use App\Traits\CanFilterByUser;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
@ -46,93 +45,4 @@ class Interaction extends Model
|
|||
{
|
||||
return $this->belongsTo(Song::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the number of times a song is played by a user.
|
||||
*
|
||||
* @param string $songId
|
||||
* @param User $user
|
||||
*
|
||||
* @return Interaction
|
||||
*/
|
||||
public static function increasePlayCount($songId, User $user)
|
||||
{
|
||||
return tap(self::firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), function (Interaction $interaction) {
|
||||
if (!$interaction->exists) {
|
||||
$interaction->liked = false;
|
||||
}
|
||||
|
||||
$interaction->play_count++;
|
||||
$interaction->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Like or unlike a song on behalf of a user.
|
||||
*
|
||||
* @param string $songId
|
||||
* @param User $user
|
||||
*
|
||||
* @return Interaction
|
||||
*/
|
||||
public static function toggleLike($songId, User $user)
|
||||
{
|
||||
return tap(self::firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), function (Interaction $interaction) {
|
||||
$interaction->liked = !$interaction->liked;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Like several songs at once.
|
||||
*
|
||||
* @param array $songIds
|
||||
* @param User $user
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function batchLike(array $songIds, User $user)
|
||||
{
|
||||
return collect($songIds)->map(function ($songId) use ($user) {
|
||||
return tap(self::firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), function (Interaction $interaction) {
|
||||
if (!$interaction->exists) {
|
||||
$interaction->play_count = 0;
|
||||
}
|
||||
|
||||
$interaction->liked = true;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
});
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike several songs at once.
|
||||
*
|
||||
* @param array $songIds
|
||||
* @param User $user
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function batchUnlike(array $songIds, User $user)
|
||||
{
|
||||
self::whereIn('song_id', $songIds)->whereUserId($user->id)->get()->each(function (Interaction $interaction) {
|
||||
$interaction->liked = false;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
109
app/Services/InteractionService.php
Normal file
109
app/Services/InteractionService.php
Normal file
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Events\SongLikeToggled;
|
||||
use App\Models\Interaction;
|
||||
use App\Models\User;
|
||||
|
||||
class InteractionService
|
||||
{
|
||||
private $interaction;
|
||||
|
||||
public function __construct(Interaction $interaction)
|
||||
{
|
||||
$this->interaction = $interaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the number of times a song is played by a user.
|
||||
*
|
||||
* @param string $songId
|
||||
* @param User $user
|
||||
*
|
||||
* @return Interaction The affected Interaction object
|
||||
*/
|
||||
public function increasePlayCount($songId, User $user)
|
||||
{
|
||||
return tap($this->interaction->firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), static function (Interaction $interaction) {
|
||||
if (!$interaction->exists) {
|
||||
$interaction->liked = false;
|
||||
}
|
||||
|
||||
$interaction->play_count++;
|
||||
$interaction->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Like or unlike a song on behalf of a user.
|
||||
*
|
||||
* @param string $songId
|
||||
* @param User $user
|
||||
*
|
||||
* @return Interaction The affected Interaction object.
|
||||
*/
|
||||
public function toggleLike($songId, User $user)
|
||||
{
|
||||
return tap($this->interaction->firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), static function (Interaction $interaction) {
|
||||
$interaction->liked = !$interaction->liked;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Like several songs at once as a user.
|
||||
*
|
||||
* @param array $songIds
|
||||
* @param User $user
|
||||
*
|
||||
* @return array The array of Interaction objects.
|
||||
*/
|
||||
public function batchLike(array $songIds, User $user)
|
||||
{
|
||||
return collect($songIds)->map(function ($songId) use ($user) {
|
||||
return tap($this->interaction->firstOrCreate([
|
||||
'song_id' => $songId,
|
||||
'user_id' => $user->id,
|
||||
]), static function (Interaction $interaction) {
|
||||
if (!$interaction->exists) {
|
||||
$interaction->play_count = 0;
|
||||
}
|
||||
|
||||
$interaction->liked = true;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
});
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike several songs at once.
|
||||
*
|
||||
* @param array $songIds
|
||||
* @param User $user
|
||||
*/
|
||||
public function batchUnlike(array $songIds, User $user)
|
||||
{
|
||||
$this->interaction
|
||||
->whereIn('song_id', $songIds)
|
||||
->where('user_id', $user->id)
|
||||
->get()
|
||||
->each(static function (Interaction $interaction) {
|
||||
$interaction->liked = false;
|
||||
$interaction->save();
|
||||
|
||||
event(new SongLikeToggled($interaction));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
100
tests/Integration/Services/InteractionServiceTest.php
Normal file
100
tests/Integration/Services/InteractionServiceTest.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
namespace Tests\Integration\Services;
|
||||
|
||||
use App\Events\SongLikeToggled;
|
||||
use App\Models\Interaction;
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\InteractionService;
|
||||
use Exception;
|
||||
use Illuminate\Support\Collection;
|
||||
use Tests\TestCase;
|
||||
|
||||
class InteractionServiceTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var InteractionService
|
||||
*/
|
||||
private $interactionService;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->interactionService = new InteractionService(new Interaction());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_increases_a_songs_play_count()
|
||||
{
|
||||
/** @var Interaction $interaction */
|
||||
$interaction = factory(Interaction::class)->create();
|
||||
|
||||
$this->interactionService->increasePlayCount($interaction->song, $interaction->user);
|
||||
|
||||
/** @var Interaction $interaction */
|
||||
$updatedInteraction = Interaction::find($interaction->id);
|
||||
self::assertEquals($interaction->play_count + 1, $updatedInteraction->play_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function it_toggles_like_status()
|
||||
{
|
||||
$this->expectsEvents(SongLikeToggled::class);
|
||||
|
||||
$interaction = factory(Interaction::class)->create();
|
||||
|
||||
$this->interactionService->toggleLike($interaction->song, $interaction->user);
|
||||
|
||||
/** @var Interaction $interaction */
|
||||
$updatedInteraction = Interaction::find($interaction->id);
|
||||
self::assertNotSame($interaction->liked, $updatedInteraction->liked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function user_can_like_multiple_songs_at_once()
|
||||
{
|
||||
$this->expectsEvents(SongLikeToggled::class);
|
||||
|
||||
/** @var Collection $songs */
|
||||
$songs = factory(Song::class, 2)->create();
|
||||
$user = factory(User::class)->create();
|
||||
|
||||
$this->interactionService->batchLike($songs->pluck('id')->all(), $user);
|
||||
|
||||
$songs->each(static function (Song $song) use ($user) {
|
||||
self::assertTrue(Interaction::whereSongIdAndUserId($song->id, $user->id)->first()->liked);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function user_can_unlike_multiple_songs_at_once()
|
||||
{
|
||||
$this->expectsEvents(SongLikeToggled::class);
|
||||
|
||||
$user = factory(User::class)->create();
|
||||
/** @var Collection $interactions */
|
||||
$interactions = factory(Interaction::class, 3)->create([
|
||||
'user_id' => $user->id,
|
||||
'liked' => true,
|
||||
]);
|
||||
|
||||
$this->interactionService->batchUnlike($interactions->pluck('song.id')->all(), $user);
|
||||
|
||||
$interactions->each(static function (Interaction $interaction) {
|
||||
self::assertFalse(Interaction::find($interaction->id)->liked);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue