diff --git a/modules/features_ui/src/Form/AssignmentBaseForm.php b/modules/features_ui/src/Form/AssignmentBaseForm.php index 673aee0..c8d4f6b 100644 --- a/modules/features_ui/src/Form/AssignmentBaseForm.php +++ b/modules/features_ui/src/Form/AssignmentBaseForm.php @@ -28,7 +28,7 @@ class AssignmentBaseForm extends AssignmentFormBase { */ public function buildForm(array $form, FormStateInterface $form_state, $bundle_name = NULL) { $this->currentBundle = $this->assigner->loadBundle($bundle_name); - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); // Pass the last argument to limit the select to config entity types that // provide bundles for other entity types. @@ -55,7 +55,7 @@ class AssignmentBaseForm extends AssignmentFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state) { // Merge in types selections. - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $settings['types'] = $form_state->getValue('types'); $this->currentBundle->setAssignmentSettings(self::METHOD_ID, $settings)->save(); $this->setRedirect($form_state); diff --git a/modules/features_ui/src/Form/AssignmentCoreForm.php b/modules/features_ui/src/Form/AssignmentCoreForm.php index dbd0a98..a094e4f 100644 --- a/modules/features_ui/src/Form/AssignmentCoreForm.php +++ b/modules/features_ui/src/Form/AssignmentCoreForm.php @@ -28,7 +28,7 @@ class AssignmentCoreForm extends AssignmentFormBase { */ public function buildForm(array $form, FormStateInterface $form_state, $bundle_name = NULL) { $this->currentBundle = $this->assigner->loadBundle($bundle_name); - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $this->setConfigTypeSelect($form, $settings['types']['config'], $this->t('core')); $this->setActions($form); @@ -48,7 +48,7 @@ class AssignmentCoreForm extends AssignmentFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state) { // Merge in types selections. - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $settings['types'] = $form_state->getValue('types'); $this->currentBundle->setAssignmentSettings(self::METHOD_ID, $settings)->save(); $this->setRedirect($form_state); diff --git a/modules/features_ui/src/Form/AssignmentExcludeForm.php b/modules/features_ui/src/Form/AssignmentExcludeForm.php index 0831342..f29c2dd 100644 --- a/modules/features_ui/src/Form/AssignmentExcludeForm.php +++ b/modules/features_ui/src/Form/AssignmentExcludeForm.php @@ -29,7 +29,7 @@ class AssignmentExcludeForm extends AssignmentFormBase { public function buildForm(array $form, FormStateInterface $form_state, $bundle_name = NULL) { $this->currentBundle = $this->assigner->loadBundle($bundle_name); - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $this->setConfigTypeSelect($form, $settings['types']['config'], $this->t('exclude')); $module_settings = $settings['module']; @@ -98,7 +98,7 @@ class AssignmentExcludeForm extends AssignmentFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state) { // Merge in selections. - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $settings = array_merge($settings, [ 'types' => $form_state->getValue('types'), 'curated' => $form_state->getValue('curated'), diff --git a/modules/features_ui/src/Form/AssignmentOptionalForm.php b/modules/features_ui/src/Form/AssignmentOptionalForm.php index 94dba35..4a73c38 100644 --- a/modules/features_ui/src/Form/AssignmentOptionalForm.php +++ b/modules/features_ui/src/Form/AssignmentOptionalForm.php @@ -28,7 +28,7 @@ class AssignmentOptionalForm extends AssignmentFormBase { */ public function buildForm(array $form, FormStateInterface $form_state, $bundle_name = NULL) { $this->currentBundle = $this->assigner->loadBundle($bundle_name); - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $this->setConfigTypeSelect($form, $settings['types']['config'], $this->t('optional')); $this->setActions($form); @@ -48,7 +48,7 @@ class AssignmentOptionalForm extends AssignmentFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state) { // Merge in types selections. - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $settings['types'] = $form_state->getValue('types'); $this->currentBundle->setAssignmentSettings(self::METHOD_ID, $settings)->save(); $this->setRedirect($form_state); diff --git a/modules/features_ui/src/Form/AssignmentProfileForm.php b/modules/features_ui/src/Form/AssignmentProfileForm.php index 06db212..f576f55 100644 --- a/modules/features_ui/src/Form/AssignmentProfileForm.php +++ b/modules/features_ui/src/Form/AssignmentProfileForm.php @@ -28,7 +28,7 @@ class AssignmentProfileForm extends AssignmentFormBase { */ public function buildForm(array $form, FormStateInterface $form_state, $bundle_name = NULL) { $this->currentBundle = $this->assigner->loadBundle($bundle_name); - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $this->setConfigTypeSelect($form, $settings['types']['config'], $this->t('profile')); @@ -76,7 +76,7 @@ class AssignmentProfileForm extends AssignmentFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state) { // Merge in selections. - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $settings = array_merge($settings, [ 'curated' => $form_state->getValue('curated'), diff --git a/modules/features_ui/src/Form/AssignmentSiteForm.php b/modules/features_ui/src/Form/AssignmentSiteForm.php index 71a4266..46b3e02 100644 --- a/modules/features_ui/src/Form/AssignmentSiteForm.php +++ b/modules/features_ui/src/Form/AssignmentSiteForm.php @@ -28,7 +28,7 @@ class AssignmentSiteForm extends AssignmentFormBase { */ public function buildForm(array $form, FormStateInterface $form_state, $bundle_name = NULL) { $this->currentBundle = $this->assigner->loadBundle($bundle_name); - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $this->setConfigTypeSelect($form, $settings['types']['config'], $this->t('site')); $this->setActions($form); @@ -48,7 +48,7 @@ class AssignmentSiteForm extends AssignmentFormBase { */ public function submitForm(array &$form, FormStateInterface $form_state) { // Merge in types selections. - $settings = $this->currentBundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID, $this->currentBundle); $settings['types'] = $form_state->getValue('types'); $this->currentBundle->setAssignmentSettings(self::METHOD_ID, $settings)->save(); $this->setRedirect($form_state); diff --git a/src/FeaturesAssigner.php b/src/FeaturesAssigner.php index 45ad5ab..d494916 100644 --- a/src/FeaturesAssigner.php +++ b/src/FeaturesAssigner.php @@ -414,4 +414,17 @@ class FeaturesAssigner implements FeaturesAssignerInterface { } } + /** + * {@inheritdoc} + */ + public function getAssignmentSettings($method_id, $bundle = NULL) { + if (empty($bundle)) { + $bundle = $this->getBundle(); + } + $settings = $bundle->getAssignmentSettings($method_id); + $settings += $this->getAssignmentMethodInstance($method_id)->defaultSettings(); + $settings += ['enabled' => FALSE, 'weight' => 999]; + return $settings; + } + } diff --git a/src/FeaturesAssignerInterface.php b/src/FeaturesAssignerInterface.php index 950f2a8..db5be8d 100644 --- a/src/FeaturesAssignerInterface.php +++ b/src/FeaturesAssignerInterface.php @@ -230,4 +230,17 @@ interface FeaturesAssignerInterface { */ public function loadBundle($machine_name = NULL); + /** + * Get the settings for an assignment method. + * + * @param string $method_id + * The string identifier of the package assignment method. + * @param \Drupal\features\FeaturesBundleInterface + * Bundle to get settings from. + * + * @return array + * The assignment method's settings. + */ + public function getAssignmentSettings($method_id, $bundle = NULL); + } diff --git a/src/FeaturesAssignmentMethodBase.php b/src/FeaturesAssignmentMethodBase.php index bf8f6c7..c5898ca 100644 --- a/src/FeaturesAssignmentMethodBase.php +++ b/src/FeaturesAssignmentMethodBase.php @@ -86,7 +86,7 @@ abstract class FeaturesAssignmentMethodBase implements FeaturesAssignmentMethodI */ protected function assignPackageByConfigTypes($method_id, $machine_name, $force = FALSE) { $current_bundle = $this->assigner->getBundle(); - $settings = $current_bundle->getAssignmentSettings($method_id); + $settings = $this->assigner->getAssignmentSettings($method_id); $types = $settings['types']['config']; $config_collection = $this->featuresManager->getConfigCollection(); @@ -114,7 +114,7 @@ abstract class FeaturesAssignmentMethodBase implements FeaturesAssignmentMethodI */ protected function assignSubdirectoryByConfigTypes($method_id, $subdirectory) { $current_bundle = $this->assigner->getBundle(); - $settings = $current_bundle->getAssignmentSettings($method_id); + $settings = $this->assigner->getAssignmentSettings($method_id); $types = $settings['types']['config']; $config_collection = $this->featuresManager->getConfigCollection(); @@ -130,4 +130,11 @@ abstract class FeaturesAssignmentMethodBase implements FeaturesAssignmentMethodI $this->featuresManager->setConfigCollection($config_collection); } + /** + * {@inheritdoc} + */ + public function defaultSettings() { + return []; + } + } diff --git a/src/FeaturesAssignmentMethodInterface.php b/src/FeaturesAssignmentMethodInterface.php index a2b90ce..0d272cd 100644 --- a/src/FeaturesAssignmentMethodInterface.php +++ b/src/FeaturesAssignmentMethodInterface.php @@ -57,4 +57,12 @@ interface FeaturesAssignmentMethodInterface { */ public function assignPackages($force = FALSE); + /** + * Get the default settings for this assignment. + * + * @return array + * The settings, not including the keys 'weight' or 'enabled'. + */ + public function defaultSettings(); + } diff --git a/src/Plugin/FeaturesAssignment/FeaturesAssignmentBaseType.php b/src/Plugin/FeaturesAssignment/FeaturesAssignmentBaseType.php index 6aae549..705f37e 100644 --- a/src/Plugin/FeaturesAssignment/FeaturesAssignmentBaseType.php +++ b/src/Plugin/FeaturesAssignment/FeaturesAssignmentBaseType.php @@ -33,7 +33,7 @@ class FeaturesAssignmentBaseType extends FeaturesAssignmentMethodBase { */ public function assignPackages($force = FALSE) { $current_bundle = $this->assigner->getBundle(); - $settings = $current_bundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID); $config_base_types = $settings['types']['config']; $config_types = $this->featuresManager->listConfigTypes(); @@ -70,4 +70,16 @@ class FeaturesAssignmentBaseType extends FeaturesAssignmentMethodBase { } } + /** + * {@inheritdoc} + */ + public function defaultSettings() { + return parent::defaultSettings() + [ + 'types' => [ + 'config' => [], + 'content' => [], + ], + ]; + } + } diff --git a/src/Plugin/FeaturesAssignment/FeaturesAssignmentCoreType.php b/src/Plugin/FeaturesAssignment/FeaturesAssignmentCoreType.php index 1239dae..bfefb85 100644 --- a/src/Plugin/FeaturesAssignment/FeaturesAssignmentCoreType.php +++ b/src/Plugin/FeaturesAssignment/FeaturesAssignmentCoreType.php @@ -40,4 +40,13 @@ class FeaturesAssignmentCoreType extends FeaturesAssignmentMethodBase { $this->assignPackageByConfigTypes(self::METHOD_ID, $machine_name, $force); } + /** + * {@inheritdoc} + */ + public function defaultSettings() { + return parent::defaultSettings() + [ + 'types' => ['config' => []], + ]; + } + } diff --git a/src/Plugin/FeaturesAssignment/FeaturesAssignmentExclude.php b/src/Plugin/FeaturesAssignment/FeaturesAssignmentExclude.php index 9790b5f..96ef3ea 100644 --- a/src/Plugin/FeaturesAssignment/FeaturesAssignmentExclude.php +++ b/src/Plugin/FeaturesAssignment/FeaturesAssignmentExclude.php @@ -32,7 +32,7 @@ class FeaturesAssignmentExclude extends FeaturesAssignmentMethodBase { */ public function assignPackages($force = FALSE) { $current_bundle = $this->assigner->getBundle(); - $settings = $current_bundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID); $config_collection = $this->featuresManager->getConfigCollection(); @@ -143,4 +143,19 @@ class FeaturesAssignmentExclude extends FeaturesAssignmentMethodBase { $this->featuresManager->setConfigCollection($config_collection); } + /** + * {@inheritdoc} + */ + public function defaultSettings() { + return parent::defaultSettings() + [ + 'curated' => FALSE, + 'module' => [ + 'installed' => FALSE, + 'profile' => FALSE, + 'namespace' => FALSE, + ], + 'types' => ['config' => []], + ]; + } + } diff --git a/src/Plugin/FeaturesAssignment/FeaturesAssignmentOptionalType.php b/src/Plugin/FeaturesAssignment/FeaturesAssignmentOptionalType.php index 9ce8f3d..5f270c3 100644 --- a/src/Plugin/FeaturesAssignment/FeaturesAssignmentOptionalType.php +++ b/src/Plugin/FeaturesAssignment/FeaturesAssignmentOptionalType.php @@ -40,4 +40,13 @@ class FeaturesAssignmentOptionalType extends FeaturesAssignmentMethodBase { $this->assignSubdirectoryByConfigTypes(self::METHOD_ID, InstallStorage::CONFIG_OPTIONAL_DIRECTORY); } + /** + * {@inheritdoc} + */ + public function defaultSettings() { + return parent::defaultSettings() + [ + 'types' => ['config' => []], + ]; + } + } diff --git a/src/Plugin/FeaturesAssignment/FeaturesAssignmentProfile.php b/src/Plugin/FeaturesAssignment/FeaturesAssignmentProfile.php index b63b72d..79017f2 100644 --- a/src/Plugin/FeaturesAssignment/FeaturesAssignmentProfile.php +++ b/src/Plugin/FeaturesAssignment/FeaturesAssignmentProfile.php @@ -35,7 +35,7 @@ class FeaturesAssignmentProfile extends FeaturesAssignmentMethodBase { $current_bundle = $this->assigner->getBundle(); if ($current_bundle->isProfile()) { - $settings = $current_bundle->getAssignmentSettings(self::METHOD_ID); + $settings = $this->assigner->getAssignmentSettings(self::METHOD_ID); // Ensure the profile package exists. $profile_name = $current_bundle->getProfileName(); @@ -177,4 +177,18 @@ class FeaturesAssignmentProfile extends FeaturesAssignmentMethodBase { ]; } + /** + * {@inheritdoc} + */ + public function defaultSettings() { + return parent::defaultSettings() + [ + 'types' => ['config' => []], + 'curated' => FALSE, + 'standard' => [ + 'files' => FALSE, + 'dependencies' => FALSE, + ], + ]; + } + } diff --git a/src/Plugin/FeaturesAssignment/FeaturesAssignmentSiteType.php b/src/Plugin/FeaturesAssignment/FeaturesAssignmentSiteType.php index ec8cdc3..58b5fc5 100644 --- a/src/Plugin/FeaturesAssignment/FeaturesAssignmentSiteType.php +++ b/src/Plugin/FeaturesAssignment/FeaturesAssignmentSiteType.php @@ -40,4 +40,13 @@ class FeaturesAssignmentSiteType extends FeaturesAssignmentMethodBase { $this->assignPackageByConfigTypes(self::METHOD_ID, $machine_name, $force); } + /** + * {@inheritdoc} + */ + public function defaultSettings() { + return parent::defaultSettings() + [ + 'types' => ['config' => []], + ]; + } + } diff --git a/src/Tests/FeaturesBundleUITest.php b/src/Tests/FeaturesBundleUITest.php new file mode 100644 index 0000000..29f1513 --- /dev/null +++ b/src/Tests/FeaturesBundleUITest.php @@ -0,0 +1,182 @@ +bundleStorage = \Drupal::entityTypeManager()->getStorage('features_bundle'); + + $admin_user = $this->createUser(['administer site configuration', 'export configuration', 'administer modules']); + $this->drupalLogin($admin_user); + $this->drupalPlaceBlock('local_actions_block'); + } + + /** + * Get the default features bundle. + * + * @return \Drupal\features\FeaturesBundleInterface + * The features bundle. + */ + protected function defaultBundle() { + return $this->bundleStorage->load('default'); + } + + /** + * Completely remove a features assignment method from the bundle. + * + * @param string $method_id + * The assignment method ID. + */ + protected function removeAssignment($method_id) { + $bundle = $this->defaultBundle(); + $assignments = $bundle->get('assignments'); + unset($assignments[$method_id]); + $bundle->set('assignments', $assignments); + $bundle->save(); + } + + /** + * Tests configuring an assignment. + */ + public function testAssignmentConfigure() { + // Check initial values. + $settings = $this->defaultBundle()->getAssignmentSettings('exclude'); + $this->assertTrue(isset($settings['types']['config']['features_bundle']), 'Excluding features_bundle'); + $this->assertFalse(isset($settings['types']['config']['system_simple']), 'Not excluding system_simple'); + $this->assertFalse(isset($settings['types']['config']['user_role']), 'Not excluding user_role'); + $this->assertTrue($settings['curated'], 'Excluding curated items'); + $this->assertTrue($settings['module']['namespace'], 'Excluding by namespace'); + + // Check initial form. + $this->drupalGet('admin/config/development/features/bundle/_exclude/default'); + $this->assertFieldChecked('edit-types-config-features-bundle', 'features_bundle is checked'); + $this->assertNoFieldChecked('edit-types-config-system-simple', 'system_simple is not checked'); + $this->assertNoFieldChecked('edit-types-config-user-role', 'user_role is not checked'); + $this->assertFieldChecked('edit-curated', 'curated is checked'); + $this->assertFieldChecked('edit-module-namespace', 'namespace is checked'); + + // Configure the form. + $this->drupalPostForm(NULL, [ + 'types[config][system_simple]' => TRUE, + 'types[config][user_role]' => FALSE, + 'curated' => TRUE, + 'module[namespace]' => FALSE, + ], $this->t('Save settings')); + + // Check form results. + $this->drupalGet('admin/config/development/features/bundle/_exclude/default'); + $this->assertFieldChecked('edit-types-config-features-bundle', 'Saved, features_bundle is checked'); + $this->assertFieldChecked('edit-types-config-system-simple', 'Saved, system_simple is checked'); + $this->assertNoFieldChecked('edit-types-config-user-role', 'Saved, user_role is not checked'); + $this->assertFieldChecked('edit-curated', 'Saved, curated is checked'); + $this->assertNoFieldChecked('edit-module-namespace', 'Saved, namespace is not checked'); + + // Check final values. + $settings = $this->defaultBundle()->getAssignmentSettings('exclude'); + $this->assertTrue(isset($settings['types']['config']['features_bundle']), 'Saved, excluding features_bundle'); + $this->assertTrue(isset($settings['types']['config']['system_simple']), 'Saved, excluding system_simple'); + $this->assertFalse(isset($settings['types']['config']['user_role']), 'Saved, not excluding user_role'); + $this->assertTrue($settings['curated'], 'Saved, excluding curated items'); + $this->assertFalse($settings['module']['namespace'], 'Saved, not excluding by namespace'); + } + + /** + * Tests configuring an assignment that didn't exist before. + */ + public function testNewAssignmentConfigure() { + $this->removeAssignment('exclude'); + + // Is the method really removed? + $settings = $this->defaultBundle()->getAssignmentSettings('exclude'); + $this->assertIdentical($settings, [], 'No exclude assignment'); + + // Can we visit the config page with no settings? + $this->drupalGet('admin/config/development/features/bundle/_exclude/default'); + $this->assertNoFieldChecked('edit-types-config-features-bundle', 'features_bundle is not checked'); + $this->assertNoFieldChecked('edit-types-config-system-simple', 'system_simple is not checked'); + $this->assertNoFieldChecked('edit-types-config-user-role', 'user_role is not checked'); + $this->assertNoFieldChecked('edit-curated', 'curated is not checked'); + $this->assertNoFieldChecked('edit-module-namespace', 'namespace is not checked'); + + // Can we enable the method? + $this->drupalGet('admin/config/development/features/bundle'); + $this->assertNoFieldChecked('edit-enabled-exclude', 'Exclude disabled'); + $this->drupalPostForm(NULL, [ + 'enabled[exclude]' => TRUE, + ], $this->t('Save settings')); + $this->assertFieldChecked('edit-enabled-exclude', 'Exclude enabled'); + + // Check new settings. + $settings = $this->defaultBundle()->getAssignmentSettings('exclude'); + $this->assertTrue($settings['enabled'], 'Exclude enabled'); + $this->assertTrue(isset($settings['weight']), 'Exclude has weight'); + $other_keys = array_diff(array_keys($settings), ['enabled', 'weight']); + $this->assertIdentical($other_keys, [], 'Exclude has no other settings'); + + // Can we run assignment with no settings? + $this->drupalGet('admin/config/development/features'); + + // Can we configure the method? + $this->drupalPostForm('admin/config/development/features/bundle/_exclude/default', [ + 'types[config][system_simple]' => TRUE, + 'types[config][user_role]' => FALSE, + 'curated' => TRUE, + 'module[namespace]' => FALSE, + ], $this->t('Save settings')); + + // Check form results. + $this->drupalGet('admin/config/development/features/bundle/_exclude/default'); + $this->assertNoFieldChecked('edit-types-config-features-bundle', 'Saved, features_bundle is not checked'); + $this->assertFieldChecked('edit-types-config-system-simple', 'Saved, system_simple is checked'); + $this->assertNoFieldChecked('edit-types-config-user-role', 'Saved, user_role is not checked'); + $this->assertFieldChecked('edit-curated', 'Saved, curated is checked'); + $this->assertNoFieldChecked('edit-module-namespace', 'Saved, namespace is not checked'); + + // Check final values. + $settings = $this->defaultBundle()->getAssignmentSettings('exclude'); + $this->assertFalse(isset($settings['types']['config']['features_bundle']), 'Saved, not excluding features_bundle'); + $this->assertTrue(isset($settings['types']['config']['system_simple']), 'Saved, excluding system_simple'); + $this->assertFalse(isset($settings['types']['config']['user_role']), 'Saved, not excluding user_role'); + $this->assertTrue($settings['curated'], 'Saved, excluding curated items'); + $this->assertFalse($settings['module']['namespace'], 'Saved, not excluding by namespace'); + } + +}