diff --git a/sources/content/src/Plugin/tmgmt/Source/ContentEntitySource.php b/sources/content/src/Plugin/tmgmt/Source/ContentEntitySource.php index ff98065..2697684 100644 --- a/sources/content/src/Plugin/tmgmt/Source/ContentEntitySource.php +++ b/sources/content/src/Plugin/tmgmt/Source/ContentEntitySource.php @@ -11,6 +11,7 @@ use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\Plugin\DataType\EntityReference; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemInterface; +use Drupal\Core\Field\Plugin\Field\FieldType\StringItem; use Drupal\Core\TypedData\OptionsProviderInterface; use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Core\TypedData\PrimitiveInterface; @@ -124,6 +125,9 @@ class ContentEntitySource extends SourcePluginBase { '#text' => $property->getValue(), '#translate' => $translate, ); + if ($translate) { + $data[$key][$index][$property_key]['#max_length'] = $field_item->getFieldDefinition()->getFieldStorageDefinition()->getSetting('max_length'); + } if ($property_definition->getDataType() == 'filter_format') { $format = $property->getValue(); diff --git a/sources/content/src/Tests/ContentEntitySourceUnitTest.php b/sources/content/src/Tests/ContentEntitySourceUnitTest.php index fe66880..3093ced 100644 --- a/sources/content/src/Tests/ContentEntitySourceUnitTest.php +++ b/sources/content/src/Tests/ContentEntitySourceUnitTest.php @@ -9,12 +9,12 @@ namespace Drupal\tmgmt_content\Tests; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Language\LanguageInterface; -use Drupal\entity_test\Entity\EntityTestMul; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\node\Entity\Node; use Drupal\system\Tests\Entity\EntityUnitTestBase; +use Drupal\tmgmt\Entity\JobItem; use Drupal\tmgmt\Entity\Translator; use Drupal\tmgmt\JobItemInterface; @@ -30,7 +30,20 @@ class ContentEntitySourceUnitTest extends EntityUnitTestBase { * * @var array */ - public static $modules = array('tmgmt', 'tmgmt_content', 'tmgmt_test', 'node', 'filter', 'file', 'image', 'language', 'content_translation', 'options', 'entity_reference'); + public static $modules = [ + 'tmgmt', + 'tmgmt_content', + 'tmgmt_test', + 'node', + 'field', + 'filter', + 'file', + 'image', + 'language', + 'content_translation', + 'options', + 'entity_reference' + ]; protected $entityTypeId = 'entity_test_mul'; @@ -364,7 +377,7 @@ class ContentEntitySourceUnitTest extends EntityUnitTestBase { */ protected function drupalCreateContentType($settings = array()) { $name = strtolower($this->randomMachineName(8)); - $values = array( + $settings += [ 'type' => $name, 'name' => $name, 'base' => 'node_content', @@ -372,9 +385,9 @@ class ContentEntitySourceUnitTest extends EntityUnitTestBase { 'body_label' => 'Body', 'has_title' => 1, 'has_body' => 1, - ); + ]; - $type = entity_create('node_type', $values); + $type = entity_create('node_type', $settings); $saved = $type->save(); node_add_body_field($type); @@ -483,4 +496,70 @@ class ContentEntitySourceUnitTest extends EntityUnitTestBase { } + /** + * Test translating a field with a max_length set. + */ + public function testMaxLength() { + $account = $this->createUser(); + $type = $this->drupalCreateContentType(); + + // Create a field with max_length of 15. + $field_storage = FieldStorageConfig::create([ + 'field_name' => 'max_length_field', + 'type' => 'string', + 'entity_type' => 'node', + ]); + $field_storage->setTranslatable(TRUE); + $field_storage->setSetting('max_length', 15); + $field_storage->save(); + + $field = FieldConfig::create([ + 'field_storage' => $field_storage, + 'field_name' => 'max_length_field', + 'entity_type' => 'node', + 'bundle' => $type->id(), + ]); + $field->save(); + + // Create a node with that field. + $node = \Drupal::entityManager() + ->getStorage('node') + ->create([ + 'title' => $this->randomMachineName(), + 'uid' => $account->id(), + 'type' => $type->id(), + 'langcode' => 'en', + 'max_length_field' => $this->randomString(15), + ]); + $node->save(); + + $job = tmgmt_job_create('en', 'de'); + $job->translator = 'test_translator'; + $job->save(); + $job_item = tmgmt_job_item_create('content', 'node', $node->id(), array('tjid' => $job->id())); + $job_item->save(); + + // Test if the #max_length value is set in the item data. + $data = $job_item->getSourcePlugin()->getData($job_item); + $this->assertEqual($data['max_length_field'][0]['value']['#max_length'], 15); + + $job->requestTranslation(); + $items = $job->getItems(); + /** @var JobItem $item */ + $item = reset($items); + + // The acceptTranslation will fail as the translation from testTranslator + // will have 3 extra characters. + try { + $item->acceptTranslation(); + $this->fail('Translation was accepted'); + } + catch (\Exception $e) { + $this->pass('Could not accept the translation'); + } + + // The JobItem state should still be review. + $this->assertEqual($item->getState(), JobItem::STATE_REVIEW, 'JobItem state is Review'); + } + } diff --git a/src/Form/JobItemForm.php b/src/Form/JobItemForm.php index 2ad5c2a..c3cc1b3 100644 --- a/src/Form/JobItemForm.php +++ b/src/Form/JobItemForm.php @@ -11,7 +11,6 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\Xss; -use Drupal\Core\Url; use Drupal\tmgmt\Entity\JobItem; use Drupal\tmgmt\JobItemInterface; use Drupal\tmgmt\TranslatorRejectDataInterface; @@ -159,7 +158,8 @@ class JobItemForm extends TmgmtFormBase { $actions['validate'] = array( '#type' => 'submit', '#value' => t('Validate HTML tags'), - '#submit' => array('::submitForm', '::validateTags'), + '#validate' => ['::validateTags'], + '#submit' => array('::submitForm'), ); $url = $item->getJob()->url(); $url = isset($_GET['destination']) ? $_GET['destination'] : $url; @@ -172,23 +172,23 @@ class JobItemForm extends TmgmtFormBase { } /** - * Gets the parent key given the parent array and the key of the child. + * Gets the translatable fields of a given job item. * - * @param string $name - * String containing the child's key. - * @param array $parent_array - * Array containing the elements of the parent. + * @param array $form + * The form array. * - * @return string $key - * Returns the parent key. + * @return array $fields + * Returns the translatable fields of the job item. */ - private function getParentKey($name, array $parent_array) { - foreach ($parent_array as $key => $value) { - if (is_array($value) && isset($value[$name])) { - return $key; + private function getTranslatableFields(array $form) { + $fields = []; + foreach ($form['review'] as $parent_key => $value) { + $key = $parent_key . '|0|value'; + if (isset($value[$key]['translation'])) { + $fields[$parent_key] = $value; } } - return NULL; + return $fields; } /** @@ -196,6 +196,7 @@ class JobItemForm extends TmgmtFormBase { */ public function validateForm(array &$form, FormStateInterface $form_state) { parent::validateForm($form, $form_state); + /** @var JobItem $item */ $item = $this->buildEntity($form, $form_state); // First invoke the validation method on the source controller. $source_ui = $this->sourceManager->createUIInstance($item->getPlugin()); @@ -205,18 +206,46 @@ class JobItemForm extends TmgmtFormBase { $translator_ui = $this->translatorManager->createUIInstance($item->getTranslator()->getPluginId()); $translator_ui->reviewFormValidate($form, $form_state, $item); } - foreach ($form_state->getValues() as $key => $value) { - if (is_array($value) && isset($value['translation'])) { - // If there is an empty field then sets and error to fill it. - if (($value['translation'] == '') && ($value['source'] != '') && ($form_state->getTriggeringElement()['#value'] != 'Validate HTML tags')) { - $parent_key = $this->getParentKey($key, $form['review']); - $form_state->setError($form['review'][$parent_key][$key]['translation'], $this->t('The field is empty')); - } + + foreach ($this->getTranslatableFields($form) as $parent_key => $value) { + $key = $parent_key . '|0|value'; + // If has HTML tags will be an array. + if (isset($value[$key]['translation']['value'])) { + $label = $value[$key]['translation']['value']['#value']; + } + else { + $label = $value[$key]['translation']['#value']; + } + + // Validate that is not empty. + if (empty($label)) { + $form_state->setError($form['review'][$parent_key][$key]['translation'], $this->t('The field is empty.')); + continue; } } } /** + * Validate that is not longer than the max length. + * + * @param array $element + * The input element to validate. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + */ + public function validateMaxLength(array $element, FormStateInterface &$form_state) { + if (isset($element['#max_length']) + && ($element['#max_length'] < strlen($element['#value']))) { + $form_state->setError($element, + $this->t('The field has :size characters while the limit is :limit.', [ + ':size' => strlen($element['#value']), + ':limit' => $element['#max_length'], + ]) + ); + } + } + + /** * Overrides Drupal\Core\Entity\EntityForm::save(). */ public function save(array $form, FormStateInterface $form_state) { @@ -431,6 +460,10 @@ class JobItemForm extends TmgmtFormBase { '#disabled' => $job_item->isAccepted(), '#rows' => $rows, ); + if (!empty($data[$key]['#max_length'])) { + $form[$target_key]['translation']['#max_length'] = $data[$key]['#max_length']; + $form[$target_key]['translation']['#element_validate'] = ['::validateMaxLength']; + } } if (!empty($data[$key]['#format']) && \Drupal::config('tmgmt.settings')->get('respect_text_format') == '1') { diff --git a/src/Tests/TMGMTUiTest.php b/src/Tests/TMGMTUiTest.php index 6ddb34b..7479451 100644 --- a/src/Tests/TMGMTUiTest.php +++ b/src/Tests/TMGMTUiTest.php @@ -496,25 +496,52 @@ class TMGMTUiTest extends TMGMTTestBase { $this->assertText(t('HTML tag validation failed for 2 field(s).')); // Tests that there is always a title. - \Drupal::state()->set('tmgmt.test_source_data', array( - 'title' => array( - '0|value' => array( - '#text' => '

Source text bold and Italic

', - '#label' => 'Title', - ), - ), - 'body' => array( - 'deep_nesting' => array( - '#text' => '

Source body bold and Italic

', + $label = '

Source text bold and Italic

'; + \Drupal::state()->set('tmgmt.test_source_data', [ + 'title' => [ + [ + 'value' => [ + '#text' => $label, + '#label' => 'Title', + '#translate' => TRUE, + ], + ], + ], + 'body' => [ + 'deep_nesting' => [ + '#text' => $label, '#label' => 'Body', - ) - ), - )); + '#translate' => TRUE, + ], + ], + ]); $item5 = $job->addItem('test_source', 'test', 4); - $this->drupalGet('admin/tmgmt/items/' . $item5->id()); - $this->drupalPostForm(NULL, [], t('Save')); - $this->assertText(t('The field is empty')); + $this->drupalPostForm('admin/tmgmt/items/' . $item5->id(), [], t('Save')); + $this->assertText(t('The field is empty.')); + + // Tests field is less than max_length. + \Drupal::state()->set('tmgmt.test_source_data', [ + 'title' => [ + [ + 'value' => [ + '#text' => $label, + '#label' => 'Title', + '#translate' => TRUE, + '#max_length' => 10, + ], + ], + ], + ]); + $item5 = $job->addItem('test_source', 'test', 4); + + $this->drupalPostForm('admin/tmgmt/items/' . $item5->id(), [ + 'title|0|value[translation]' => $label, + ], t('Save')); + $this->assertText(t('The field has :size characters while the limit is :limit.', [ + ':size' => strlen($label), + ':limit' => 10, + ])); // Test for the text with format set. \Drupal::state()->set('tmgmt.test_source_data', array( diff --git a/tmgmt_test/src/Plugin/tmgmt/Source/TestSource.php b/tmgmt_test/src/Plugin/tmgmt/Source/TestSource.php index e2e1227..eee578c 100644 --- a/tmgmt_test/src/Plugin/tmgmt/Source/TestSource.php +++ b/tmgmt_test/src/Plugin/tmgmt/Source/TestSource.php @@ -67,6 +67,7 @@ class TestSource extends SourcePluginBase { 'deep_nesting' => array( '#text' => 'Text for job item with type @type and id @id.', '#label' => 'Label for job item with type @type and id @id.', + '#translate' => TRUE, ), ), ));