107 lines
3.4 KiB
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);
|
|
}
|
|
|
|
} |