diff -u b/conditional_fields.features.inc b/conditional_fields.features.inc --- b/conditional_fields.features.inc +++ b/conditional_fields.features.inc @@ -99,10 +99,10 @@ $instances = field_info_instances(); foreach ($defaults as $item) { foreach ($item as $field) { - if (isset($dependencies[$field['entity']][$field['bundle']])) { - /* @see hook_conditional_fields_features_rebuild_alter() */ - drupal_alter(__FUNCTION__, $field, $module); + /* @see hook_conditional_fields_features_rebuild_alter() */ + drupal_alter(__FUNCTION__, $field, $module); + if (isset($dependencies[$field['entity']][$field['bundle']])) { foreach ($dependencies[$field['entity']][$field['bundle']] as $dependancy_type => $field_dep_settings) { if ($dependancy_type == 'dependees' && !empty($field_dep_settings)) { foreach ($field_dep_settings as $dep_setting) { only in patch2: unchanged: --- a/conditional_fields.info +++ b/conditional_fields.info @@ -3,6 +3,12 @@ description = Define dependencies between fields based on their states and value core = 7.x package = Fields +configure = admin/structure/dependencies + +test_dependencies[] = uuid +test_dependencies[] = features +test_dependencies[] = entityreference +test_dependencies[] = hierarchical_select + dependencies[] = system (>=7.14) dependencies[] = field -configure = admin/structure/dependencies only in patch2: unchanged: --- /dev/null +++ b/src/Tests/EntityReferenceFeaturesUuidExportImport/AutocompleteWidgetTest.php @@ -0,0 +1,370 @@ + end($namespace), + // The first part (zero index) is "Drupal", second - name of + // the module. Use it as an identifier of the group. + 'group' => $namespace[1], + ); + } + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(array_merge($this->modules, array( + 'taxonomy', + 'conditional_fields', + 'entityreference', + 'features', + 'uuid', + ))); + + $this->contentType = $this->drupalCreateContentType(array( + 'type' => 'test_content_type', + )); + + $this->vocabulary = $this->drupalCreateTaxonomyVocabulary(array( + 'machine_name' => 'test_vocabulary', + )); + + $this->user = $this->drupalCreateUser(array( + 'administer dependencies', + 'administer features', + 'generate features', + )); + + $this->term = $this->drupalCreateTaxonomyTerm($this->vocabulary); + + foreach (array( + 'field_text' => array( + 'type' => 'text', + 'settings' => array( + 'max_length' => 60, + ), + ), + 'field_reference' => array( + 'type' => 'entityreference', + 'widget' => $this->getWidget(), + 'settings' => array( + 'handler' => 'base', + 'target_type' => 'taxonomy_term', + 'handler_settings' => array( + 'target_bundles' => array($this->vocabulary->machine_name), + ), + ), + ), + ) as $field_name => $info) { + $info += array( + 'bundle' => $this->contentType->type, + 'field_name' => $field_name, + 'entity_type' => self::ENTITY_TYPE, + 'entity_types' => array(self::ENTITY_TYPE), + ); + + field_create_field($info); + field_create_instance($info); + + $this->fieldInstances[$field_name] = field_info_instance( + self::ENTITY_TYPE, + $field_name, + $this->contentType->type + ); + } + } + + /** + * Returns definition of the field widget to test export of. + * + * @return array + * Definition of the widget. + */ + protected function getWidget() { + return array( + 'type' => 'entityreference_autocomplete', + 'active' => TRUE, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'size' => 60, + 'path' => '', + ), + ); + } + + /** + * Returns the value for the field for the particular widget. + * + * @param null|string $value + * A value to use instead of the default. + * + * @return array[] + * Value for the field. + */ + protected function getWidgetValue($value = NULL) { + if (NULL === $value) { + $value = $this->term->name . ' (' . $this->term->tid . ')'; + } + + return array(array('target_id' => $value)); + } + + /** + * Returns the value for the form of the field for the particular widget. + * + * @param null|string $value + * A value to use instead of the default. + * + * @return array[] + * Value for the form of the field. + */ + protected function getWidgetValueForm($value = NULL) { + return $this->getWidgetValue($value); + } + + /** + * Creates an instance of the "taxonomy_vocabulary" entity. + * + * @param array $settings + * A list of settings. + * + * @return \stdClass + * An instance of the "taxonomy_vocabulary" entity. + */ + protected function drupalCreateTaxonomyVocabulary(array $settings = array()) { + $name = $this->randomName(); + $vocabulary = (object) ($settings + array( + 'name' => $name, + 'machine_name' => drupal_strtolower($name), + )); + + taxonomy_vocabulary_save($vocabulary); + + return $vocabulary; + } + + /** + * Creates an instance of the "taxonomy_term" entity. + * + * @param \stdClass $vocabulary + * An instance of the "taxonomy_vocabulary" to which the term will belong. + * @param array $settings + * A list of settings. + * + * @return \stdClass + * An instance of the "taxonomy_term" entity. + */ + protected function drupalCreateTaxonomyTerm(\stdClass $vocabulary, array $settings = array()) { + $term = (object) ($settings + array( + 'vid' => $vocabulary->vid, + 'name' => $this->randomName(), + 'uuid' => uuid_generate(), + 'weight' => 0, + 'parent' => 0, + 'language' => LANGUAGE_NONE, + // Set the property here to not call the "taxonomy_vocabulary_load()" + // during saving. + 'vocabulary_machine_name' => $vocabulary->machine_name, + )); + + taxonomy_term_save($term); + + return $term; + } + + /** + * Adds new conditional fields dependency. + */ + protected function addDependency() { + $base = array( + 'condition' => 'value', + 'state' => 'visible', + ); + + $queries = array(); + $config = array(); + + $this->drupalPost( + "admin/structure/types/manage/{$this->contentType->type}/dependencies", + $base + array( + 'dependent' => $this->fieldInstances['field_text']['id'], + 'dependee' => $this->fieldInstances['field_reference']['id'], + ), + t('Add dependency') + ); + + $queries['value']['field']['field_reference'][LANGUAGE_NONE] = $this->getWidgetValueForm(); + $queries['values_set'] = CONDITIONAL_FIELDS_DEPENDENCY_VALUES_WIDGET; + + // Build HTML "name" attributes from nested arrays. + foreach (explode('&', drupal_http_build_query($queries)) as $query) { + list($query, $value) = explode('=', $query); + // Restore initial string as a value. + $config[$query] = rawurldecode($value); + } + + $this->drupalPost(NULL, $base + $config, t('Save settings')); + $this->assertNoRaw('messages error', 'The field condition has been successfully saved.'); + } + + /** + * Generates the feature with exported conditional fields. + * + * @return array[] + * - 0 : exported configuration. + * - 1 : components to rebuild. + */ + protected function generateFeature() { + // What is 58? Good question! Check references below. + /* @see features_dom_encode_options() */ + /* @see features_dom_encode_map() */ + $conditional_field = self::ENTITY_TYPE . '__58__' . $this->contentType->type; + $features_component = 'conditional_fields'; + $features_module_name = uniqid('test_feature'); + + $config = array( + 'name' => 'Test feature', + 'module_name' => $features_module_name, + 'generate_path' => "sites/default/modules/simpletest", + "dependencies[sources][selected][$features_component]" => $features_component, + "{$features_component}[sources][selected][$conditional_field]" => $conditional_field, + ); + + $this->drupalPost('admin/structure/features/create', $config, t('Generate feature')); + + $this->assertTrue( + module_enable(array($features_module_name)), + 'A generated feature has been successfully enabled.' + ); + + $this->resetAll(); + + return array( + features_get_default($features_component, $features_module_name) ?: array(), + array($features_module_name => array($features_component)), + ); + } + + /** + * Loads conditional fields dependencies. + * + * @return array[] + * Conditional fields dependencies. + */ + protected function loadDependencies() { + $function = 'conditional_fields_load_dependencies'; + + drupal_static_reset($function); + + return $function(self::ENTITY_TYPE, $this->contentType->type); + } + + /** + * Checks that export/import of referenced entities operates by UUIDs. + * + * @internal + */ + public function testExportImport() { + $this->drupalLogin($this->user); + $this->addDependency(); + + list($defaults, $components) = $this->generateFeature(); + + // After generating the feature its codebase must have UUIDs instead of + // entity IDs. Let's check this. + foreach (array( + 'value_form' => $this->getWidgetValueForm($this->term->uuid), + 'value' => $this->getWidgetValue($this->term->uuid), + ) as $key => $value) { + foreach ($defaults[self::ENTITY_TYPE . ':' . $this->contentType->type] as $dependee) { + $this->assertTrue( + $value === $dependee['options'][$key], + 'Entity ID has been successfully replaced by UUID in generated feature.' + ); + } + } + + // Remove all conditions. + db_delete('conditional_fields')->execute(); + // And ensure they were removed. + $this->assertFalse($this->loadDependencies(), 'No dependencies exist after removal.'); + + // Revert the feature. + features_rebuild($components); + // And load dependencies again. + $dependencies = $this->loadDependencies(); + + // After reverting the feature all UUIDs must had been converted to IDs. + foreach (array( + 'value_form' => $this->getWidgetValueForm($this->term->tid), + 'value' => $this->getWidgetValue($this->term->tid), + ) as $key => $value) { + foreach ($dependencies['dependees']['field_reference'] as $id => $dependee) { + $this->assertTrue( + $value === $dependee['options'][$key], + 'Entity UUID has been successfully replaced by ID after rebuilding the feature.' + ); + } + } + } + +} only in patch2: unchanged: --- /dev/null +++ b/src/Tests/EntityReferenceFeaturesUuidExportImport/HierarchicalSelectWidgetTest.php @@ -0,0 +1,59 @@ + 'hser_hierarchy', + 'active' => TRUE, + 'module' => 'hser', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'size' => 60, + 'path' => '', + 'editable' => FALSE, + ), + ); + } + + /** + * {@inheritdoc} + */ + protected function getWidgetValue($value = NULL) { + if (NULL === $value) { + $value = $this->term->tid; + } + + return array(array('target_id' => $value)); + } + + /** + * {@inheritdoc} + */ + protected function getWidgetValueForm($value = NULL) { + if (NULL === $value) { + $value = $this->term->tid; + } + + return array( + 'hsid' => '59af2a36e3799', + 'hierarchical_select' => array( + 'selects' => array($value), + ), + ); + } + +}