ldc-gen-game-web/app/Jobs/ProcessUniqueCode.php
2025-08-29 14:46:51 +02:00

136 lines
4 KiB
PHP

<?php
namespace App\Jobs;
use App\Mail\Jobs\CodeGenerationSucceed;
use App\Mail\Jobs\JobFailed;
use App\Models\Code;
use App\Models\Settings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
class ProcessUniqueCode implements ShouldQueue, ShouldBeUnique
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
/**
* The number of seconds the job can run before timing out.
*
* 7200 seconds (2 hours)
*
* @var integer
*/
public $timeout = 7200;
/**
* Setting of the current model.
*
* @var \App\Models\Settings|null $settingModel
*/
protected $settingModel = null;
/**
* Create a new job instance.
*
* @param integer $amount Amount of code to generate.
* @param integer $length Length of each code to generate.
* @param Settings $settings Setting of the current tenant.
* @return void
*/
public function __construct(protected int $amount, protected int $length, protected Settings $settings)
{
$this->settingModel = $settings;
}
/**
* Execute the job.
*
* @return void
*/
public function handle(): void
{
DB::transaction(function () {
// ! Le premier code commence à 1
$last_id = (Code::query()->max('id') ?? 0) + 1;
$maxSQLPlaceholders = 65535;
$insertColumns = collect(DB::getSchemaBuilder()
->getColumnListing((new Code())->getTable()))
->filter(function ($name) {
// * Ignorer les colonnes avec valeurs par défaut sur la table.
return !in_array($name, ['id', 'code_exported']);
})->count() + 1;
/** @var integer $perPage Nombre d'insertions max sur un seule requète. */
$perPage = \floor($maxSQLPlaceholders / $insertColumns);
/** @var integer $totalPages Nombre de page totale à insérer. */
$totalPages = \ceil($this->amount / $perPage);
$totalGeneratedInserts = 0;
for ($currentPage = 1; $currentPage <= $totalPages; $currentPage++) {
$inserts = [];
$insertToGenerate = min($perPage, $this->amount - $totalGeneratedInserts);
do {
$inserts[] = [
'id' => $last_id++,
'tenant_id' => $this->settingModel->tenant_id,
'date_creation' => now()->format('Y-m-d'),
];
} while (($totalGeneratedInserts < $this->amount) && --$insertToGenerate);
// * Mass insert
Code::query()->insert($inserts);
$totalGeneratedInserts += count($inserts);
}
// * Fin de la génération.
Mail::to(config('mail.admin'))->send(new CodeGenerationSucceed(
$this->amount,
$this->settingModel->name,
));
});
}
/**
* In case of job failure.
*
* @param \Throwable $exception
* @return void
*/
public function failed(\Throwable $exception): void
{
Mail::to(config('mail.admin'))->send(
new JobFailed(__CLASS__, [
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString()
])
);
}
/**
* Get the middleware the job should pass through.
*
* @return array<int, object>
*/
public function middleware(): array
{
return [
(new WithoutOverlapping('code_generation'))
->releaseAfter(60)
];
}
}