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]; }); } }