diff --git a/imageapi_optimize.module b/imageapi_optimize.module index 5ffeafd..31778ca 100644 --- a/imageapi_optimize.module +++ b/imageapi_optimize.module @@ -49,6 +49,15 @@ function imageapi_optimize_entity_type_alter(array &$entity_types) { } /** + * Implements hook_config_schema_info_alter(). + */ +function imageapi_optimize_config_schema_info_alter(&$definitions) { + if (isset($definitions['image.style.*'])) { + $definitions['image.style.*']['mapping']['pipeline']['type'] = 'string'; + } +} + +/** * Implements hook_form_FORM_ID_alter(). */ function imageapi_optimize_form_image_style_edit_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) { diff --git a/tests/modules/image_module_test/config/schema/image_module_test.schema.yml b/tests/modules/image_module_test/config/schema/image_module_test.schema.yml new file mode 100644 index 0000000..9158f56 --- /dev/null +++ b/tests/modules/image_module_test/config/schema/image_module_test.schema.yml @@ -0,0 +1,15 @@ +image.effect.image_module_test_ajax: + type: mapping + label: 'Ajax test' + mapping: + test_parameter: + type: integer + label: 'Test Parameter' + +image.style.*.third_party.image_module_test: + type: mapping + label: 'Schema for image_module_test module additions to image_style entity' + mapping: + foo: + type: string + label: 'Label for foo' diff --git a/tests/modules/image_module_test/image_module_test.info.yml b/tests/modules/image_module_test/image_module_test.info.yml new file mode 100644 index 0000000..a50c463 --- /dev/null +++ b/tests/modules/image_module_test/image_module_test.info.yml @@ -0,0 +1,12 @@ +name: 'Image test' +type: module +description: 'Provides hook implementations for testing Image module functionality.' +package: Testing +# version: VERSION +# core: 8.x + +# Information added by Drupal.org packaging script on 2016-09-21 +version: '8.2.0-rc2' +core: '8.x' +project: 'drupal' +datestamp: 1474485575 diff --git a/tests/modules/image_module_test/image_module_test.module b/tests/modules/image_module_test/image_module_test.module new file mode 100644 index 0000000..df71375 --- /dev/null +++ b/tests/modules/image_module_test/image_module_test.module @@ -0,0 +1,34 @@ +get('image.test_file_download') ?: FALSE; + if ($default_uri == $uri) { + return array('X-Image-Owned-By' => 'image_module_test'); + } +} + +/** + * Implements hook_image_effect_info_alter(). + * + * Used to keep a count of cache misses in \Drupal\image\ImageEffectManager. + */ +function image_module_test_image_effect_info_alter(&$effects) { + $image_effects_definition_called = &drupal_static(__FUNCTION__, 0); + $image_effects_definition_called++; +} + +/** + * Implements hook_image_style_presave(). + * + * Used to save test third party settings in the image style entity. + */ +function image_module_test_image_style_presave(ImageStyleInterface $style) { + $style->setThirdPartySetting('image_module_test', 'foo', 'bar'); +} diff --git a/tests/modules/image_module_test/src/Plugin/ImageEffect/AjaxTestImageEffect.php b/tests/modules/image_module_test/src/Plugin/ImageEffect/AjaxTestImageEffect.php new file mode 100644 index 0000000..a18c263 --- /dev/null +++ b/tests/modules/image_module_test/src/Plugin/ImageEffect/AjaxTestImageEffect.php @@ -0,0 +1,84 @@ + 0, + ]; + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $form['test_parameter'] = [ + '#type' => 'number', + '#title' => t('Test parameter'), + '#default_value' => $this->configuration['test_parameter'], + '#min' => 0, + ]; + $form['ajax_refresh'] = [ + '#type' => 'button', + '#value' => $this->t('Ajax refresh'), + '#ajax' => ['callback' => [$this, 'ajaxCallback']], + ]; + $form['ajax_value'] = [ + '#id' => 'ajax-value', + '#type' => 'item', + '#title' => $this->t('Ajax value'), + '#markup' => 'bar', + ]; + return $form; + } + + /** + * AJAX callback. + */ + public function ajaxCallback($form, FormStateInterface $form_state) { + $item = [ + '#type' => 'item', + '#title' => $this->t('Ajax value'), + '#markup' => microtime(), + ]; + $response = new AjaxResponse(); + $response->addCommand(new HtmlCommand('#ajax-value', $item)); + return $response; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + parent::submitConfigurationForm($form, $form_state); + + $this->configuration['test_parameter'] = $form_state->getValue('test_parameter'); + } + + /** + * {@inheritdoc} + */ + public function applyEffect(ImageInterface $image) { + return TRUE; + } + +} diff --git a/tests/modules/image_module_test/src/Plugin/ImageEffect/NullTestImageEffect.php b/tests/modules/image_module_test/src/Plugin/ImageEffect/NullTestImageEffect.php new file mode 100644 index 0000000..ceca6fa --- /dev/null +++ b/tests/modules/image_module_test/src/Plugin/ImageEffect/NullTestImageEffect.php @@ -0,0 +1,33 @@ +getUriDependentDimensions($uri); + } + + /** + * {@inheritdoc} + */ + public function applyEffect(ImageInterface $image) { + $dimensions = $this->getUriDependentDimensions($image->getSource()); + return $image->resize($dimensions['width'], $dimensions['height']); + } + + /** + * Make the image dimensions dependent on the image file extension. + * + * @param string $uri + * Original image file URI. + * + * @return array + * Associative array. + * - width: Integer with the derivative image width. + * - height: Integer with the derivative image height. + */ + protected function getUriDependentDimensions($uri) { + $dimensions = []; + $extension = pathinfo($uri, PATHINFO_EXTENSION); + switch (strtolower($extension)) { + case 'png': + $dimensions['width'] = $dimensions['height'] = 100; + break; + + case 'gif': + $dimensions['width'] = $dimensions['height'] = 50; + break; + + default: + $dimensions['width'] = $dimensions['height'] = 20; + break; + + } + return $dimensions; + } + +} diff --git a/tests/modules/image_test_views/image_test_views.info.yml b/tests/modules/image_test_views/image_test_views.info.yml new file mode 100644 index 0000000..b029410 --- /dev/null +++ b/tests/modules/image_test_views/image_test_views.info.yml @@ -0,0 +1,15 @@ +name: 'Image test views' +type: module +description: 'Provides default views for views image tests.' +package: Testing +# version: VERSION +# core: 8.x +dependencies: + - image + - views + +# Information added by Drupal.org packaging script on 2016-09-21 +version: '8.2.0-rc2' +core: '8.x' +project: 'drupal' +datestamp: 1474485575 diff --git a/tests/modules/image_test_views/test_views/views.view.test_image_user_image_data.yml b/tests/modules/image_test_views/test_views/views.view.test_image_user_image_data.yml new file mode 100644 index 0000000..8ea166b --- /dev/null +++ b/tests/modules/image_test_views/test_views/views.view.test_image_user_image_data.yml @@ -0,0 +1,77 @@ +langcode: en +status: true +dependencies: + module: + - file + - user +id: test_image_user_image_data +label: test_image_user_image_data +module: views +description: '' +tag: '' +base_table: users_field_data +base_field: uid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access user profiles' + cache: + type: tag + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + override: true + sticky: false + caption: '' + summary: '' + description: '' + columns: + name: name + fid: fid + info: + name: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + fid: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + default: '-1' + empty_table: false + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + relationships: + user_picture_target_id: + id: user_picture_target_id + table: user__user_picture + field: user_picture_target_id + relationship: none + group_type: group + admin_label: 'image from user_picture' + required: true + plugin_id: standard + arguments: { } + display_extenders: { } diff --git a/tests/src/Kernel/ImageFormatterTest.php b/tests/src/Kernel/ImageFormatterTest.php new file mode 100644 index 0000000..04ac8b0 --- /dev/null +++ b/tests/src/Kernel/ImageFormatterTest.php @@ -0,0 +1,102 @@ +installConfig(['field']); + $this->installEntitySchema('entity_test'); + $this->installEntitySchema('file'); + $this->installSchema('file', array('file_usage')); + + $this->entityType = 'entity_test'; + $this->bundle = $this->entityType; + $this->fieldName = Unicode::strtolower($this->randomMachineName()); + + FieldStorageConfig::create(array( + 'entity_type' => $this->entityType, + 'field_name' => $this->fieldName, + 'type' => 'image', + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + ))->save(); + FieldConfig::create([ + 'entity_type' => $this->entityType, + 'field_name' => $this->fieldName, + 'bundle' => $this->bundle, + 'settings' => [ + 'file_extensions' => 'jpg', + ], + ])->save(); + + $this->display = entity_get_display($this->entityType, $this->bundle, 'default') + ->setComponent($this->fieldName, [ + 'type' => 'image', + 'label' => 'hidden', + ]); + $this->display->save(); + } + + /** + * Tests the cache tags from image formatters. + */ + function testImageFormatterCacheTags() { + // Create a test entity with the image field set. + $entity = EntityTest::create([ + 'name' => $this->randomMachineName(), + ]); + $entity->{$this->fieldName}->generateSampleItems(2); + $entity->save(); + + // Generate the render array to verify if the cache tags are as expected. + $build = $this->display->build($entity); + + $this->assertEquals($entity->{$this->fieldName}[0]->entity->getCacheTags(), $build[$this->fieldName][0]['#cache']['tags'], 'First image cache tags is as expected'); + $this->assertEquals($entity->{$this->fieldName}[1]->entity->getCacheTags(), $build[$this->fieldName][1]['#cache']['tags'], 'Second image cache tags is as expected'); + } + +} diff --git a/tests/src/Kernel/ImageImportTest.php b/tests/src/Kernel/ImageImportTest.php new file mode 100644 index 0000000..d8ca036 --- /dev/null +++ b/tests/src/Kernel/ImageImportTest.php @@ -0,0 +1,46 @@ + 'test' + ]); + + $style->addImageEffect(['id' => 'image_module_test_null']); + $style->addImageEffect(['id' => 'image_module_test_null']); + $style->save(); + + $this->assertEqual(count($style->getEffects()), 2); + + $uuid = \Drupal::service('uuid')->generate(); + $style->set('effects', [ + $uuid => [ + 'id' => 'image_module_test_null', + ], + ]); + $style->save(); + + $style = ImageStyle::load('test'); + $this->assertEqual(count($style->getEffects()), 1); + } + +} diff --git a/tests/src/Kernel/ImageItemTest.php b/tests/src/Kernel/ImageItemTest.php new file mode 100644 index 0000000..1e04c26 --- /dev/null +++ b/tests/src/Kernel/ImageItemTest.php @@ -0,0 +1,132 @@ +installEntitySchema('file'); + $this->installSchema('file', array('file_usage')); + + FieldStorageConfig::create(array( + 'entity_type' => 'entity_test', + 'field_name' => 'image_test', + 'type' => 'image', + 'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED, + ))->save(); + FieldConfig::create([ + 'entity_type' => 'entity_test', + 'field_name' => 'image_test', + 'bundle' => 'entity_test', + 'settings' => [ + 'file_extensions' => 'jpg', + ], + ])->save(); + file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg'); + $this->image = File::create([ + 'uri' => 'public://example.jpg', + ]); + $this->image->save(); + $this->imageFactory = $this->container->get('image.factory'); + } + + /** + * Tests using entity fields of the image field type. + */ + public function testImageItem() { + // Create a test entity with the image field set. + $entity = EntityTest::create(); + $entity->image_test->target_id = $this->image->id(); + $entity->image_test->alt = $alt = $this->randomMachineName(); + $entity->image_test->title = $title = $this->randomMachineName(); + $entity->name->value = $this->randomMachineName(); + $entity->save(); + + $entity = EntityTest::load($entity->id()); + $this->assertTrue($entity->image_test instanceof FieldItemListInterface, 'Field implements interface.'); + $this->assertTrue($entity->image_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); + $this->assertEqual($entity->image_test->target_id, $this->image->id()); + $this->assertEqual($entity->image_test->alt, $alt); + $this->assertEqual($entity->image_test->title, $title); + $image = $this->imageFactory->get('public://example.jpg'); + $this->assertEqual($entity->image_test->width, $image->getWidth()); + $this->assertEqual($entity->image_test->height, $image->getHeight()); + $this->assertEqual($entity->image_test->entity->id(), $this->image->id()); + $this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid()); + + // Make sure the computed entity reflects updates to the referenced file. + file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example-2.jpg'); + $image2 = File::create([ + 'uri' => 'public://example-2.jpg', + ]); + $image2->save(); + + $entity->image_test->target_id = $image2->id(); + $entity->image_test->alt = $new_alt = $this->randomMachineName(); + // The width and height is only updated when width is not set. + $entity->image_test->width = NULL; + $entity->save(); + $this->assertEqual($entity->image_test->entity->id(), $image2->id()); + $this->assertEqual($entity->image_test->entity->getFileUri(), $image2->getFileUri()); + $image = $this->imageFactory->get('public://example-2.jpg'); + $this->assertEqual($entity->image_test->width, $image->getWidth()); + $this->assertEqual($entity->image_test->height, $image->getHeight()); + $this->assertEqual($entity->image_test->alt, $new_alt); + + // Check that the image item can be set to the referenced file directly. + $entity->image_test = $this->image; + $this->assertEqual($entity->image_test->target_id, $this->image->id()); + + // Delete the image and try to save the entity again. + $this->image->delete(); + $entity = EntityTest::create(array('mame' => $this->randomMachineName())); + $entity->save(); + + // Test image item properties. + $expected = array('target_id', 'entity', 'alt', 'title', 'width', 'height'); + $properties = $entity->getFieldDefinition('image_test')->getFieldStorageDefinition()->getPropertyDefinitions(); + $this->assertEqual(array_keys($properties), $expected); + + // Test the generateSampleValue() method. + $entity = EntityTest::create(); + $entity->image_test->generateSampleItems(); + $this->entityValidateAndSave($entity); + $this->assertEqual($entity->image_test->entity->get('filemime')->value, 'image/jpeg'); + } + +} diff --git a/tests/src/Kernel/ImageStyleCustomStreamWrappersTest.php b/tests/src/Kernel/ImageStyleCustomStreamWrappersTest.php new file mode 100644 index 0000000..4d12713 --- /dev/null +++ b/tests/src/Kernel/ImageStyleCustomStreamWrappersTest.php @@ -0,0 +1,111 @@ +fileSystem = $this->container->get('file_system'); + $this->config('system.file')->set('default_scheme', 'public')->save(); + $this->imageStyle = ImageStyle::create(['name' => 'test']); + $this->imageStyle->save(); + } + + /** + * {@inheritdoc} + */ + public function register(ContainerBuilder $container) { + parent::register($container); + foreach ($this->providerTestCustomStreamWrappers() as $stream_wrapper) { + $scheme = $stream_wrapper[0]; + $class = $stream_wrapper[2]; + $container->register("stream_wrapper.$scheme", $class) + ->addTag('stream_wrapper', ['scheme' => $scheme]); + } + } + + /** + * Tests derivative creation with several source on a local writable stream. + * + * @dataProvider providerTestCustomStreamWrappers + * + * @param string $source_scheme + * The source stream wrapper scheme. + * @param string $expected_scheme + * The derivative expected stream wrapper scheme. + */ + public function testCustomStreamWrappers($source_scheme, $expected_scheme) { + $derivative_uri = $this->imageStyle->buildUri("$source_scheme://some/path/image.png"); + $derivative_scheme = $this->fileSystem->uriScheme($derivative_uri); + + // Check that the derivative scheme is the expected scheme. + $this->assertSame($expected_scheme, $derivative_scheme); + + // Check that the derivative URI is the expected one. + $expected_uri = "$expected_scheme://styles/{$this->imageStyle->id()}/$source_scheme/some/path/image.png"; + $this->assertSame($expected_uri, $derivative_uri); + } + + /** + * Provide test cases for testCustomStreamWrappers(). + * + * Derivatives created from writable source stream wrappers will inherit the + * scheme from source. Derivatives created from read-only stream wrappers will + * fall-back to the default scheme. + * + * @return array[] + * An array having each element an array with three items: + * - The source stream wrapper scheme. + * - The derivative expected stream wrapper scheme. + * - The stream wrapper service class. + */ + public function providerTestCustomStreamWrappers() { + return [ + ['public', 'public', PublicStream::class], + ['private', 'private', PrivateStream::class], + ['dummy', 'dummy', DummyStreamWrapper::class], + ['dummy-readonly', 'public', DummyReadOnlyStreamWrapper::class], + ['dummy-remote-readonly', 'public', DummyRemoteReadOnlyStreamWrapper::class], + ]; + } + +} diff --git a/tests/src/Kernel/ImageStyleIntegrationTest.php b/tests/src/Kernel/ImageStyleIntegrationTest.php new file mode 100644 index 0000000..aee8c33 --- /dev/null +++ b/tests/src/Kernel/ImageStyleIntegrationTest.php @@ -0,0 +1,112 @@ + 'main_style']); + $style->save(); + /** @var \Drupal\image\ImageStyleInterface $replacement */ + $replacement = ImageStyle::create(['name' => 'replacement_style']); + $replacement->save(); + + // Create a node-type, named 'note'. + $node_type = NodeType::create(['type' => 'note']); + $node_type->save(); + + // Create an image field and attach it to the 'note' node-type. + FieldStorageConfig::create([ + 'entity_type' => 'node', + 'field_name' => 'sticker', + 'type' => 'image', + ])->save(); + FieldConfig::create([ + 'entity_type' => 'node', + 'field_name' => 'sticker', + 'bundle' => 'note', + ])->save(); + + // Create the default entity view display and set the 'sticker' field to use + // the 'main_style' images style in formatter. + /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $view_display */ + $view_display = EntityViewDisplay::create([ + 'targetEntityType' => 'node', + 'bundle' => 'note', + 'mode' => 'default', + 'status' => TRUE, + ])->setComponent('sticker', ['settings' => ['image_style' => 'main_style']]); + $view_display->save(); + + // Create the default entity form display and set the 'sticker' field to use + // the 'main_style' images style in the widget. + /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */ + $form_display = EntityFormDisplay::create([ + 'targetEntityType' => 'node', + 'bundle' => 'note', + 'mode' => 'default', + 'status' => TRUE, + ])->setComponent('sticker', ['settings' => ['preview_image_style' => 'main_style']]); + $form_display->save(); + + // Check that the entity displays exists before dependency removal. + $this->assertNotNull(EntityViewDisplay::load($view_display->id())); + $this->assertNotNull(EntityFormDisplay::load($form_display->id())); + + // Delete the 'main_style' image style. Before that, emulate the UI process + // of selecting a replacement style by setting the replacement image style + // ID in the image style storage. + /** @var \Drupal\image\ImageStyleStorageInterface $storage */ + $storage = $this->container->get('entity.manager')->getStorage($style->getEntityTypeId()); + $storage->setReplacementId('main_style', 'replacement_style'); + $style->delete(); + + // Check that the entity displays exists after dependency removal. + $this->assertNotNull($view_display = EntityViewDisplay::load($view_display->id())); + $this->assertNotNull($form_display = EntityFormDisplay::load($form_display->id())); + // Check that the 'sticker' formatter component exists in both displays. + $this->assertNotNull($formatter = $view_display->getComponent('sticker')); + $this->assertNotNull($widget = $form_display->getComponent('sticker')); + // Check that both displays are using now 'replacement_style' for images. + $this->assertSame('replacement_style', $formatter['settings']['image_style']); + $this->assertSame('replacement_style', $widget['settings']['preview_image_style']); + + // Delete the 'replacement_style' without setting a replacement image style. + $replacement->delete(); + + // The entity view and form displays exists after dependency removal. + $this->assertNotNull($view_display = EntityViewDisplay::load($view_display->id())); + $this->assertNotNull($form_display = EntityFormDisplay::load($form_display->id())); + // The 'sticker' formatter component should be hidden in view display. + $this->assertNull($view_display->getComponent('sticker')); + $this->assertTrue($view_display->get('hidden')['sticker']); + // The 'sticker' widget component should be active in form displays, but the + // image preview should be disabled. + $this->assertNotNull($widget = $form_display->getComponent('sticker')); + $this->assertSame('', $widget['settings']['preview_image_style']); + } + +} diff --git a/tests/src/Kernel/Views/ImageViewsDataTest.php b/tests/src/Kernel/Views/ImageViewsDataTest.php new file mode 100644 index 0000000..70bfd84 --- /dev/null +++ b/tests/src/Kernel/Views/ImageViewsDataTest.php @@ -0,0 +1,92 @@ + 'entity_test', + 'field_name' => 'field_base_image', + 'type' => 'image', + ))->save(); + FieldConfig::create(array( + 'entity_type' => 'entity_test', + 'field_name' => 'field_base_image', + 'bundle' => 'entity_test', + ))->save(); + // Check the generated views data. + $views_data = Views::viewsData()->get('entity_test__field_base_image'); + $relationship = $views_data['field_base_image_target_id']['relationship']; + $this->assertEqual($relationship['id'], 'standard'); + $this->assertEqual($relationship['base'], 'file_managed'); + $this->assertEqual($relationship['base field'], 'fid'); + $this->assertEqual($relationship['entity type'], 'file'); + // Check the backwards reference. + $views_data = Views::viewsData()->get('file_managed'); + $relationship = $views_data['reverse_field_base_image_entity_test']['relationship']; + $this->assertEqual($relationship['id'], 'entity_reverse'); + $this->assertEqual($relationship['base'], 'entity_test'); + $this->assertEqual($relationship['base field'], 'id'); + $this->assertEqual($relationship['field table'], 'entity_test__field_base_image'); + $this->assertEqual($relationship['field field'], 'field_base_image_target_id'); + $this->assertEqual($relationship['field_name'], 'field_base_image'); + $this->assertEqual($relationship['entity_type'], 'entity_test'); + $this->assertEqual($relationship['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]); + + // Create image field to entity_test_mul. + FieldStorageConfig::create(array( + 'entity_type' => 'entity_test_mul', + 'field_name' => 'field_data_image', + 'type' => 'image', + ))->save(); + FieldConfig::create(array( + 'entity_type' => 'entity_test_mul', + 'field_name' => 'field_data_image', + 'bundle' => 'entity_test_mul', + ))->save(); + // Check the generated views data. + $views_data = Views::viewsData()->get('entity_test_mul__field_data_image'); + $relationship = $views_data['field_data_image_target_id']['relationship']; + $this->assertEqual($relationship['id'], 'standard'); + $this->assertEqual($relationship['base'], 'file_managed'); + $this->assertEqual($relationship['base field'], 'fid'); + $this->assertEqual($relationship['entity type'], 'file'); + // Check the backwards reference. + $views_data = Views::viewsData()->get('file_managed'); + $relationship = $views_data['reverse_field_data_image_entity_test_mul']['relationship']; + $this->assertEqual($relationship['id'], 'entity_reverse'); + $this->assertEqual($relationship['base'], 'entity_test_mul_property_data'); + $this->assertEqual($relationship['base field'], 'id'); + $this->assertEqual($relationship['field table'], 'entity_test_mul__field_data_image'); + $this->assertEqual($relationship['field field'], 'field_data_image_target_id'); + $this->assertEqual($relationship['field_name'], 'field_data_image'); + $this->assertEqual($relationship['entity_type'], 'entity_test_mul'); + $this->assertEqual($relationship['join_extra'][0], ['field' => 'deleted', 'value' => 0, 'numeric' => TRUE]); + } + +}