186 lines
6.1 KiB
PHP
186 lines
6.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Bo;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\InstantWin;
|
|
use App\Models\Prize;
|
|
use App\Models\Settings;
|
|
use Carbon\Carbon;
|
|
use Carbon\CarbonInterface;
|
|
use Carbon\CarbonInterval;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
use stdClass;
|
|
|
|
class InstantWinController extends Controller
|
|
{
|
|
/**
|
|
* Create the controller instance.
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->authorizeResource(InstantWin::class);
|
|
}
|
|
|
|
/**
|
|
* Display a listing of the resource.
|
|
*/
|
|
public function index(): View
|
|
{
|
|
$instantWinModelList = InstantWin::query()->oldest('available_at')->get();
|
|
|
|
/** @var view-string $view */
|
|
$view = 'back::pages.instant-win.index';
|
|
|
|
return view($view, [
|
|
'instantWinModelList' => $instantWinModelList,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Returns generated instant win.
|
|
*/
|
|
public function generate(): JsonResponse
|
|
{
|
|
$this->authorize('generate', InstantWin::class);
|
|
|
|
return DB::transaction(function () {
|
|
/**
|
|
* À partir de quelle heure on peut gagner
|
|
* ! Seul l'heure sera prize en compte
|
|
*/
|
|
$day_start = now()->setTime(6, 0);
|
|
/**
|
|
* Jusqu'à quelle heure on peut gagner
|
|
* ! Seul l'heure sera prize en compte
|
|
*/
|
|
$day_end = now()->setTime(22, 29);
|
|
|
|
/** @var Settings */
|
|
$settings = resolve(Settings::class);
|
|
$prizeModelList = Prize::all();
|
|
|
|
/** @var Collection<array-key, WinDayCalendar> */
|
|
$datesGlobal = collect();
|
|
/** @var Collection<array-key, WinTimeElement> Liste de tous les lots à gagner */
|
|
$lotsGlobal = collect();
|
|
|
|
// * Seed srand !
|
|
\mt_srand(time());
|
|
|
|
// * Init prize list
|
|
$prizeModelList->each(function (Prize $prize) use ($lotsGlobal, $day_start, $day_end): void {
|
|
for ($i = 0; $i < $prize->quantity; $i++) {
|
|
$el = new WinTimeElement();
|
|
$el->prize = $prize;
|
|
$el->time = now()->setTime(
|
|
mt_rand($day_start->hour, $day_end->hour),
|
|
mt_rand($day_start->minute, $day_end->minute)
|
|
);
|
|
$lotsGlobal->push($el);
|
|
}
|
|
});
|
|
|
|
$lotsGlobal->shuffle();
|
|
|
|
// * Init days calendar
|
|
foreach ($settings->start_date->toPeriod($settings->end_date, CarbonInterval::make('1day')) as $date) {
|
|
$el = new WinDayCalendar();
|
|
$el->lots = collect();
|
|
$el->time = $date->setTime(0, 0);
|
|
$datesGlobal->push($el);
|
|
}
|
|
|
|
// * Save Instant wins
|
|
$this->generateArray($lotsGlobal, $datesGlobal, 0)->each(function (WinDayCalendar $winDayCalendar): void {
|
|
$winDayCalendar->lots->each(function (WinTimeElement $winTimeElement): void {
|
|
$instantWin = new InstantWin();
|
|
$instantWin->available_at = $winTimeElement->time;
|
|
$instantWin->prize()->associate($winTimeElement->prize);
|
|
$instantWin->saveOrFail();
|
|
});
|
|
});
|
|
|
|
// * Output instant wins to ajax response
|
|
return response()->json(InstantWin::all());
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate instant win.
|
|
*
|
|
* Même algo que celui implémenté par Romain.
|
|
*
|
|
* @param Collection<array-key, WinTimeElement> $lotsGlobal
|
|
* Liste de tous les lots à gagner
|
|
* @param Collection<array-key, WinDayCalendar> $dateGlobal
|
|
* @return Collection<array-key, WinDayCalendar>
|
|
*
|
|
* @phpcs:disable Squiz.Commenting.FunctionComment.IncorrectTypeHint
|
|
*/
|
|
private function generateArray(Collection $lotsGlobal, Collection $dateGlobal, int $prizesDone): Collection
|
|
{
|
|
// phpcs:enable
|
|
/** @var array-key Un jour sélectionné aléatoire. */
|
|
$rKey = $dateGlobal->keys()->random(1)->firstOrFail();
|
|
|
|
// ? À-t-on déjà assigné un lot par jour (au moins) ?
|
|
// ? Le jour aléatoire sélectionné à déja un lot ?
|
|
if ($prizesDone < $dateGlobal->count() && $dateGlobal->get($rKey)->lots->count() > 0) {
|
|
return $this->generateArray($lotsGlobal, $dateGlobal, $prizesDone);
|
|
}
|
|
|
|
// * Insert next prize on a randowm day
|
|
$dateGlobal->get($rKey)->lots->push($lotsGlobal->get($prizesDone++));
|
|
|
|
// ? On a distribué assez de lots ?
|
|
if ($prizesDone < $lotsGlobal->count()) {
|
|
return $this->generateArray($lotsGlobal, $dateGlobal, $prizesDone);
|
|
}
|
|
|
|
// * Tri par heure et assignation du jour correct.
|
|
$dateGlobal->each(function (WinDayCalendar $date): void {
|
|
$date->lots = $date->lots->sort(fn (WinTimeElement $a, WinTimeElement $b): int | float => $a->time->timestamp - $b->time->timestamp)
|
|
->map(function (WinTimeElement $time) use ($date): WinTimeElement {
|
|
$time->time->setDate(
|
|
$date->time->year,
|
|
$date->time->month,
|
|
$date->time->day
|
|
);
|
|
|
|
return $time;
|
|
});
|
|
});
|
|
|
|
return $dateGlobal;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @property Prize $prize Le lot à gagner.
|
|
* @property Carbon $time Une heure aléatoire.
|
|
*
|
|
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
|
|
*/
|
|
class WinTimeElement extends stdClass
|
|
{
|
|
// phpcs:enable
|
|
}
|
|
|
|
/**
|
|
* @property Carbon|CarbonInterface $time
|
|
* Un jour dans le temps.
|
|
* @property Collection<array-key, WinTimeElement> $lots
|
|
* Liste des lots tombant ce jour.
|
|
*
|
|
* @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
|
|
*/
|
|
class WinDayCalendar extends stdClass
|
|
{
|
|
// phpcs:enable
|
|
}
|