mirror of
https://github.com/nullthoughts/laravel-data-sync.git
synced 2026-01-26 11:44:11 +00:00
212 lines
4.8 KiB
PHP
212 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace distinctm\LaravelDataSync;
|
|
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class Updater
|
|
{
|
|
|
|
/**
|
|
* Get files in sync directory
|
|
*
|
|
* @param string|null $path
|
|
*/
|
|
public function __construct($path = null)
|
|
{
|
|
|
|
$this->files = $this->getFiles(
|
|
$this->getDirectory($path)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Execute syncModel for each file
|
|
*
|
|
* @return void
|
|
*/
|
|
public function run()
|
|
{
|
|
$records = collect($this->files)->map(function($file) {
|
|
return $this->syncModel($file);
|
|
});
|
|
|
|
return $records;
|
|
}
|
|
|
|
/**
|
|
* Parse each record for criteria/values and update/create model
|
|
*
|
|
* @param string $file
|
|
* @return \Illuminate\Support\Collection
|
|
*/
|
|
protected function syncModel(string $file)
|
|
{
|
|
$model = $this->getModel($file);
|
|
$records = $this->getRecords($file);
|
|
|
|
$records->each(function($record) use ($model) {
|
|
$record = $this->resolveObjects($record);
|
|
|
|
$criteria = $this->getCriteria($record);
|
|
$values = $this->getValues($record);
|
|
|
|
$model::updateOrCreate($criteria, $values);
|
|
});
|
|
|
|
return $records;
|
|
}
|
|
|
|
/**
|
|
* Get directory path for sync files
|
|
*
|
|
* @param object $record
|
|
* @return array
|
|
*/
|
|
protected function getDirectory($path)
|
|
{
|
|
$directory = $path ?? config('data-sync.path', base_path('sync'));
|
|
|
|
if(!file_exists($directory)) {
|
|
throw new \Exception("Specified sync file directory does not exist");
|
|
}
|
|
|
|
return $directory;
|
|
}
|
|
|
|
/**
|
|
* Get list of files in directory
|
|
*
|
|
* @param string $directory
|
|
* @return void
|
|
*/
|
|
protected function getFiles(string $directory)
|
|
{
|
|
return collect(File::files($directory))->map(function($path) {
|
|
return $path->getPathname();
|
|
})->toArray();
|
|
}
|
|
|
|
/**
|
|
* Filter record criteria
|
|
*
|
|
* @param \Illuminate\Support\Collection $record
|
|
* @return array
|
|
*/
|
|
protected function getCriteria(\Illuminate\Support\Collection $record)
|
|
{
|
|
$criteria = $record->filter(function($value, $key) {
|
|
return $this->isCriteria($key);
|
|
});
|
|
|
|
if($criteria->count() == 0) {
|
|
throw new \Exception("No criteria/attributes detected");
|
|
}
|
|
|
|
return $criteria->mapWithKeys(function($value, $key) {
|
|
return [substr($key, 1) => $value];
|
|
})->toArray();
|
|
}
|
|
|
|
/**
|
|
* Filter record values
|
|
*
|
|
* @param \Illuminate\Support\Collection $record
|
|
* @return array
|
|
*/
|
|
protected function getValues(\Illuminate\Support\Collection $record)
|
|
{
|
|
return $record->reject(function($value, $key) {
|
|
if($this->isCriteria($key)) {
|
|
return true;
|
|
}
|
|
|
|
if(empty($value)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
})->toArray();
|
|
}
|
|
|
|
/**
|
|
* Returns model name for file
|
|
*
|
|
* @param string $file
|
|
* @return string
|
|
*/
|
|
protected function getModel(string $name)
|
|
{
|
|
return '\\App\\' . pathinfo($name, PATHINFO_FILENAME);
|
|
}
|
|
|
|
/**
|
|
* Parses JSON from file and returns collection
|
|
*
|
|
* @param string $file
|
|
* @return \Illuminate\Support\Collection
|
|
*/
|
|
protected function getRecords(string $file)
|
|
{
|
|
$records = collect(json_decode(File::get($file)));
|
|
|
|
if($records->isEmpty()) {
|
|
throw new \Exception("No records or invalid JSON for {$file} model");
|
|
}
|
|
|
|
return $records;
|
|
}
|
|
|
|
/**
|
|
* Check if column is criteria for a condition match
|
|
*
|
|
* @param string $key
|
|
* @return boolean
|
|
*/
|
|
protected function isCriteria($key)
|
|
{
|
|
return substr($key, 0, 1) == '_';
|
|
}
|
|
|
|
/**
|
|
* Return ID for nested key-value pairs
|
|
*
|
|
* @param string $key
|
|
* @param object $values
|
|
* @return array
|
|
*/
|
|
protected function resolveId(string $key, object $values)
|
|
{
|
|
$model = $this->getModel($key);
|
|
|
|
$values = collect($values)->mapWithKeys(function($value, $column) {
|
|
if(is_object($value)) {
|
|
return $this->resolveId($column, $value);
|
|
}
|
|
|
|
return [$column => $value];
|
|
})->toArray();
|
|
|
|
return [$key . '_id' => $model::where($values)->first()->id];
|
|
}
|
|
|
|
/**
|
|
* Detect nested objects and resolve them
|
|
*
|
|
* @param object $records
|
|
* @return \Illuminate\Support\Collection
|
|
*/
|
|
protected function resolveObjects(object $record)
|
|
{
|
|
return collect($record)->mapWithKeys(function($value, $key) {
|
|
if(is_object($value)) {
|
|
return $this->resolveId($key, $value);
|
|
}
|
|
|
|
return [$key => $value];
|
|
});
|
|
}
|
|
|
|
}
|