Commit 98d71715 authored by plach's avatar plach

Issue #2935932 by Sam152, dwkitchen, jibran, amateescu, kiamlaluno,...

Issue #2935932 by Sam152, dwkitchen, jibran, amateescu, kiamlaluno, tstoeckler, joachim: Add a FieldDefinition class for defining bundle fields in code
parent dd571111
......@@ -7,6 +7,7 @@
use Drupal\Core\Cache\UseCacheBackendTrait;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinition;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
......@@ -405,6 +406,8 @@ protected function buildBundleFieldDefinitions($entity_type_id, $bundle, array $
if ($field_definition instanceof BaseFieldDefinition) {
$field_definition->setName($field_name);
$field_definition->setTargetEntityTypeId($entity_type_id);
}
if ($field_definition instanceof BaseFieldDefinition || $field_definition instanceof FieldDefinition) {
$field_definition->setTargetBundle($bundle);
}
}
......
......@@ -9,6 +9,7 @@
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinition;
use Drupal\Core\Render\Element;
use Drupal\language\Entity\ContentLanguageSettings;
use Drupal\node\Entity\NodeType;
......@@ -1860,6 +1861,7 @@ function hook_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityT
* @see hook_entity_field_storage_info_alter()
* @see hook_entity_bundle_field_info_alter()
* @see \Drupal\Core\Field\FieldDefinitionInterface
* @see \Drupal\Core\Field\FieldDefinition
* @see \Drupal\Core\Entity\EntityManagerInterface::getFieldDefinitions()
*
* @todo WARNING: This hook will be changed in
......@@ -1869,12 +1871,12 @@ function hook_entity_bundle_field_info(\Drupal\Core\Entity\EntityTypeInterface $
// Add a property only to nodes of the 'article' bundle.
if ($entity_type->id() == 'node' && $bundle == 'article') {
$fields = [];
$fields['mymodule_text_more'] = BaseFieldDefinition::create('string')
->setLabel(t('More text'))
->setComputed(TRUE)
->setClass('\Drupal\mymodule\EntityComputedMoreText');
$storage_definitions = mymodule_entity_field_storage_info($entity_type);
$fields['mymodule_bundle_field'] = FieldDefinition::createFromFieldStorageDefinition($storage_definitions['mymodule_bundle_field'])
->setLabel(t('Bundle Field'));
return $fields;
}
}
/**
......
<?php
namespace Drupal\Core\Field;
use Drupal\Core\Cache\UnchangingCacheableDependencyTrait;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\TypedData\FieldItemDataDefinition;
use Drupal\Core\TypedData\ListDataDefinition;
/**
* A class for defining entity field definitions.
*
* A field definition in the context of a bundle field is different from a base
* field in that it may exist only for one or more bundles of an entity type. A
* bundle field definition may also override the definition of an existing base
* field definition on a per bundle basis. The bundle field definition is used
* for code driven overrides, while the
* \Drupal\Core\Field\Entity\BaseFieldOverride uses config to override the base
* field definition.
*
* Bundle fields can be defined in code using hook_entity_bundle_field_info() or
* via the
* \Drupal\Core\Entity\FieldableEntityInterface::bundleFieldDefinitions() method
* when defining an entity type. All bundle fields require an associated storage
* definition. A storage definition may have automatically been defined when
* overriding a base field or it may be manually provided via
* hook_entity_field_storage_info().
*
* @see \Drupal\Core\Entity\FieldableEntityInterface::bundleFieldDefinitions()
* @see \Drupal\Core\Field\FieldDefinitionInterface
* @see \Drupal\Core\Field\FieldStorageDefinitionInterface
* @see hook_entity_bundle_field_info()
* @see hook_entity_field_storage_info()
*/
class FieldDefinition extends ListDataDefinition implements FieldDefinitionInterface {
use UnchangingCacheableDependencyTrait;
use FieldInputValueNormalizerTrait;
/**
* The associated field storage definition.
*
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface
*/
protected $fieldStorageDefinition;
/**
* Creates a new field definition.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storageDefinition
* The associated field storage definition.
*
* @return static
*/
public static function createFromFieldStorageDefinition(FieldStorageDefinitionInterface $storageDefinition) {
$field_definition = new static();
$field_definition->setFieldStorageDefinition($storageDefinition);
return $field_definition;
}
/**
* {@inheritdoc}
*/
public function getName() {
return $this->getFieldStorageDefinition()->getName();
}
/**
* {@inheritdoc}
*/
public function getType() {
return $this->getFieldStorageDefinition()->getType();
}
/**
* {@inheritdoc}
*/
public function getTargetEntityTypeId() {
return $this->getFieldStorageDefinition()->getTargetEntityTypeId();
}
/**
* Set the target bundle.
*
* @param string $bundle
* The target bundle.
*
* @return $this
*/
public function setTargetBundle($bundle) {
$this->definition['bundle'] = $bundle;
return $this;
}
/**
* {@inheritdoc}
*/
public function getTargetBundle() {
return $this->definition['bundle'];
}
/**
* Sets whether the display for the field can be configured.
*
* @param string $display_context
* The display context. Either 'view' or 'form'.
* @param bool $configurable
* Whether the display options can be configured (e.g., via the "Manage
* display" / "Manage form display" UI screens). If TRUE, the options
* specified via getDisplayOptions() act as defaults.
*
* @return $this
*/
public function setDisplayConfigurable($display_context, $configurable) {
// If no explicit display options have been specified, default to 'hidden'.
if (empty($this->definition['display'][$display_context])) {
$this->definition['display'][$display_context]['options'] = ['region' => 'hidden'];
}
$this->definition['display'][$display_context]['configurable'] = $configurable;
return $this;
}
/**
* {@inheritdoc}
*/
public function isDisplayConfigurable($display_context) {
return isset($this->definition['display'][$display_context]['configurable']) ? $this->definition['display'][$display_context]['configurable'] : FALSE;
}
/**
* Sets the display options for the field in forms or rendered entities.
*
* This enables generic rendering of the field with widgets / formatters,
* including automated support for "In place editing", and with optional
* configurability in the "Manage display" / "Manage form display" UI screens.
*
* Unless this method is called, the field remains invisible (or requires
* ad-hoc rendering logic).
*
* @param string $display_context
* The display context. Either 'view' or 'form'.
* @param array $options
* An array of display options. Refer to
* \Drupal\Core\Field\FieldDefinitionInterface::getDisplayOptions() for
* a list of supported keys. The options should include at least a 'weight',
* or specify 'type' = 'hidden'. The 'default_widget' / 'default_formatter'
* for the field type will be used if no 'type' is specified.
*
* @return $this
*/
public function setDisplayOptions($display_context, array $options) {
$this->definition['display'][$display_context]['options'] = $options;
return $this;
}
/**
* {@inheritdoc}
*/
public function getDisplayOptions($display_context) {
return isset($this->definition['display'][$display_context]['options']) ? $this->definition['display'][$display_context]['options'] : NULL;
}
/**
* {@inheritdoc}
*/
public function getDefaultValueLiteral() {
return isset($this->definition['default_value']) ? $this->definition['default_value'] : [];
}
/**
* Set the default value callback for the field.
*
* @param string $callback
* The default value callback.
*
* @return $this
*/
public function setDefaultValueCallback($callback) {
if (isset($callback) && !is_string($callback)) {
throw new \InvalidArgumentException('Default value callback must be a string, like "function_name" or "ClassName::methodName"');
}
$this->definition['default_value_callback'] = $callback;
return $this;
}
/**
* {@inheritdoc}
*/
public function getDefaultValueCallback() {
return isset($this->definition['default_value_callback']) ? $this->definition['default_value_callback'] : NULL;
}
/**
* Set a default value for the field.
*
* @param mixed $value
* The default value.
*
* @return $this
*/
public function setDefaultValue($value) {
$this->definition['default_value'] = $this->normalizeValue($value, $this->getFieldStorageDefinition()->getMainPropertyName());
return $this;
}
/**
* {@inheritdoc}
*/
public function getDefaultValue(FieldableEntityInterface $entity) {
// Allow custom default values function.
if ($callback = $this->getDefaultValueCallback()) {
$value = call_user_func($callback, $entity, $this);
}
else {
$value = $this->getDefaultValueLiteral();
}
$value = $this->normalizeValue($value, $this->getFieldStorageDefinition()->getMainPropertyName());
// Allow the field type to process default values.
$field_item_list_class = $this->getClass();
return $field_item_list_class::processDefaultValue($value, $entity, $this);
}
/**
* Sets whether the field is translatable.
*
* @param bool $translatable
* Whether the field is translatable.
*
* @return $this
*/
public function setTranslatable($translatable) {
$this->definition['translatable'] = $translatable;
return $this;
}
/**
* {@inheritdoc}
*/
public function isTranslatable() {
return !empty($this->definition['translatable']) && $this->getFieldStorageDefinition()->isTranslatable();
}
/**
* Set the field storage definition.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storageDefinition
* The field storage definition associated with this field definition.
*
* @return $this
*/
public function setFieldStorageDefinition(FieldStorageDefinitionInterface $storageDefinition) {
$this->fieldStorageDefinition = $storageDefinition;
$this->itemDefinition = FieldItemDataDefinition::create($this);
// Create a definition for the items, and initialize it with the default
// settings for the field type.
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
$default_settings = $field_type_manager->getDefaultFieldSettings($storageDefinition->getType());
$this->itemDefinition->setSettings($default_settings);
return $this;
}
/**
* {@inheritdoc}
*/
public function getFieldStorageDefinition() {
return $this->fieldStorageDefinition;
}
/**
* {@inheritdoc}
*/
public function getConfig($bundle) {
// @todo provide a FieldDefinitionOverride config entity in
// https://www.drupal.org/project/drupal/issues/2935978.
throw new \Exception('Field definitions do not currently have an override config entity.');
}
/**
* {@inheritdoc}
*/
public function getUniqueIdentifier() {
return $this->getTargetEntityTypeId() . '-' . $this->getTargetBundle() . '-' . $this->getName();
}
/**
* {@inheritdoc}
*/
public function getSetting($setting_name) {
if (array_key_exists($setting_name, $this->itemDefinition->getSettings())) {
return $this->itemDefinition->getSetting($setting_name);
}
else {
return $this->getFieldStorageDefinition()->getSetting($setting_name);
}
}
/**
* {@inheritdoc}
*/
public function getSettings() {
return $this->getItemDefinition()->getSettings() + $this->getFieldStorageDefinition()->getSettings();
}
/**
* {@inheritdoc}
*/
public function setSetting($setting_name, $value) {
$this->getItemDefinition()->setSetting($setting_name, $value);
return $this;
}
/**
* {@inheritdoc}
*/
public function setSettings(array $settings) {
// Assign settings individually, in order to keep the current values
// of settings not specified in $settings.
foreach ($settings as $setting_name => $setting) {
$this->getItemDefinition()->setSetting($setting_name, $setting);
}
return $this;
}
}
......@@ -8,6 +8,7 @@
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinition;
use Drupal\entity_test\FieldStorageDefinition;
use Drupal\entity_test\Entity\EntityTestMulRev;
......@@ -73,7 +74,9 @@ function entity_schema_test_entity_field_storage_info(EntityTypeInterface $entit
*/
function entity_schema_test_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle) {
if ($entity_type->id() == 'entity_test' && $bundle == 'custom') {
$definitions['custom_bundle_field'] = \Drupal::entityManager()->getFieldStorageDefinitions($entity_type->id())['custom_bundle_field'];
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $custom_bundle_field_storage */
$custom_bundle_field_storage = entity_schema_test_entity_field_storage_info($entity_type)['custom_bundle_field'];
$definitions[$custom_bundle_field_storage->getName()] = FieldDefinition::createFromFieldStorageDefinition($custom_bundle_field_storage);
return $definitions;
}
}
......@@ -83,11 +86,7 @@ function entity_schema_test_entity_bundle_field_info(EntityTypeInterface $entity
*/
function entity_schema_test_entity_bundle_create($entity_type_id, $bundle) {
if ($entity_type_id == 'entity_test' && $bundle == 'custom') {
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
$field_definitions = entity_schema_test_entity_bundle_field_info($entity_type, $bundle);
$field_definitions['custom_bundle_field']
->setTargetEntityTypeId($entity_type_id)
->setTargetBundle($bundle);
$field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type_id, $bundle);
// Notify the entity storage that we just created a new field.
\Drupal::entityManager()->onFieldDefinitionCreate($field_definitions['custom_bundle_field']);
}
......@@ -98,13 +97,9 @@ function entity_schema_test_entity_bundle_create($entity_type_id, $bundle) {
*/
function entity_schema_test_entity_bundle_delete($entity_type_id, $bundle) {
if ($entity_type_id == 'entity_test' && $bundle == 'custom') {
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
$field_definitions = entity_schema_test_entity_bundle_field_info($entity_type, $bundle);
$field_definitions['custom_bundle_field']
->setTargetEntityTypeId($entity_type_id)
->setTargetBundle($bundle);
$field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type_id, $bundle);
// Notify the entity storage that our field is gone.
\Drupal::entityManager()->onFieldDefinitionDelete($field_definitions['custom_bundle_field']);
\Drupal::entityManager()->onFieldStorageDefinitionDelete($field_definitions['custom_bundle_field']);
\Drupal::entityManager()->onFieldStorageDefinitionDelete($field_definitions['custom_bundle_field']->getFieldStorageDefinition());
}
}
......@@ -80,7 +80,7 @@ public function testCustomBundleFieldUsage() {
$entity->delete();
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $storage->getTableMapping();
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_bundle_field'));
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_bundle_field')->getFieldStorageDefinition());
$result = $this->database->select($table, 'f')
->fields('f')
->condition('f.entity_id', $entity->id())
......@@ -93,7 +93,7 @@ public function testCustomBundleFieldUsage() {
$entity->save();
entity_test_delete_bundle('custom');
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_bundle_field'), TRUE);
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_bundle_field')->getFieldStorageDefinition(), TRUE);
$result = $this->database->select($table, 'f')
->condition('f.entity_id', $entity->id())
->condition('deleted', 1)
......
<?php
namespace Drupal\Tests\Core\Entity;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Field\FieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\TypedData\TypedDataManager;
use Drupal\Tests\UnitTestCase;
/**
* Unit test for the FieldDefinition class.
*
* @group Entity
* @group field
* @coversDefaultClass \Drupal\Core\Field\FieldDefinition
*/
class FieldDefinitionTest extends UnitTestCase {
/**
* A dummy field type name.
*
* @var string
*/
protected $fieldType;
/**
* A dummy field type definition.
*
* @var array
*/
protected $fieldTypeDefinition;
/**
* The test field storage definition.
*
* @var \Drupal\Core\Field\FieldStorageDefinitionInterface
*/
protected $storageDefinition;
/**
* A flag for setting if the field storage supports translation.
*
* @var bool
*/
protected $storageSupportsTranslation = TRUE;
/**
* {@inheritdoc}
*/
protected function setUp() {
$this->fieldType = $this->randomMachineName();
$this->fieldTypeDefinition = [
'id' => $this->fieldType,
'field_settings' => [
'some_instance_setting' => 'value 2',
],
'storage_settings' => [
'some_storage_setting' => 'some value',
],
];
$field_type_manager = $this->prophesize(FieldTypePluginManagerInterface::class);
$field_type_manager->getDefinitions()->willReturn([$this->fieldType => $this->fieldTypeDefinition]);
$field_type_manager->getDefinition()->willReturn($this->fieldTypeDefinition);
$field_type_manager->getDefaultFieldSettings($this->fieldType)->willReturn($this->fieldTypeDefinition['field_settings']);
$field_type_manager->getDefaultStorageSettings($this->fieldType)->willReturn($this->fieldTypeDefinition['storage_settings']);
$storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
$storage_definition->getMainPropertyName()->willReturn('value');
$storage_definition->getType()->willReturn($this->fieldType);
$storage_definition->getName()->willReturn('test_field_name');
$storage_supports_translation = &$this->storageSupportsTranslation;
$storage_definition->isTranslatable()->will(function () use (&$storage_supports_translation) {
return $storage_supports_translation;
});
$storage_definition->getSettings()->willReturn($this->fieldTypeDefinition['storage_settings']);
$storage_definition->getSetting('some_storage_setting')->willReturn($this->fieldTypeDefinition['storage_settings']['some_storage_setting']);
$this->storageDefinition = $storage_definition->reveal();
$entity_field_manager = $this->prophesize(EntityFieldManagerInterface::class);
$entity_field_manager->getFieldStorageDefinitions('entity_test')->willReturn([
'foo' => $storage_definition->reveal(),
]);
$typed_data_manager = $this->prophesize(TypedDataManager::class);
$container = new ContainerBuilder();
$container->set('plugin.manager.field.field_type', $field_type_manager->reveal());
$container->set('entity_field.manager', $entity_field_manager->reveal());
$container->set('typed_data_manager', $typed_data_manager->reveal());
\Drupal::setContainer($container);
}
/**
* @covers ::getName
* @dataProvider factoryTypeProvider
*/
public function testFieldName($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$this->assertEquals($this->storageDefinition->getName(), $definition->getName());
}
/**
* @covers ::getLabel
* @dataProvider factoryTypeProvider
*/
public function testFieldLabel($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$label = $this->randomMachineName();
$definition->setLabel($label);
$this->assertEquals($label, $definition->getLabel());
}
/**
* @covers ::setTargetBundle
* @covers ::getTargetBundle
* @dataProvider factoryTypeProvider
*/
public function testBundle($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$bundle = $this->randomMachineName();
$definition->setTargetBundle($bundle);
$this->assertEquals($bundle, $definition->getTargetBundle());
}
/**
* @covers ::getDescription
* @dataProvider factoryTypeProvider
*/
public function testFieldDescription($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$description = $this->randomMachineName();
$definition->setDescription($description);
$this->assertEquals($description, $definition->getDescription());
}
/**
* @covers ::getType
* @dataProvider factoryTypeProvider
*/
public function testFieldType($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$this->assertEquals($this->fieldType, $definition->getType());
}
/**
* @covers ::getSetting
* @covers ::setSetting
* @covers ::getSettings
* @dataProvider factoryTypeProvider
*/
public function testFieldSettings($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$setting = $this->randomMachineName();
$value = $this->randomMachineName();
$definition->setSetting($setting, $value);
$this->assertEquals($value, $definition->getSetting($setting));
$default_settings = $this->fieldTypeDefinition['field_settings'] + $this->fieldTypeDefinition['storage_settings'];
$this->assertEquals([$setting => $value] + $default_settings, $definition->getSettings());
}
/**
* @covers ::getSetting
* @covers ::setSetting
* @covers ::getSettings
* @dataProvider factoryTypeProvider
*/
public function testDefaultFieldSettings($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$expected_settings = $this->fieldTypeDefinition['field_settings'] + $this->fieldTypeDefinition['storage_settings'];;
$this->assertEquals($expected_settings, $definition->getSettings());
foreach ($expected_settings as $setting => $value) {
$this->assertEquals($value, $definition->getSetting($setting));
}
}
/**
* @covers ::getDefaultValue
* @covers ::setDefaultValue
* @dataProvider factoryTypeProvider
*/
public function testFieldDefaultValue($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$this->assertEquals([], $definition->getDefaultValueLiteral());
$default_value = [
'value' => $this->randomMachineName(),
];
$expected_default_value = [$default_value];
$definition->setDefaultValue($default_value);
$entity = $this->getMockBuilder('Drupal\Core\Entity\ContentEntityBase')
->disableOriginalConstructor()
->getMock();
// Set the field item list class to be used to avoid requiring the typed
// data manager to retrieve it.
$definition->setClass('Drupal\Core\Field\FieldItemList');
$this->assertEquals($expected_default_value, $definition->getDefaultValue($entity));
$data_definition = $this->getMockBuilder('Drupal\Core\TypedData\DataDefinition')
->disableOriginalConstructor()
->getMock();
$data_definition->expects($this->any())
->method('getClass')
->will($this->returnValue('Drupal\Core\Field\FieldItemBase'));
$definition->setItemDefinition($data_definition);
// Set default value only with a literal.
$definition->setDefaultValue($default_value['value']);
$this->assertEquals($expected_default_value, $definition->getDefaultValue($entity));
// Set default value with an indexed array.
$definition->setDefaultValue($expected_default_value);
$this->assertEquals($expected_default_value, $definition->getDefaultValue($entity));
// Set default value with an empty array.
$definition->setDefaultValue([]);
$this->assertEquals([], $definition->getDefaultValue($entity));
// Set default value with NULL.
$definition->setDefaultValue(NULL);
$this->assertEquals([], $definition->getDefaultValue($entity));
}
/**
* Tests field translatable methods.
*
* @covers ::isTranslatable
* @covers ::setTranslatable
* @dataProvider factoryTypeProvider
*/
public function testFieldTranslatable($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$this->assertFalse($definition->isTranslatable());
$definition->setTranslatable(TRUE);
$this->assertTrue($definition->isTranslatable());
$definition->setTranslatable(FALSE);
$this->assertFalse($definition->isTranslatable());
$this->storageSupportsTranslation = FALSE;
$definition->setTranslatable(TRUE);
$this->assertFalse($this->storageDefinition->isTranslatable());
$this->assertFalse($definition->isTranslatable());
}
/**
* Tests required.
*
* @covers ::isRequired
* @covers ::setRequired
* @dataProvider factoryTypeProvider
*/
public function testFieldRequired($factory_name) {
$definition = $this->initializeFieldUsingFactory($factory_name);
$this->assertFalse($definition->isRequired());
$definition->setRequired(TRUE);
$this->assertTrue($definition->isRequired());
$definition->setRequired(FALSE);
$this->assertFalse($definition->isRequired());
}
/**
* Tests default value callbacks.
*
* @covers ::setDefaultValueCallback
* @dataProvider factoryTypeProvider
*/
public function testDefaultValueCallback($factory_name) {