Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed Relation #3

Merged
merged 6 commits into from
Aug 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"require": {
"drupal/auto_entitylabel": "^2.1@beta",
"drupal/name": "^1.0@RC",
"drupal/geolocation": "^2.0"
"drupal/geolocation": "^2.0",
"drupal/token": "^1.3"
},
"require-dev": {
"phpunit/phpunit": "^6",
Expand Down
10 changes: 10 additions & 0 deletions config/install/core.entity_form_display.node.person.default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies:
- field.field.node.person.field_cat_date_begin
- field.field.node.person.field_cat_date_end
- field.field.node.person.field_cat_member_of
- field.field.node.person.field_linked_agent
- field.field.node.person.field_person_alternate_names
- field.field.node.person.field_person_name_authorities
- field.field.node.person.field_person_preferred_name
Expand Down Expand Up @@ -62,6 +63,15 @@ content:
third_party_settings: { }
type: entity_reference_autocomplete
region: content
field_linked_agent:
weight: 29
settings:
match_operator: CONTAINS
size: '60'
placeholder: ''
third_party_settings: { }
type: typed_relation_default
region: content
field_person_alternate_names:
weight: 3
settings: { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies:
- field.field.node.person.field_cat_date_begin
- field.field.node.person.field_cat_date_end
- field.field.node.person.field_cat_member_of
- field.field.node.person.field_linked_agent
- field.field.node.person.field_person_alternate_names
- field.field.node.person.field_person_name_authorities
- field.field.node.person.field_person_preferred_name
Expand Down Expand Up @@ -61,6 +62,14 @@ content:
third_party_settings: { }
type: entity_reference_label
region: content
field_linked_agent:
weight: 9
label: above
settings:
link: true
third_party_settings: { }
type: typed_relation_default
region: content
field_person_alternate_names:
weight: 3
label: above
Expand Down
11 changes: 11 additions & 0 deletions config/install/core.entity_view_display.node.person.teaser.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
uuid: 4ccf6aa8-482a-4bfe-bb49-849fdf573c84
langcode: en
status: true
dependencies:
config:
- core.entity_view_mode.node.teaser
- field.field.node.person.body
- field.field.node.person.field_cat_date_begin
- field.field.node.person.field_cat_date_end
- field.field.node.person.field_cat_member_of
- field.field.node.person.field_person_alternate_names
- field.field.node.person.field_person_name_authorities
- field.field.node.person.field_person_preferred_name
- field.field.node.person.field_relation
- node.type.person
module:
Expand All @@ -27,5 +33,10 @@ content:
weight: 100
region: content
hidden:
field_cat_date_begin: true
field_cat_date_end: true
field_cat_member_of: true
field_person_alternate_names: true
field_person_name_authorities: true
field_person_preferred_name: true
field_relation: true
46 changes: 46 additions & 0 deletions config/install/field.field.node.person.field_linked_agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
uuid: f7e611af-b0d6-4325-81dc-52839a6c56be
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_linked_agent
- node.type.corporate_body
- node.type.family
- node.type.person
module:
- controlled_access_terms
id: node.person.field_linked_agent
field_name: field_linked_agent
entity_type: node
bundle: person
label: 'Linked Agent'
description: ''
required: false
translatable: false
default_value: { }
default_value_callback: ''
settings:
handler: 'default:node'
handler_settings:
target_bundles:
corporate_body: corporate_body
family: family
person: person
sort:
field: _none
auto_create: 0
auto_create_bundle: family
rel_types:
'schema:knows': Knows
'schema:alumniOf': Alumni Of
'schema:children': Children
'schema:colleague': Colleague
'schema:follows': Follows
'schema:knowsAbout': Knows About
'schema:parent': Parent
'schema:relatedTo': Related To
'schema:sibling': Sibling
'schema:sponsor': Sponsor
'schema:spouse': Spouse
'schema:worksFor': Works For (use only with Corporate Bodies)
field_type: typed_relation
20 changes: 20 additions & 0 deletions config/install/field.storage.node.field_linked_agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
uuid: 5eadb639-a448-437d-b048-e2b92b040cf6
langcode: en
status: true
dependencies:
module:
- controlled_access_terms
- node
id: node.field_linked_agent
field_name: field_linked_agent
entity_type: node
type: typed_relation
settings:
target_type: node
module: controlled_access_terms
locked: false
cardinality: -1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
1 change: 1 addition & 0 deletions controlled_access_terms.info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ dependencies:
- name
- auto_entitylabel
- geolocation
- token
38 changes: 38 additions & 0 deletions src/Plugin/Field/FieldFormatter/TypedRelationFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Drupal\controlled_access_terms\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceLabelFormatter;
use Drupal\Core\Field\FieldItemListInterface;

/**
* Plugin implementation of the 'TypedRelationFormatter'.
*
* @FieldFormatter(
* id = "typed_relation_default",
* label = @Translation("Typed Relation Formatter"),
* field_types = {
* "typed_relation"
* }
* )
*/
class TypedRelationFormatter extends EntityReferenceLabelFormatter {

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

foreach ($items as $delta => $item) {

$rel_types = $item->getRelTypes();
$rel_type = isset($rel_types[$item->rel_type]) ? $rel_types[$item->rel_type] : $item->rel_type;

$elements[$delta]['#prefix'] = $rel_type . ': ';
}

return $elements;
}

}
187 changes: 187 additions & 0 deletions src/Plugin/Field/FieldType/TypedRelation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<?php

namespace Drupal\controlled_access_terms\Plugin\Field\FieldType;

use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\FormElement;
use Drupal\Core\TypedData\DataDefinition;

/**
* Implements a Typed Relation field.
*
* @FieldType(
* id = "typed_relation",
* label = @Translation("Typed Relation"),
* module = "controlled_access_terms",
* description = @Translation("Implements a typed relation field"),
* default_formatter = "typed_relation_default",
* default_widget = "typed_relation_default",
* list_class = "\Drupal\Core\Field\EntityReferenceFieldItemList",
* )
*/
class TypedRelation extends EntityReferenceItem {

/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
$schema = parent::schema($field_definition);
$schema['columns']['rel_type'] = [
'type' => 'text',
'size' => 'tiny',
'not null' => TRUE,
];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what is going on here. Is this adding in the schema? Could/should this be a yaml file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the Drupal 8 "Create a custom field type" documentation: "FieldItemInterface::schema() should be overridden, in order to tell the system how to store the value(s) for the field." Every example of custom fields I've seen does it.


return $schema;
}

/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties = parent::propertyDefinitions($field_definition);
$properties['rel_type'] = DataDefinition::create('string')
->setLabel(t('Type'))
->setRequired(TRUE);

return $properties;
}

/**
* {@inheritdoc}
*/
public function isEmpty() {
$parentEmpty = parent::isEmpty();

// All must have a value.
if ($this->rel_type !== NULL &&
!empty($this->rel_type) &&
!($parentEmpty)
) {
return FALSE;
}

return TRUE;
}

/**
* {@inheritdoc}
*/
public static function defaultFieldSettings() {
return ['rel_types' => []] + parent::defaultFieldSettings();
}

/**
* {@inheritdoc}
*/
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
$element = parent::fieldSettingsForm($form, $form_state);

$element['rel_types'] = [
'#type' => 'textarea',
'#title' => t('Available Relations'),
'#default_value' => $this->encodeTextSettingsField($this->getSetting('rel_types')),
'#element_validate' => [[get_class($this), 'validateValues']],
'#required' => TRUE,
'#min' => 1,
'#description' => '<p>' . t('Enter one value per line, in the format key|label.') .
'<br/>' . t('The key is the stored value. The label will be used in displayed values and edit forms.') .
'<br/>' . t("Keys may not contain dots ('.'). They will be removed if used.") .
'<br/>' . t('The label is optional: if a line contains a single string, it will be used as key and label.') .
'</p>',
];

return $element;
}

/**
* Convience method allowing the Formatter to get the rel_types.
*
* @return array
* The array of relation types
*/
public function getRelTypes() {
return $this->getSetting('rel_types');
}

/**
* Encodes pipe-delimited key/value pairs.
*
* @param array $settings
* The array of key/value pairs to encode.
*
* @return string
* The string of encoded key/value pairs.
*/
protected function encodeTextSettingsField(array $settings) {
$output = '';
foreach ($settings as $key => $value) {
$output .= "$key|$value\n";
}
return $output;
}

/**
* Extracts pipe-delimited key/value pairs.
*
* @param string $string
* The raw string to extract values from.
*
* @return array|null
* The array of extracted key/value pairs, or NULL if the string is invalid.
*
* @see \Drupal\options\Plugin\Field\FieldType\ListItemBase::extractAllowedValues()
*/
protected static function extractPipedValues($string) {
$values = [];

$list = explode("\n", $string);
$list = array_map('trim', $list);
$list = array_filter($list, 'strlen');

foreach ($list as $position => $text) {
// Check for an explicit key.
$matches = [];
if (preg_match('/(.*)\|(.*)/', $text, $matches)) {
// Trim key and value to avoid unwanted spaces issues.
// Also remove dots in keys (which aren't permitted.)
$key = str_replace('.', '', trim($matches[1]));
$value = trim($matches[2]);
}
// Otherwise use the value as key and value.
else {
$key = $value = $text;
}

$values[$key] = $value;
}

return $values;
}

/**
* Callback for settings form.
*
* @param \Drupal\Core\Render\Element\FormElement $element
* An associative array containing the properties and children of the
* generic form element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form for the form this element belongs to.
*
* @see \Drupal\Core\Render\Element\FormElement::processPattern()
*/
public static function validateValues(FormElement $element, FormStateInterface $form_state) {
$values = static::extractPipedValues($element['#value']);

if (!is_array($values)) {
$form_state->setError($element, t('Allowed values list: invalid input.'));
}
else {
// We may want to validate key values in the future...
$form_state->setValueForElement($element, $values);
}
}

}
Loading