# Adding an EAV-based field

**Each address form in the checkout is based upon the EAV entity `customer_address`. By adding a new EAV attribute to this entity, you can easily add your own form field to the checkout. On this page, you will see the steps involved for this.**

## Adding the EAV attribute to the database
First of all, you will need to add the EAV attribute to the database. This is usually done through a `Patch` class, but you can also use a third party extension for this (like the Amasty [Customer Attributes](https://amasty.com/customer-attributes-for-magento-2.html)) extension. The following shows an example `Patch` class that creates an example EAV attribute `example`:

```php
namespace YireoTraining\Example\Setup\Patch\Data;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Eav\Model\Config as EavConfig;
use Magento\Customer\Model\ResourceModel\Attribute as AttributeResourceModel;

class AddExampleFieldToCustomerAddress implements DataPatchInterface
{
    public function __construct(
        private EavSetupFactory $eavSetupFactory,
        private ModuleDataSetupInterface $moduleDataSetup,
        private EavConfig $eavConfig,
        private AttributeResourceModel $attributeResourceModel
    ) {
    }

    public static function getDependencies()
    {
        return [];
    }

    public function getAliases()
    {
        return [];
    }

    public function apply()
    {
        $attributeCode = 'example';
        $attributeLabel = 'Example';
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);

        $eavSetup->addAttribute(
            'customer_address',
            $attributeCode,
            [
                'input' => 'text',
                'is_visible_in_grid' => false,
                'visible' => true,
                'user_defined' => true,
                'is_filterable_in_grid' => false,
                'system' => false,
                'label' => $attributeLabel,
                'position' => 10,
                'type' => 'varchar',
                'is_used_in_grid' => false,
                'required' => false,
            ]
        );

        $attribute = $this->eavConfig->getAttribute('customer_address', $attributeCode);

        return $this;
    }
}
```

Once this class has been created as part of a new module, running `bin/magento setup:upgrade` should create this EAV-attribute as a row in the database table `eav_attribute` (amongst others).

This example can be further extended by adding the attribute to frontend and backend forms. See the `LokiCheckout_Coc` module  for a full example.

## Adding a quote address column to the database
The above adds an attribute to the `customer_address` entity. While attributes of this entity are automatically copied into a quote address, it doesn't save the quote address attribute value yet. To save a value to the database, we can either add a new column to the `quote_address` table and `sales_order_address` table, or we could save things via an extension attribute.

In this example, we simply extend the tables. This can be done with the following `db_schema.xml` file:

```xml
<?xml version="1.0"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
    <table name="quote_address" resource="default">
        <column xsi:type="varchar" name="example" nullable="true" length="128" comment="Example"/>
    </table>
    <table name="sales_order_address" resource="default">
        <column xsi:type="varchar" name="example" nullable="true" length="128" comment="Example"/>
    </table>
</schema>
```

After running `bin/magento setup:upgrade`, the tables should be altered.

## Creating a new block
Next, let's create a new block for this EAV attribute via an XML layout file `loki_checkout_block_shipping_address.xml`:

```xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:View/Layout:etc/page_configuration.xsd">
    <body>
        <referenceBlock name="loki-checkout.shipping.address.form">
            <block
                name="loki-checkout-example.shipping.address.example" as="example"
                template="Loki_FieldComponents::form/field.phtml"/>
        </referenceBlock>
    </body>
</page>
```

Note that the PHTML template `Loki_FieldComponents::form/field.phtml` is reused here. Normally, this is what you want: A lot of changes you might want to make to this field can be made via either the ViewModel or the XML layout.

## Creating a component
To transform the block above into a full-blown LokiComponent, we need one more step. We need to add a new component to the `etc/loki_components.xml` file. The `name` of that component is identical to the `name` of the block. The `group` called `shippingAddressFields` includes a definition for a `Context` class, `ViewModel` class and `Repository` class which we can reuse here. These classes automatically match the name of the block (in our case `example`) with the attribute code of your EAV attribute (in our case `example`).

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<components xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Loki_Components:etc/loki_components.xsd">
    <component
        name="loki-checkout-example.shipping.address.example"
        group="shippingAddressFields"
    />
</components>
```

> See the `etc/loki_components.xml` of the core module `LokiCheckout_Core` to see the definition of the group `shippingAddressFields`.

It might be that the original classes need to be modified. In this case, you would create your own classes, extending upon the original. This is actually done for **all** of the core component classes: Even though they don't have anything specific, they allow for an easier extensibility.

A more customized version could look the following:
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<components xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Loki_Components:etc/loki_components.xsd">
    <component
        name="loki-checkout-example.shipping.address.example"
        group="shippingAddressFields"
        viewModel="LokiCheckoutExample\Component\Checkout\Address\Example\ExampleViewModel"
        repository="LokiCheckoutExample\Component\Checkout\Address\Example\ExampleRepository"
    />
</components>
```

## Enhancing the LokiComponent
You could also add `<target/>` elements, so that other HTML elements are refreshed when your component is being updated. You could add validators and filters as well.
