From e1229ef4460d5f796c7af88253105a9820340da3 Mon Sep 17 00:00:00 2001 From: Abrar Ahmad Date: Wed, 28 Sep 2022 13:38:01 +0500 Subject: [PATCH] allow defining a mix of attribute names and default values --- src/Listeners/UpdateSyncedResource.php | 24 +++++++++++- tests/ResourceSyncingTest.php | 54 ++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/Listeners/UpdateSyncedResource.php b/src/Listeners/UpdateSyncedResource.php index f95c1fd3..155465b0 100644 --- a/src/Listeners/UpdateSyncedResource.php +++ b/src/Listeners/UpdateSyncedResource.php @@ -129,12 +129,32 @@ class UpdateSyncedResource extends QueueableListener } if (Arr::isAssoc($model->getSyncedCreationAttributes())) { - // Developer provided the default values + // Developer provided the default values (key => value) or mix of default values and attribute names (values only) // We will merge the default values with sync attributes - return array_merge($model->getSyncedCreationAttributes(), $model->only($model->getSyncedAttributeNames())); + [$attributes, $defaultValues] = $this->getAttributeNamesAndDefaultValues($model); + + return array_merge($defaultValues, $model->only(array_merge($model->getSyncedAttributeNames(), $attributes))); } // Developer provided the attribute names, so we'd use them to pick model attributes return $model->only($model->getSyncedCreationAttributes()); } + + /** + * Split the attribute names (sequential index items) and default values (key => values). + */ + protected function getAttributeNamesAndDefaultValues(Syncable $model): array + { + $syncedCreationAttributes = $model->getSyncedCreationAttributes(); + + $attributes = Arr::where($syncedCreationAttributes, function ($value, $key) { + return is_numeric($key); + }); + + $defaultValues = Arr::where($syncedCreationAttributes, function ($value, $key) { + return is_string($key); + }); + + return [$attributes, $defaultValues]; + } } diff --git a/tests/ResourceSyncingTest.php b/tests/ResourceSyncingTest.php index d748b9db..e495f95a 100644 --- a/tests/ResourceSyncingTest.php +++ b/tests/ResourceSyncingTest.php @@ -224,12 +224,12 @@ test('creating the resource in tenant database creates it in central database wi tenancy()->initialize($tenant); // Create the user in tenant DB - ResourceUserWithAttributeNames::create([ + ResourceUserWithAttributeNamesAndDefaultValues::create([ 'global_id' => 'acme', 'name' => 'John Doe', 'email' => 'john@localhost', 'password' => 'secret', - 'role' => 'commenter', + 'role' => 'commenter', // this will not be synced because we are providing default value 'code' => 'bar' // extra column which does not exist in central users table ]); @@ -242,7 +242,7 @@ test('creating the resource in tenant database creates it in central database wi expect(CentralUser::first()->password)->toBe('secret'); expect(CentralUser::first()->code)->toBeNull(); expect(CentralUser::first()->role)->toBe('admin'); // unsynced so it should be default value -})->skip('mixing attribute names and values is not possible with current implementation'); +}) ; test('creating the resource in central database creates it in tenant database as 1:1 copy when creation attributes are not specified', function () { $centralUser = CentralUser::create([ @@ -340,6 +340,36 @@ test('creating the resource in central database creates it in tenant database wi }); }); +test('creating the resource in central database creates it in tenant database with a mix of attributes names and default values', function () { + $centralUser = CentralUserWithAttributeNamesAndDefaultValues::create([ + 'global_id' => 'acme', + 'name' => 'John Doe', + 'email' => 'john@localhost', + 'password' => 'secret', + 'role' => 'commenter', // this will not be synced because we are providing default value + ]); + + $tenant = ResourceTenant::create([ + 'id' => 't1', + ]); + migrateTenantsResource(); + + $tenant->run(function () { + expect(ResourceUser::all())->toHaveCount(0); + }); + + $centralUser->tenants()->attach('t1'); + + $tenant->run(function () { + expect(ResourceUser::all())->toHaveCount(1); + expect(ResourceUser::first()->global_id)->toBe('acme'); + expect(CentralUser::first()->name)->toBe('John Doe'); + expect(CentralUser::first()->email)->toBe('john@localhost'); + expect(CentralUser::first()->password)->toBe('secret'); + expect(ResourceUser::first()->role)->toBe('admin'); // default value + }); +}); + test('creating the resource in tenant database creates it in central database and creates the mapping', function () { creatingResourceInTenantDatabaseCreatesAndMapInCentralDatabase(); }); @@ -882,7 +912,7 @@ class ResourceUserWithAttributeNames extends ResourceUser { } -// override method in ResourceUser class to return attribute names + default values +// override method in ResourceUser class to return attribute names and default values class ResourceUserWithAttributeNamesAndDefaultValues extends ResourceUser { public function getSyncedCreationAttributes(): array { @@ -927,4 +957,20 @@ class CentralUserWithAttributeNames extends CentralUser { } } +// override method in CentralUser class to return attribute names and default values +class CentralUserWithAttributeNamesAndDefaultValues extends CentralUser { + public function getSyncedCreationAttributes(): array + { + // Sync name, email and password but provide default value for role + return + [ + 'global_id', + 'name', + 'password', + 'email', + 'role' => 'admin', + ]; + } +} +