From 7492fff67b56065ef9165f82d28bfa17bb99f2f5 Mon Sep 17 00:00:00 2001 From: Andrei Mateescu Date: Sun, 19 Aug 2018 19:07:08 +0300 Subject: [PATCH 1/7] Add an Ethereum address content entity type. --- ethereum.links.action.yml | 6 + ethereum.links.menu.yml | 6 + src/Entity/EthereumAddress.php | 138 ++++++++++++++++++++ src/EthereumAddressAccessControlHandler.php | 30 +++++ src/EthereumAddressInterface.php | 48 +++++++ src/EthereumAddressListBuilder.php | 36 +++++ src/EthereumAddressStorageSchema.php | 46 +++++++ 7 files changed, 310 insertions(+) create mode 100644 src/Entity/EthereumAddress.php create mode 100644 src/EthereumAddressAccessControlHandler.php create mode 100644 src/EthereumAddressInterface.php create mode 100644 src/EthereumAddressListBuilder.php create mode 100644 src/EthereumAddressStorageSchema.php diff --git a/ethereum.links.action.yml b/ethereum.links.action.yml index fbcc203..5210db9 100644 --- a/ethereum.links.action.yml +++ b/ethereum.links.action.yml @@ -3,3 +3,9 @@ entity.ethereum_server.add_server_form: title: 'Add Ethereum node' appears_on: - ethereum.settings + +entity.ethereum_address.add_form: + route_name: entity.ethereum_address.add_form + title: 'Add address' + appears_on: + - entity.ethereum_address.collection diff --git a/ethereum.links.menu.yml b/ethereum.links.menu.yml index 62a38fa..2b077a7 100644 --- a/ethereum.links.menu.yml +++ b/ethereum.links.menu.yml @@ -14,3 +14,9 @@ ethereum.settings: parent: ethereum.admin_index title: 'Ethereum Network Configuration' description: 'Configure how Drupal connects to Ethereum.' + +entity.ethereum_address.collection: + title: 'Ethereum addresses' + parent: ethereum.admin_index + description: 'Create and manage Ethereum addresses.' + route_name: entity.ethereum_address.collection diff --git a/src/Entity/EthereumAddress.php b/src/Entity/EthereumAddress.php new file mode 100644 index 0000000..fa63d2b --- /dev/null +++ b/src/Entity/EthereumAddress.php @@ -0,0 +1,138 @@ +get('network')->value; + } + + /** + * {@inheritdoc} + */ + public function setNetworkID($network_id) { + $this->set('network', $network_id); + return $this; + } + + /** + * {@inheritdoc} + */ + public function isContract() { + return (bool) $this->get('contract')->value; + } + + /** + * {@inheritdoc} + */ + public function setContract($is_contract) { + $this->set('contract', $is_contract); + return $this; + } + + /** + * {@inheritdoc} + */ + public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { + $fields['address'] = BaseFieldDefinition::create('ethereum_address') + ->setLabel(new TranslatableMarkup('Address')) + ->setRequired(TRUE) + ->setReadOnly(TRUE) + ->setDisplayOptions('view', [ + 'label' => 'hidden', + 'type' => 'basic_string', + ]) + ->setDisplayOptions('form', [ + 'type' => 'ethereum_address', + ]); + + $fields['network'] = BaseFieldDefinition::create('list_string') + ->setLabel(new TranslatableMarkup('Network')) + ->setDescription(new TranslatableMarkup('The Ethereum network on which this address exists.')) + ->setRequired(TRUE) + ->setReadOnly(TRUE) + ->setDefaultValueCallback('\Drupal\ethereum\Entity\EthereumAddress::getCurrentNetworkId') + ->setSetting('allowed_values_function', '\Drupal\ethereum\Controller\EthereumController::getNetworksAsOptions') + ->setDisplayOptions('form', [ + 'type' => 'options_select', + ]); + + + $fields['contract'] = BaseFieldDefinition::create('boolean') + ->setLabel(new TranslatableMarkup('Is contract')) + ->setDefaultValue(FALSE) + ->setReadOnly(TRUE) + ->setDisplayOptions('form', [ + 'type' => 'boolean_checkbox', + ]); + + return $fields; + } + + /** + * Default value callback for the 'network' base field. + * + * @see ::baseFieldDefinitions() + * + * @return array + * An array of default values. + */ + public static function getCurrentNetworkId() { + $current_server = \Drupal::config('ethereum.settings')->get('current_server'); + $server = EthereumServer::load($current_server); + return [$server->getNetworkId()]; + } + +} diff --git a/src/EthereumAddressAccessControlHandler.php b/src/EthereumAddressAccessControlHandler.php new file mode 100644 index 0000000..4d61e9c --- /dev/null +++ b/src/EthereumAddressAccessControlHandler.php @@ -0,0 +1,30 @@ +getName() === $this->entityType->getKey('id')) { + return $return_as_object ? AccessResult::allowed() : TRUE; + } + + return $access; + } + +} diff --git a/src/EthereumAddressInterface.php b/src/EthereumAddressInterface.php new file mode 100644 index 0000000..f32ff72 --- /dev/null +++ b/src/EthereumAddressInterface.php @@ -0,0 +1,48 @@ + $this->t('Address'), + 'network' => $this->t('Network'), + ]; + return $header + parent::buildHeader(); + } + + /** + * {@inheritdoc} + */ + public function buildRow(EntityInterface $entity) { + /** @var \Drupal\ethereum\EthereumAddressInterface $entity */ + $row['address'] = $entity->id(); + $networks = EthereumController::getNetworksAsOptions(); + $row['network'] = $networks[$entity->getNetworkId()]; + return $row + parent::buildRow($entity); + } + +} diff --git a/src/EthereumAddressStorageSchema.php b/src/EthereumAddressStorageSchema.php new file mode 100644 index 0000000..f6740c6 --- /dev/null +++ b/src/EthereumAddressStorageSchema.php @@ -0,0 +1,46 @@ +storage->getBaseTable()]['primary key'] = [$entity_type->getKey('id'), 'network']; + + return $schema; + } + + /** + * {@inheritdoc} + */ + protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) { + $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping); + $field_name = $storage_definition->getName(); + + if ($table_name == $this->storage->getBaseTable()) { + switch ($field_name) { + case 'network': + $schema['fields'][$field_name]['not null'] = TRUE; + $schema['fields'][$field_name]['length'] = 4; + break; + } + } + + return $schema; + } + +} From f7dd29c477746cf5a774c00ccd6a4dcda4f2e4c3 Mon Sep 17 00:00:00 2001 From: Andrei Mateescu Date: Mon, 20 Aug 2018 11:37:38 +0300 Subject: [PATCH 2/7] Add a regular ID field for ethereum addresses and a unique constraint on the (address, network) field pair. --- src/Entity/EthereumAddress.php | 28 +++++++- src/EthereumAddressInterface.php | 18 +++++ src/EthereumAddressListBuilder.php | 6 +- src/EthereumAddressStorageSchema.php | 11 ++- .../EthereumAddressNetworkConstraint.php | 32 +++++++++ ...ereumAddressNetworkConstraintValidator.php | 67 +++++++++++++++++++ 6 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 src/Plugin/Validation/Constraint/EthereumAddressNetworkConstraint.php create mode 100644 src/Plugin/Validation/Constraint/EthereumAddressNetworkConstraintValidator.php diff --git a/src/Entity/EthereumAddress.php b/src/Entity/EthereumAddress.php index fa63d2b..2d50023 100644 --- a/src/Entity/EthereumAddress.php +++ b/src/Entity/EthereumAddress.php @@ -38,7 +38,8 @@ * admin_permission = "administer site configuration", * base_table = "ethereum_address", * entity_keys = { - * "id" = "address", + * "id" = "id", + * "uuid" = "uuid", * "label" = "address", * }, * links = { @@ -47,11 +48,29 @@ * "edit-form" = "/admin/config/ethereum/addresses/address/{ethereum_address}/edit", * "delete-form" = "/admin/config/ethereum/addresses/address/{ethereum_address}/delete", * "collection" = "/admin/config/ethereum/addresses", - * } + * }, + * constraints = { + * "EthereumAddressNetwork" = {} + * }, * ) */ class EthereumAddress extends ContentEntityBase implements EthereumAddressInterface { + /** + * {@inheritdoc} + */ + public function getAddress() { + return $this->get('address')->value; + } + + /** + * {@inheritdoc} + */ + public function setAddress($address) { + $this->set('address', $address); + return $this; + } + /** * {@inheritdoc} */ @@ -86,6 +105,11 @@ public function setContract($is_contract) { * {@inheritdoc} */ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { + $fields = parent::baseFieldDefinitions($entity_type); + + // Ensure that we can store as many addresses as possible. + $fields['id']->setSetting('size', 'big'); + $fields['address'] = BaseFieldDefinition::create('ethereum_address') ->setLabel(new TranslatableMarkup('Address')) ->setRequired(TRUE) diff --git a/src/EthereumAddressInterface.php b/src/EthereumAddressInterface.php index f32ff72..dea51f8 100644 --- a/src/EthereumAddressInterface.php +++ b/src/EthereumAddressInterface.php @@ -9,6 +9,24 @@ */ interface EthereumAddressInterface extends ContentEntityInterface { + /** + * Gets the Ethereum address. + * + * @return string + * The Ethereum address. + */ + public function getAddress(); + + /** + * Sets the address. + * + * @param string $address + * The address. + * + * @return $this + */ + public function setAddress($address); + /** * Gets the address' network ID. * diff --git a/src/EthereumAddressListBuilder.php b/src/EthereumAddressListBuilder.php index aa3d21c..cb734ef 100644 --- a/src/EthereumAddressListBuilder.php +++ b/src/EthereumAddressListBuilder.php @@ -27,9 +27,9 @@ public function buildHeader() { */ public function buildRow(EntityInterface $entity) { /** @var \Drupal\ethereum\EthereumAddressInterface $entity */ - $row['address'] = $entity->id(); - $networks = EthereumController::getNetworksAsOptions(); - $row['network'] = $networks[$entity->getNetworkId()]; + $networks = EthereumController::getNetworks(); + $row['address'] = $entity->getAddress(); + $row['network'] = $networks[$entity->getNetworkId()]['label']; return $row + parent::buildRow($entity); } diff --git a/src/EthereumAddressStorageSchema.php b/src/EthereumAddressStorageSchema.php index f6740c6..1ddec82 100644 --- a/src/EthereumAddressStorageSchema.php +++ b/src/EthereumAddressStorageSchema.php @@ -17,9 +17,11 @@ class EthereumAddressStorageSchema extends SqlContentEntityStorageSchema { protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) { $schema = parent::getEntitySchema($entity_type, $reset); - // Use a composite primary key because an Ethereum address can only exist in - // the context of a specific network. - $schema[$this->storage->getBaseTable()]['primary key'] = [$entity_type->getKey('id'), 'network']; + // Add a UNIQUE index on the 'address' and 'network' fields because two + // identical addresses can not live on the same network. + $schema[$this->storage->getBaseTable()]['unique keys'] += [ + 'ethereum_address__address_network' => ['address', 'network'], + ]; return $schema; } @@ -33,6 +35,9 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st if ($table_name == $this->storage->getBaseTable()) { switch ($field_name) { + case 'address': + $schema['fields'][$field_name]['not null'] = TRUE; + break; case 'network': $schema['fields'][$field_name]['not null'] = TRUE; $schema['fields'][$field_name]['length'] = 4; diff --git a/src/Plugin/Validation/Constraint/EthereumAddressNetworkConstraint.php b/src/Plugin/Validation/Constraint/EthereumAddressNetworkConstraint.php new file mode 100644 index 0000000..ac01c25 --- /dev/null +++ b/src/Plugin/Validation/Constraint/EthereumAddressNetworkConstraint.php @@ -0,0 +1,32 @@ +ethereumAddressStorage = $ethereum_address_storage; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static($container->get('entity_type.manager')->getStorage('ethereum_address')); + } + + /** + * {@inheritdoc} + */ + public function validate($entity, Constraint $constraint) { + /** @var \Drupal\ethereum\EthereumAddressInterface $entity */ + $network_id = $entity->getNetworkId(); + $existing_address = $this->ethereumAddressStorage->loadByProperties([ + 'address' => $entity->getAddress(), + 'network' => $network_id, + ]); + + if ($existing_address) { + $networks = EthereumController::getNetworks(); + $this->context->buildViolation($constraint->message, ['%network_label' => $networks[$network_id]['label']]) + ->atPath('address') + ->addViolation(); + } + } + +} From 8773e52fa59b0a3031d2d97a821d87553f8831c4 Mon Sep 17 00:00:00 2001 From: Andrei Mateescu Date: Mon, 20 Aug 2018 11:40:52 +0300 Subject: [PATCH 3/7] The custom access handler is not needed anymore. --- src/Entity/EthereumAddress.php | 1 - src/EthereumAddressAccessControlHandler.php | 30 --------------------- 2 files changed, 31 deletions(-) delete mode 100644 src/EthereumAddressAccessControlHandler.php diff --git a/src/Entity/EthereumAddress.php b/src/Entity/EthereumAddress.php index 2d50023..b48735a 100644 --- a/src/Entity/EthereumAddress.php +++ b/src/Entity/EthereumAddress.php @@ -24,7 +24,6 @@ * handlers = { * "storage_schema" = "Drupal\ethereum\EthereumAddressStorageSchema", * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", - * "access" = "Drupal\ethereum\EthereumAddressAccessControlHandler", * "views_data" = "Drupal\views\EntityViewsData", * "form" = { * "default" = "Drupal\Core\Entity\ContentEntityForm", diff --git a/src/EthereumAddressAccessControlHandler.php b/src/EthereumAddressAccessControlHandler.php deleted file mode 100644 index 4d61e9c..0000000 --- a/src/EthereumAddressAccessControlHandler.php +++ /dev/null @@ -1,30 +0,0 @@ -getName() === $this->entityType->getKey('id')) { - return $return_as_object ? AccessResult::allowed() : TRUE; - } - - return $access; - } - -} From 841c52d667e3c91bb28cbf062660d6c55d741638 Mon Sep 17 00:00:00 2001 From: Andrei Mateescu Date: Thu, 23 Aug 2018 10:03:04 +0300 Subject: [PATCH 4/7] Add an option to reference only addresses from the current network by default. --- .../EthereumAddressSelection.php | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/Plugin/EntityReferenceSelection/EthereumAddressSelection.php diff --git a/src/Plugin/EntityReferenceSelection/EthereumAddressSelection.php b/src/Plugin/EntityReferenceSelection/EthereumAddressSelection.php new file mode 100644 index 0000000..18f7b39 --- /dev/null +++ b/src/Plugin/EntityReferenceSelection/EthereumAddressSelection.php @@ -0,0 +1,66 @@ + TRUE, + ] + parent::defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $configuration = $this->getConfiguration(); + + $form['restrict_to_current_network'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Filter the available addresses by the current network'), + '#default_value' => $configuration['restrict_to_current_network'], + ]; + $form += parent::buildConfigurationForm($form, $form_state); + + return $form; + } + + /** + * {@inheritdoc} + */ + protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') { + $query = parent::buildEntityQuery($match, $match_operator); + + $configuration = $this->getConfiguration(); + + // Filter by the current network if needed. + if ($configuration['restrict_to_current_network']) { + $current_server = \Drupal::config('ethereum.settings')->get('current_server'); + $server = EthereumServer::load($current_server); + + $query->condition('network', $server->getNetworkId(), '='); + } + + return $query; + } + +} From 6426a794d8bbceb4082b4b2968d7250d13309c77 Mon Sep 17 00:00:00 2001 From: Andrei Mateescu Date: Thu, 23 Aug 2018 10:03:41 +0300 Subject: [PATCH 5/7] Expose the Field UI routes. --- ethereum.links.task.yml | 4 ++++ src/Entity/EthereumAddress.php | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 ethereum.links.task.yml diff --git a/ethereum.links.task.yml b/ethereum.links.task.yml new file mode 100644 index 0000000..21c5a6f --- /dev/null +++ b/ethereum.links.task.yml @@ -0,0 +1,4 @@ +entity.ethereum_address.collection: + title: List + route_name: entity.ethereum_address.collection + base_route: entity.ethereum_address.collection diff --git a/src/Entity/EthereumAddress.php b/src/Entity/EthereumAddress.php index b48735a..3a5d7fc 100644 --- a/src/Entity/EthereumAddress.php +++ b/src/Entity/EthereumAddress.php @@ -14,7 +14,7 @@ * @ContentEntityType( * id = "ethereum_address", * label = @Translation("Ethereum address"), - * label_collection = @Translation("Ethereum address"), + * label_collection = @Translation("Ethereum addresses"), * label_singular = @Translation("address"), * label_plural = @Translation("addresses"), * label_count = @PluralTranslation( @@ -41,6 +41,7 @@ * "uuid" = "uuid", * "label" = "address", * }, + * field_ui_base_route = "entity.ethereum_address.collection", * links = { * "canonical" = "/admin/config/ethereum/addresses/address/{ethereum_address}", * "add-form" = "/admin/config/ethereum/addresses/add", From 95cb4751c5f6b4b76d2899e74b7283285087ec81 Mon Sep 17 00:00:00 2001 From: Andrei Mateescu Date: Thu, 23 Aug 2018 10:57:22 +0300 Subject: [PATCH 6/7] Provide a nicer UX for views. --- ethereum.module | 9 +++++++++ src/EthereumAddressStorageSchema.php | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ethereum.module b/ethereum.module index e74c3fe..2674a6a 100644 --- a/ethereum.module +++ b/ethereum.module @@ -50,6 +50,15 @@ function ethereum_field_formatter_info_alter(array &$info) { $info['basic_string']['field_types'][] = 'ethereum_address'; } +/** + * Implements hook_views_data_alter(). + */ +function ethereum_views_data_alter(array &$data) { + // Provide a nice list of options for the 'network' filter. + $data['ethereum_address']['network']['filter']['id'] = 'in_operator'; + $data['ethereum_address']['network']['filter']['options callback'] = 'Drupal\ethereum\Controller\EthereumController::getNetworksAsOptions'; +} + /** * Implements hook_js_settings_alter(). * diff --git a/src/EthereumAddressStorageSchema.php b/src/EthereumAddressStorageSchema.php index 1ddec82..9d951c2 100644 --- a/src/EthereumAddressStorageSchema.php +++ b/src/EthereumAddressStorageSchema.php @@ -40,7 +40,7 @@ protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $st break; case 'network': $schema['fields'][$field_name]['not null'] = TRUE; - $schema['fields'][$field_name]['length'] = 4; + $schema['fields'][$field_name]['length'] = 10; break; } } From ed52626dbb93de2ab1b0197431940c961ecd917a Mon Sep 17 00:00:00 2001 From: Andrei Mateescu Date: Thu, 23 Aug 2018 13:25:25 +0300 Subject: [PATCH 7/7] Add a field formatter and make all the fields configurable in the UI. --- src/Entity/EthereumAddress.php | 14 +- .../EthereumAddressFormatter.php | 173 ++++++++++++++++++ .../Field/FieldType/EthereumAddressItem.php | 2 +- 3 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 src/Plugin/Field/FieldFormatter/EthereumAddressFormatter.php diff --git a/src/Entity/EthereumAddress.php b/src/Entity/EthereumAddress.php index 3a5d7fc..90aabc5 100644 --- a/src/Entity/EthereumAddress.php +++ b/src/Entity/EthereumAddress.php @@ -116,11 +116,13 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setReadOnly(TRUE) ->setDisplayOptions('view', [ 'label' => 'hidden', - 'type' => 'basic_string', + 'type' => 'ethereum_address', ]) ->setDisplayOptions('form', [ 'type' => 'ethereum_address', - ]); + ]) + ->setDisplayConfigurable('view', TRUE) + ->setDisplayConfigurable('form', TRUE);; $fields['network'] = BaseFieldDefinition::create('list_string') ->setLabel(new TranslatableMarkup('Network')) @@ -131,7 +133,9 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setSetting('allowed_values_function', '\Drupal\ethereum\Controller\EthereumController::getNetworksAsOptions') ->setDisplayOptions('form', [ 'type' => 'options_select', - ]); + ]) + ->setDisplayConfigurable('view', TRUE) + ->setDisplayConfigurable('form', TRUE); $fields['contract'] = BaseFieldDefinition::create('boolean') @@ -140,7 +144,9 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setReadOnly(TRUE) ->setDisplayOptions('form', [ 'type' => 'boolean_checkbox', - ]); + ]) + ->setDisplayConfigurable('view', TRUE) + ->setDisplayConfigurable('form', TRUE); return $fields; } diff --git a/src/Plugin/Field/FieldFormatter/EthereumAddressFormatter.php b/src/Plugin/Field/FieldFormatter/EthereumAddressFormatter.php new file mode 100644 index 0000000..aeda39c --- /dev/null +++ b/src/Plugin/Field/FieldFormatter/EthereumAddressFormatter.php @@ -0,0 +1,173 @@ + '', + 'rel' => '', + 'target' => '', + ] + parent::defaultSettings(); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state) { + $elements = parent::settingsForm($form, $form_state); + + $elements['link_to_network'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Link to the network address page'), + '#default_value' => $this->getSetting('link_to_network'), + ]; + $elements['rel'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Add rel="nofollow" to the link'), + '#return_value' => 'nofollow', + '#default_value' => $this->getSetting('rel'), + '#states' => array( + 'visible' => array( + array( + 'input[name="fields[address][settings_edit_form][settings][link_to_network]"]' => array('checked' => TRUE), + ), + ), + ), + ]; + $elements['target'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Open link in new window'), + '#return_value' => '_blank', + '#default_value' => $this->getSetting('target'), + '#states' => array( + 'visible' => array( + array( + 'input[name="fields[address][settings_edit_form][settings][link_to_network]"]' => array('checked' => TRUE), + ), + ), + ), + ]; + + return $elements; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary() { + $summary = []; + + $settings = $this->getSettings(); + + if (!empty($settings['link_to_network'])) { + $summary[] = $this->t('Link to the network address page'); + } + if (!empty($settings['rel'])) { + $summary[] = $this->t('Add rel="@rel"', ['@rel' => $settings['rel']]); + } + if (!empty($settings['target'])) { + $summary[] = $this->t('Open link in new window'); + } + + return $summary; + } + + /** + * {@inheritdoc} + */ + public function viewElements(FieldItemListInterface $items, $langcode) { + $elements = []; + $entity = $items->getEntity(); + $settings = $this->getSettings(); + + if (empty($settings['link_to_network'])) { + return parent::viewElements($items, $langcode); + } + + $current_server = \Drupal::config('ethereum.settings')->get('current_server'); + $server = EthereumServer::load($current_server); + $networks = EthereumController::getNetworks(); + + if ($entity->getEntityTypeId() === 'ethereum_address') { + $network = $networks[$entity->get('network')->first()->value]; + } + else { + $network = $networks[$server->getNetworkId()]; + } + + foreach ($items as $delta => $item) { + $url = $this->buildUrl($item, $network); + + $elements[$delta] = [ + '#type' => 'link', + '#title' => $item->value, + '#url' => $url, + '#options' => $url->getOptions(), + ]; + } + + return $elements; + } + + /** + * Builds the \Drupal\Core\Url object for a field item. + * + * @param \Drupal\ethereum\Plugin\Field\FieldType\EthereumAddressItem $item + * The field item being rendered. + * @param array $network + * An associative array with network information. + * + * @return \Drupal\Core\Url + * A Url object. + */ + protected function buildUrl(EthereumAddressItem $item, array $network) { + if (!empty($network['link_to_address'])) { + $network_link = str_replace('@address', $item->value, $network['link_to_address']); + $url = Url::fromUri($network_link); + } + else { + $url = Url::fromRoute(''); + } + + $settings = $this->getSettings(); + $options = $url->getOptions(); + + // Add optional 'rel' attribute to link options. + if (!empty($settings['rel'])) { + $options['attributes']['rel'] = $settings['rel']; + } + // Add optional 'target' attribute to link options. + if (!empty($settings['target'])) { + $options['attributes']['target'] = $settings['target']; + } + $url->setOptions($options); + + return $url; + } + +} diff --git a/src/Plugin/Field/FieldType/EthereumAddressItem.php b/src/Plugin/Field/FieldType/EthereumAddressItem.php index 8303009..e724764 100644 --- a/src/Plugin/Field/FieldType/EthereumAddressItem.php +++ b/src/Plugin/Field/FieldType/EthereumAddressItem.php @@ -14,7 +14,7 @@ * label = @Translation("Ethereum address"), * description = @Translation("Provides a field for Ethereum addresses."), * default_widget = "ethereum_address", - * default_formatter = "basic_string" + * default_formatter = "ethereum_address" * ) */ class EthereumAddressItem extends StringItem {