mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-09-03 11:15:04 +02:00
166 lines
5.1 KiB
PHP
166 lines
5.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Actions\Repositories;
|
|
|
|
use App\Contracts\Repositories\RepositoryInterface;
|
|
use Closure;
|
|
use Exception;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
/**
|
|
* Class ReconcileRepositories.
|
|
*
|
|
* @template TModel of \App\Models\BaseModel
|
|
*/
|
|
abstract class ReconcileRepositoriesAction
|
|
{
|
|
/**
|
|
* Perform set reconciliation between source and destination repositories.
|
|
*
|
|
* @param RepositoryInterface<TModel> $source
|
|
* @param RepositoryInterface<TModel> $destination
|
|
* @return ReconcileResults
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
public function reconcileRepositories(RepositoryInterface $source, RepositoryInterface $destination): ReconcileResults
|
|
{
|
|
try {
|
|
DB::beginTransaction();
|
|
|
|
$sourceModels = $source->get();
|
|
|
|
$destinationModels = $destination->get($this->columnsForCreateDelete());
|
|
|
|
$created = $this->createModelsFromSource($destination, $sourceModels, $destinationModels);
|
|
|
|
$deleted = $this->deleteModelsFromDestination($destination, $sourceModels, $destinationModels);
|
|
|
|
$destinationModels = $destination->get($this->columnsForUpdate());
|
|
|
|
$updated = $this->updateDestinationModels($destination, $sourceModels, $destinationModels);
|
|
|
|
DB::commit();
|
|
|
|
return $this->getResults($created, $deleted, $updated);
|
|
} catch (Exception $e) {
|
|
Log::error($e->getMessage());
|
|
|
|
DB::rollBack();
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The columns used for create and delete set operations.
|
|
*
|
|
* @return string[]
|
|
*/
|
|
abstract protected function columnsForCreateDelete(): array;
|
|
|
|
/**
|
|
* Callback for create and delete set operation item comparison.
|
|
*
|
|
* @return Closure
|
|
*/
|
|
abstract protected function diffCallbackForCreateDelete(): Closure;
|
|
|
|
/**
|
|
* Create models that exist in source but not in destination.
|
|
*
|
|
* @param RepositoryInterface<TModel> $destination
|
|
* @param Collection $sourceModels
|
|
* @param Collection $destinationModels
|
|
* @return Collection
|
|
*/
|
|
protected function createModelsFromSource(
|
|
RepositoryInterface $destination,
|
|
Collection $sourceModels,
|
|
Collection $destinationModels
|
|
): Collection {
|
|
$createModels = $sourceModels->diffUsing($destinationModels, $this->diffCallbackForCreateDelete());
|
|
|
|
return $createModels->each(fn (Model $createModel) => $destination->save($createModel));
|
|
}
|
|
|
|
/**
|
|
* Delete models that exist in destination but not in source.
|
|
*
|
|
* @param RepositoryInterface<TModel> $destination
|
|
* @param Collection $sourceModels
|
|
* @param Collection $destinationModels
|
|
* @return Collection
|
|
*/
|
|
protected function deleteModelsFromDestination(
|
|
RepositoryInterface $destination,
|
|
Collection $sourceModels,
|
|
Collection $destinationModels
|
|
): Collection {
|
|
$deleteModels = $destinationModels->diffUsing($sourceModels, $this->diffCallbackForCreateDelete());
|
|
|
|
return $deleteModels->each(fn (Model $deleteModel) => $destination->delete($deleteModel));
|
|
}
|
|
|
|
/**
|
|
* The columns used for update set operation.
|
|
*
|
|
* @return string[]
|
|
*/
|
|
abstract protected function columnsForUpdate(): array;
|
|
|
|
/**
|
|
* Callback for update set operation item comparison.
|
|
*
|
|
* @return Closure
|
|
*/
|
|
abstract protected function diffCallbackForUpdate(): Closure;
|
|
|
|
/**
|
|
* Get source model that has been updated for destination model.
|
|
*
|
|
* @param Collection $sourceModels
|
|
* @param Model $destinationModel
|
|
* @return Model|null
|
|
*/
|
|
abstract protected function resolveUpdatedModel(Collection $sourceModels, Model $destinationModel): ?Model;
|
|
|
|
/**
|
|
* Update destination models that have changed in source.
|
|
*
|
|
* @param RepositoryInterface<TModel> $destination
|
|
* @param Collection $sourceModels
|
|
* @param Collection $destinationModels
|
|
* @return Collection
|
|
*/
|
|
protected function updateDestinationModels(
|
|
RepositoryInterface $destination,
|
|
Collection $sourceModels,
|
|
Collection $destinationModels
|
|
): Collection {
|
|
$updatedModels = $destinationModels->diffUsing($sourceModels, $this->diffCallbackForUpdate());
|
|
|
|
return $updatedModels->each(function (Model $updatedModel) use ($sourceModels, $destination) {
|
|
$sourceModel = $this->resolveUpdatedModel($sourceModels, $updatedModel);
|
|
if ($sourceModel !== null) {
|
|
$destination->update($updatedModel, $sourceModel->toArray());
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get reconciliation results.
|
|
*
|
|
* @param Collection $created
|
|
* @param Collection $deleted
|
|
* @param Collection $updated
|
|
* @return ReconcileResults
|
|
*/
|
|
abstract protected function getResults(Collection $created, Collection $deleted, Collection $updated): ReconcileResults;
|
|
}
|