KTV/app/Services/SqliteExportService.php

107 lines
3.4 KiB
PHP

<?php
namespace App\Services;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
class SqliteExportService
{
protected string $connection;
public function __construct(string $connection)
{
$this->connection = $connection;
}
/**
* 匯出單一模型資料到 SQLite 表。
*
* @param class-string<Model> $modelClass
* @param string $tableName
* @param Closure(Blueprint): void $tableSchema
* @param Closure(Model): array $transformer
* @param int $chunkSize
*/
public function exportTableFromModel(
string $modelClass,
string $tableName,
Closure $tableSchema,
Closure $transformer,
int $chunkSize = 1000
): void {
$this->dropAndCreateTable($tableName, $tableSchema);
$modelInstance = new $modelClass;
$modelInstance->newQuery()->orderBy('id')->chunk($chunkSize, function (Collection $chunk) use ($tableName, $transformer) {
$rows = $chunk->map($transformer)->toArray();
$this->insertData($tableName, $rows);
});
$this->purge();
}
/**
* 批次匯出多張表
*
* @param array<string, array{
* modelClass?: class-string<Model>,
* query?: Closure(): \Illuminate\Support\Collection,
* tableSchema: Closure(Blueprint): void,
* transformer: Closure(Model): array,
* chunkSize?: int
* }> $tables
*/
public function exportMultiple(array $tables): void
{
foreach ($tables as $tableName => $config) {
$this->dropAndCreateTable($tableName, $config['tableSchema']);
$transformer = $config['transformer'] ?? fn($row) => (array)$row;
if (isset($config['modelClass'])) {
$modelClass = $config['modelClass'];
$chunkSize = $config['chunkSize'] ?? 1000;
$modelInstance = new $modelClass;
$modelInstance->newQuery()->chunk($chunkSize, function (Collection $chunk) use ($tableName, $transformer) {
$rows = $chunk->map($transformer)->toArray();
$this->insertData($tableName, $rows);
});
} elseif (isset($config['query']) && is_callable($config['query'])) {
$rows = call_user_func($config['query']);
if ($rows instanceof \Illuminate\Database\Query\Builder || $rows instanceof \Illuminate\Database\Eloquent\Builder) {
$rows = $rows->get();
}
$data = $rows->map($transformer)->toArray();
$this->insertData($tableName, $data);
} else {
throw new \InvalidArgumentException("Each table config must define either 'modelClass' or 'query'.");
}
}
$this->purge();
}
protected function dropAndCreateTable(string $table, Closure $schema): void
{
Schema::connection($this->connection)->dropIfExists($table);
Schema::connection($this->connection)->create($table, $schema);
}
protected function insertData(string $table, array $rows): void
{
if (empty($rows)) return;
DB::connection($this->connection)->table($table)->insert($rows);
}
protected function purge(): void
{
DB::purge($this->connection);
}
}