2022-08-01 10:42:33 +00:00
|
|
|
<?php
|
|
|
|
|
2024-02-23 18:36:02 +00:00
|
|
|
namespace App\Models\Concerns;
|
2022-08-01 10:42:33 +00:00
|
|
|
|
2024-05-19 05:49:42 +00:00
|
|
|
use Closure;
|
2022-08-01 10:42:33 +00:00
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* With reference to GitHub issue #463.
|
|
|
|
* MySQL and PostgresSQL seem to have a limit of 2^16-1 (65535) elements in an IN statement.
|
|
|
|
* This trait provides a method as a workaround to this limitation.
|
|
|
|
*
|
2022-08-09 18:45:11 +00:00
|
|
|
* @method static Builder query()
|
2022-08-01 10:42:33 +00:00
|
|
|
*/
|
|
|
|
trait SupportsDeleteWhereValueNotIn
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Deletes all records whose certain value is not in an array.
|
|
|
|
*/
|
2024-05-19 05:49:42 +00:00
|
|
|
public static function deleteWhereValueNotIn(
|
|
|
|
array $values,
|
|
|
|
?string $field = null,
|
|
|
|
?Closure $queryModifier = null
|
|
|
|
): void {
|
2023-08-20 11:03:29 +00:00
|
|
|
$field ??= (new static())->getKeyName();
|
2024-05-19 05:49:42 +00:00
|
|
|
$queryModifier ??= static fn (Builder $builder) => $builder;
|
2023-08-20 11:03:29 +00:00
|
|
|
|
|
|
|
$maxChunkSize = DB::getDriverName() === 'sqlite' ? 999 : 65_535;
|
2022-08-01 10:42:33 +00:00
|
|
|
|
|
|
|
if (count($values) <= $maxChunkSize) {
|
2024-05-19 05:49:42 +00:00
|
|
|
$queryModifier(static::query())->whereNotIn($field, $values)->delete();
|
2022-08-01 10:42:33 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-10 06:57:20 +00:00
|
|
|
$allIds = static::query()->select($field)->get()->pluck($field)->all();
|
|
|
|
$deletableIds = array_diff($allIds, $values);
|
2022-08-01 10:42:33 +00:00
|
|
|
|
2022-08-10 06:57:20 +00:00
|
|
|
if (count($deletableIds) < $maxChunkSize) {
|
2024-05-19 05:49:42 +00:00
|
|
|
$queryModifier(static::query())->whereIn($field, $deletableIds)->delete();
|
2022-08-01 10:42:33 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-20 11:03:29 +00:00
|
|
|
static::deleteByChunk($deletableIds, $maxChunkSize, $field);
|
2022-08-01 10:42:33 +00:00
|
|
|
}
|
|
|
|
|
2023-08-20 11:03:29 +00:00
|
|
|
public static function deleteByChunk(array $values, int $chunkSize = 65_535, ?string $field = null): void
|
2022-08-01 10:42:33 +00:00
|
|
|
{
|
2023-08-20 11:03:29 +00:00
|
|
|
$field ??= (new static())->getKeyName();
|
|
|
|
|
2022-08-01 10:42:33 +00:00
|
|
|
DB::transaction(static function () use ($values, $field, $chunkSize): void {
|
|
|
|
foreach (array_chunk($values, $chunkSize) as $chunk) {
|
2022-08-09 18:45:11 +00:00
|
|
|
static::query()->whereIn($field, $chunk)->delete();
|
2022-08-01 10:42:33 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|