# Textfields, formatted text and numbers

This example showcases a Custom field that's composed of multiple fields that are of different types. Specifally: textfields, numbers and formatted text

### FieldType

The `FieldType` is the class that will handle the storage of the field. It will be responsible for storing the data in the database and retrieving it. It will also be responsible for validating the data.

{% hint style="info" %}
When creating the schema, there are some rules you should follow:

* textfields should be of type **text** and the size shoul be **tiny**
* Numbers should be of type **int** and the size should be **normal**
* Formatted Text should be of type **text** and the size should be **big**
  {% endhint %}

```php
<?php

namespace Drupal\MODULE_NAME\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;

/**
 * @FieldType(
 *   id = "YOUR_FIELD_TYPE_ID",
 *   label = @Translation("THE LABEL THAT WILL BE DISPLAYED"),
 *   description = @Translation("A SIMPLE DESCRIPTION OF THE FIELD"),
 *   category = @Translation("THE CATEGORY WHERE IT WILL BE DISPLAYED"),
 *   default_widget = "YOUR_DEFAULT_WIDGET",
 *   default_formatter = "YOUR_DEFAULT_FORMATTER",
 * )
 */
class FieldTypeName extends FieldItemBase {

  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['FIELD_ONE'] = DataDefinition::create('string')
                                           ->setLabel(t('FIELD_ONE'));

    $properties['FIELD_TWO'] = DataDefinition::create('integer')
                                                  ->setLabel(t('FIELD_TWO'));

    $properties['FIELD_THREE']        = DataDefinition::create('string')
                                                 ->setLabel(t('FIELD_THREE'));
    $properties['FIELD_FOUR'] = DataDefinition::create('integer')
                                                 ->setLabel(t('FIELD_FOUR'));
    $properties['FIELD_FIVE']        = DataDefinition::create('string')
                                                 ->setLabel(t('FIELD_FIVE'));

    $properties['FIELD_SIX'] = DataDefinition::create('string')
                                          ->setLabel(t('FIELD_SIX'));

    $properties['FIELD_SEVEN'] = DataDefinition::create('integer')
                                         ->setLabel(t('FIELD_SEVEN'));

    return $properties;
  }

  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    // Create a table with three columns. one for a text field, one for a number
    // field, and one for a long text field.
    return [
      'columns' => [
        'FIELD_ONE'        => [
          'type'     => 'text',
          'size'   => 'tiny',
          'not null' => FALSE,
        ],
        'FIELD_TWO' => [
          'type'     => 'int',
          'size'     => 'normal',
          'not null' => FALSE,
        ],
        'FIELD_THREE'         => [
          'type'     => 'text',
          'size'   => 'tiny',
          'not null' => FALSE,
        ],
        'FIELD_FOUR'  => [
          'type'     => 'int',
          'size'     => 'normal',
          'not null' => FALSE,
        ],
        'FIELD_FIVE'         => [
          'type'     => 'text',
          'size'   => 'tiny',
          'not null' => FALSE,
        ],
        'FIELD_SIX'         => [
          'type'     => 'text',
          'size'     => 'big',
          'not null' => FALSE,
        ],
        'FIELD_SEVEN'          => [
          'type'     => 'int',
          'size'     => 'normal',
          'not null' => FALSE,
        ],
      ],
    ];
  }

  public function isEmpty() {
    $FIELD_ONE = $this->get('FIELD_ONE')->getValue();
    $FIELD_THREE  = $this->get('FIELD_THREE')->getValue();
    $FIELD_SIX  = $this->get('FIELD_SIX')->getValue();


    if (empty($FIELD_ONE) && empty($FIELD_THREE) && empty($FIELD_SIX)) {
      return TRUE;
    }
    return FALSE;
  }




}

```

### FieldWidget

The `FieldWidget` is the class that will handle the display of the field in the form. It will be responsible for displaying the field in the form and handling the data that is sent from the form.

{% hint style="info" %}
When working with formatted text, there are certain rules that you should follow:

* The form field should have a type of "text\_format"
* You should add the "format" you're using (basic\_html, full\_html, plaintext, etc.)
* You should use the **massageFormValues** , this will take the value that is being sent, which in this case is an array an take only the value we want, if the following method is not implemented, the form won't save any information regarded to this field.
  {% endhint %}

{% hint style="info" %}
When working with numbers be sure to implement the **errorElement** method to check for constraints.
{% endhint %}

```php
<?php

namespace Drupal\MODULE_NAME\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * @FieldWidget(
 *   id = "YOUR_DEFAULT_WIDGET",
 *   label = @Translation("THE LABEL THAT WILL BE DISPLAYED"),
 *   description = @Translation("A SIMPLE DESCRIPTION OF THE FIELD"),
 *   field_types = {
 *     "YOUR_FIELD_TYPE_ID"
 *   }
 * )
 */
class FieldWidgetName extends WidgetBase {

  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {


    // Create form elements for each field in the field type.
    $element['FIELD_ONE'] = [
      '#type'          => 'textfield',
      '#title'         => t('FIELD_ONE'),
      '#default_value' => $items[$delta]->FIELD_ONE ?? NULL,
      '#attributes'    => [
        'style' => 'width: 100%;',
      ],
    ];
    
    $element['FIELD_TWO'] = [
        '#type'          => 'number',
        '#title'         => t('FIELD_TWO'),
        '#default_value' => (isset($items[$delta]->FIELD_TWO) && !empty($items[$delta]->FIELD_TWO)) ? $items[$delta]->FIELD_TWO : 0,
        '#attributes'    => [
            'style' => 'width: 120px;',
        ],
    ];


    $element['FIELD_THREE'] = [
      '#type'          => 'textfield',
      '#title'         => t('FIELD_THREE'),
      '#default_value' => $items[$delta]->FIELD_THREE ?? NULL,
      '#attributes'    => [
        'style' => 'width: 100%;',
      ],
    ];

    $element['FIELD_FOUR'] = [
      '#type'          => 'number',
      '#title'         => t('FIELD_FOUR'),
      '#default_value' => isset($items[$delta]->FIELD_FOUR) ? $items[$delta]->FIELD_FOUR : 0,
      '#attributes'    => [
        'style' => 'width: 120px;',
      ],
    ];


    $element['FIELD_FIVE'] = [
      '#type'          => 'textfield',
      '#title'         => t('FIELD_FIVE'),
      '#default_value' => $items[$delta]->FIELD_FIVE ?? NULL,
      '#attributes'    => [
        'style' => 'width: 100%;',
      ],
    ];

    $element['FIELD_SIX'] = [
      '#type'          => 'text_format',
      '#title'         => t('FIELD_SIX'),
      '#format'        => 'full_html', // Or any format you want.
      "#base_type"     => "textarea",
      '#default_value' => isset($items[$delta]->FIELD_SIX) ? $items[$delta]->FIELD_SIX : NULL,
    ];

    $element['FIELD_SEVEN'] = [
      '#type'          => 'number',
      '#title'         => t('FIELD_SEVEN'),
      '#default_value' => isset($items[$delta]->FIELD_SEVEN) ? $items[$delta]->FIELD_SEVEN : 0,
      '#attributes'    => [
        'style' => 'width: 100px;',
      ],
    ];


    return $element;
  }

  public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
    foreach ($values as $key => $value) {
      $values[$key]['FIELD_SIX'] = $value['FIELD_SIX']['value'];
    }
    return $values;
  }

  /**
   * {@inheritdoc}
   */
  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
    if (
      $violation->arrayPropertyPath == ['FIELD_TWO'] && !is_numeric($element['FIELD_TWO']['#value'])
      || $violation->arrayPropertyPath == ['FIELD_FOUR'] && !is_numeric($element['FIELD_FOUR']['#value'])
      || $violation->arrayPropertyPath == ['FIELD_SEVEN'] && !is_numeric($element['FIELD_SEVEN']['#value'])
    ) {
      return FALSE;
    }
    return $element;
  }


}

```

### FieldFormatter

The `FieldFormatter` is the class that will handle the display of the field in the view. It will be responsible for displaying the field in the view.

```php
<?php

namespace Drupal\MODULE_NAME\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;

/**
 * @FieldWidget(
 *   id = "YOUR_DEFAULT_WIDGET",
 *   label = @Translation("THE LABEL THAT WILL BE DISPLAYED"),
 *   description = @Translation("A SIMPLE DESCRIPTION OF THE FIELD"),
 *   field_types = {
 *     "YOUR_FIELD_TYPE_ID"
 *   }
 * )
 */
class FieldFormatterName extends FormatterBase {

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];

    foreach ($items as $delta => $item) {
      // The text value has no text format assigned to it, so the user input
      // should equal the output, including newlines.
      $elements[$delta] = [
        '#type' => 'inline_template',
        '#template' => '{{ value|nl2br }}',
        '#context' => ['value' => $item->value],
      ];
    }

    return $elements;
  }

}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://drupal.bermaki.com/drupal-documentation-and-guides/guides/custom-fields/textfields-formatted-text-and-numbers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
