mirror of
https://github.com/nullthoughts/laravel-data-sync.git
synced 2026-02-27 19:58:13 +00:00
Support for ordered sync/importing
- Order specified in config - Tests for ordered sync - New ErrorUpdatingModelException specifies which Model the error was thrown on
This commit is contained in:
@@ -2,4 +2,7 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'path' => base_path('sync'),
|
'path' => base_path('sync'),
|
||||||
|
'order' => [
|
||||||
|
//
|
||||||
|
]
|
||||||
];
|
];
|
||||||
|
|||||||
14
readme.md
14
readme.md
@@ -6,7 +6,7 @@ Laravel utility to keep records synced between enviroments through source contro
|
|||||||
- Create a JSON file for each model, using the model name as the filename. Example: Product.json would update the Product model
|
- Create a JSON file for each model, using the model name as the filename. Example: Product.json would update the Product model
|
||||||
- Use nested arrays in place of hardcoded IDs for relationships
|
- Use nested arrays in place of hardcoded IDs for relationships
|
||||||
- Run `php artisan vendor:publish --provider="distinctm\LaravelDataSync\DataSyncBaseServiceProvider" --tag="data-sync-config"` to publish config file. Specify directory for sync data files (default is a new sync directory in the project root)
|
- Run `php artisan vendor:publish --provider="distinctm\LaravelDataSync\DataSyncBaseServiceProvider" --tag="data-sync-config"` to publish config file. Specify directory for sync data files (default is a new sync directory in the project root)
|
||||||
- Run `php artisan data:sync`
|
- Run `php artisan data:sync` (or `php artisan data:sync --model={model}` with the model flag to specify a model)
|
||||||
|
|
||||||
### Optional
|
### Optional
|
||||||
If using Laravel Forge, you can have the data sync run automatically on deploy. Edit your deploy script in Site -> App to include:
|
If using Laravel Forge, you can have the data sync run automatically on deploy. Edit your deploy script in Site -> App to include:
|
||||||
@@ -21,8 +21,18 @@ fi
|
|||||||
## Notes
|
## Notes
|
||||||
- use studly case for model name relationships as JSON keys (example: 'option_group' => 'OptionGroup'). This is important for case sensitive file systems.
|
- use studly case for model name relationships as JSON keys (example: 'option_group' => 'OptionGroup'). This is important for case sensitive file systems.
|
||||||
- empty values are skipped
|
- empty values are skipped
|
||||||
- the criteria/attributes for updateOrCreate are identified with a preleading underscore
|
- the criteria/attributes for updateOrCreate are identified with a leading underscore
|
||||||
- nested values represent relationships and are returned using where($key, $value)->first()->id
|
- nested values represent relationships and are returned using where($key, $value)->first()->id
|
||||||
|
- order of import can be set in _config/data-sync.php_ with an array:
|
||||||
|
```
|
||||||
|
return [
|
||||||
|
'path' => base_path('sync'),
|
||||||
|
'order' => [
|
||||||
|
'Role',
|
||||||
|
'Supervisor',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
### User.json:
|
### User.json:
|
||||||
|
|||||||
16
src/Exceptions/ErrorUpdatingModelException.php
Normal file
16
src/Exceptions/ErrorUpdatingModelException.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace distinctm\LaravelDataSync\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ErrorUpdatingModelException extends Exception
|
||||||
|
{
|
||||||
|
public function __construct(string $message = "", int $code = 0, Throwable $previous = null)
|
||||||
|
{
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
|
||||||
|
$this->message = "Error updating the {$message} model.";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ use distinctm\LaravelDataSync\Exceptions\NoCriteriaException;
|
|||||||
use distinctm\LaravelDataSync\Exceptions\NoRecordsInvalidJSONException;
|
use distinctm\LaravelDataSync\Exceptions\NoRecordsInvalidJSONException;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
|
use distinctm\LaravelDataSync\Exceptions\ErrorUpdatingModelException;
|
||||||
|
|
||||||
class Updater
|
class Updater
|
||||||
{
|
{
|
||||||
@@ -31,11 +32,17 @@ class Updater
|
|||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$records = collect($this->files)->map(function ($file) {
|
$files = $this->sortModels($this->files);
|
||||||
return $this->syncModel($file);
|
|
||||||
});
|
|
||||||
|
|
||||||
return $records;
|
return $files->map(function ($file) {
|
||||||
|
try {
|
||||||
|
return $this->syncModel($file);
|
||||||
|
} catch (\ErrorException $e) {
|
||||||
|
$model = pathinfo($file, PATHINFO_FILENAME);
|
||||||
|
|
||||||
|
throw new ErrorUpdatingModelException(ucwords($model));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,7 +78,7 @@ class Updater
|
|||||||
*
|
*
|
||||||
* @param $path
|
* @param $path
|
||||||
*
|
*
|
||||||
* @return array
|
* @return string
|
||||||
* @throws \distinctm\LaravelDataSync\Exceptions\FileDirectoryNotFoundException
|
* @throws \distinctm\LaravelDataSync\Exceptions\FileDirectoryNotFoundException
|
||||||
*/
|
*/
|
||||||
protected function getDirectory($path)
|
protected function getDirectory($path)
|
||||||
@@ -91,17 +98,41 @@ class Updater
|
|||||||
* @param string $directory
|
* @param string $directory
|
||||||
* @param string|null $model
|
* @param string|null $model
|
||||||
*
|
*
|
||||||
* @return array|string
|
* @return \Illuminate\Support\Collection
|
||||||
*/
|
*/
|
||||||
protected function getFiles(string $directory, $model)
|
protected function getFiles(string $directory, $model = null)
|
||||||
{
|
{
|
||||||
if ($model) {
|
if ($model) {
|
||||||
return $directory . '/' . $model . '.json';
|
return Collection::wrap($directory . '/' . $model . '.json');
|
||||||
}
|
}
|
||||||
|
|
||||||
return collect(File::files($directory))->map(function ($path) {
|
return collect(File::files($directory))->map(function ($path) {
|
||||||
return $path->getPathname();
|
return $path->getPathname();
|
||||||
})->toArray();
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort Models by pre-configured order
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Support\Collection $files
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
protected function sortModels(\Illuminate\Support\Collection $files)
|
||||||
|
{
|
||||||
|
if(empty(config('data-sync.order'))) {
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files->sortBy(function($file) use ($files) {
|
||||||
|
$filename = pathinfo($file, PATHINFO_FILENAME);
|
||||||
|
|
||||||
|
$order = array_search(
|
||||||
|
studly_case($filename),
|
||||||
|
config('data-sync.order')
|
||||||
|
);
|
||||||
|
|
||||||
|
return $order !== false ? $order : (count($files) + 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +140,7 @@ class Updater
|
|||||||
*
|
*
|
||||||
* @param object $record
|
* @param object $record
|
||||||
*
|
*
|
||||||
* @return array
|
* @return \Illuminate\Support\Collection
|
||||||
* @throws \distinctm\LaravelDataSync\Exceptions\NoCriteriaException
|
* @throws \distinctm\LaravelDataSync\Exceptions\NoCriteriaException
|
||||||
*/
|
*/
|
||||||
protected function getCriteria(object $record)
|
protected function getCriteria(object $record)
|
||||||
@@ -132,7 +163,7 @@ class Updater
|
|||||||
*
|
*
|
||||||
* @param object $record
|
* @param object $record
|
||||||
*
|
*
|
||||||
* @return array
|
* @return \Illuminate\Support\Collection
|
||||||
*/
|
*/
|
||||||
protected function getValues(object $record)
|
protected function getValues(object $record)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace distinctm\LaravelDataSync\Tests;
|
|||||||
|
|
||||||
use distinctm\LaravelDataSync\Tests\Fakes\UpdaterFake;
|
use distinctm\LaravelDataSync\Tests\Fakes\UpdaterFake;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use distinctm\LaravelDataSync\Exceptions\ErrorUpdatingModelException;
|
||||||
|
|
||||||
class UpdaterTest extends TestCase
|
class UpdaterTest extends TestCase
|
||||||
{
|
{
|
||||||
@@ -86,7 +87,6 @@ class UpdaterTest extends TestCase
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->assertContains('No records or invalid JSON for', $e->getMessage());
|
$this->assertContains('No records or invalid JSON for', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
@@ -101,6 +101,34 @@ class UpdaterTest extends TestCase
|
|||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->assertEquals('No criteria/attributes detected', $e->getMessage());
|
$this->assertEquals('No criteria/attributes detected', $e->getMessage());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function order_of_imports_can_be_defined_in_config()
|
||||||
|
{
|
||||||
|
config()->set('data-sync.order', [
|
||||||
|
'Supervisor',
|
||||||
|
'Roles'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$updater = new UpdaterFake(__DIR__ . '/../test-data/ordered');
|
||||||
|
$updater->run();
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('roles', ['slug' => 'update-student-records']);
|
||||||
|
$this->assertDatabaseHas('supervisors', ['name' => 'CEO']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function exception_is_thrown_if_imports_are_in_incorrect_order()
|
||||||
|
{
|
||||||
|
config()->set('data-sync.order', [
|
||||||
|
'Roles',
|
||||||
|
'Supervisor'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->expectException(ErrorUpdatingModelException::class);
|
||||||
|
|
||||||
|
$updater = new UpdaterFake(__DIR__ . '/../test-data/ordered');
|
||||||
|
$updater->run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
9
tests/test-data/ordered/roles.json
Normal file
9
tests/test-data/ordered/roles.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"_slug": "update-student-records",
|
||||||
|
"category": "testing",
|
||||||
|
"supervisor": {
|
||||||
|
"name": "CEO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
5
tests/test-data/ordered/supervisor.json
Normal file
5
tests/test-data/ordered/supervisor.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"_name": "CEO"
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user