Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • project/external_entities
  • issue/external_entities-3198912
  • issue/external_entities-3018424
  • issue/external_entities-3201512
  • issue/external_entities-3203559
  • issue/external_entities-3138256
  • issue/external_entities-3209747
  • issue/external_entities-3020924
  • issue/external_entities-3232598
  • issue/external_entities-3079012
  • issue/external_entities-3261988
  • issue/external_entities-3270683
  • issue/external_entities-3262870
  • issue/external_entities-3274173
  • issue/external_entities-3287410
  • issue/external_entities-3315167
  • issue/external_entities-3316905
  • issue/external_entities-3269431
  • issue/external_entities-3171505
  • issue/external_entities-3033305
  • issue/external_entities-3005536
  • issue/external_entities-3240844
  • issue/external_entities-3078931
  • issue/external_entities-3337903
  • issue/external_entities-3338281
  • issue/external_entities-3000080
  • issue/external_entities-3376591
  • issue/external_entities-3368304
  • issue/external_entities-3395520
  • issue/external_entities-2998932
  • issue/external_entities-3395565
  • issue/external_entities-3110209
  • issue/external_entities-2998391
  • issue/external_entities-3414496
  • issue/external_entities-3073025
  • issue/external_entities-3418226
  • issue/external_entities-3418321
  • issue/external_entities-3419507
  • issue/external_entities-3425428
  • issue/external_entities-3136353
  • issue/external_entities-3417863
  • issue/external_entities-3427431
  • issue/external_entities-3427686
  • issue/external_entities-3430375
  • issue/external_entities-3444893
  • issue/external_entities-3374867
  • issue/external_entities-3455366
  • issue/external_entities-3458277
  • issue/external_entities-3049317
  • issue/external_entities-3455362
  • issue/external_entities-3462773
  • issue/external_entities-3463731
  • issue/external_entities-3377869
  • issue/external_entities-2538706
  • issue/external_entities-3474891
  • issue/external_entities-3475589
  • issue/external_entities-3475630
  • issue/external_entities-3475645
  • issue/external_entities-3475700
  • issue/external_entities-3476099
  • issue/external_entities-3476326
  • issue/external_entities-3476772
  • issue/external_entities-3475248
  • issue/external_entities-3478219
  • issue/external_entities-3486164
  • issue/external_entities-3479118
  • issue/external_entities-3490155
  • issue/external_entities-3479938
  • issue/external_entities-3506171
  • issue/external_entities-3506394
  • issue/external_entities-3506455
  • issue/external_entities-3506667
  • issue/external_entities-3506730
  • issue/external_entities-3506738
  • issue/external_entities-3506812
  • issue/external_entities-3507472
  • issue/external_entities-3506799
  • issue/external_entities-3509474
  • issue/external_entities-3509687
  • issue/external_entities-3505555
  • issue/external_entities-3511161
  • issue/external_entities-3510714
  • issue/external_entities-3511627
  • issue/external_entities-3511947
  • issue/external_entities-3514604
  • issue/external_entities-3516385
  • issue/external_entities-3516546
  • issue/external_entities-3517947
  • issue/external_entities-3518019
  • issue/external_entities-3519200
  • issue/external_entities-3515124
  • issue/external_entities-3521734
  • issue/external_entities-3523999
  • issue/external_entities-3526917
  • issue/external_entities-3177616
  • issue/external_entities-3528814
  • issue/external_entities-3339830
  • issue/external_entities-3531815
98 results
Select Git revision
Show changes
Commits on Source (36)
Showing
with 278 additions and 139 deletions
......@@ -688,6 +688,15 @@ see the source code of an example implementation:
Drupal\xnttsanity\Plugin\ExternalEntities\StorageClient\Sanity
Drupal\gbif2_entity\Plugin\ExternalEntities\StorageClient\Gbif
(companion module of gbif2 module)
Then, your storage client will have to implement a set of methods. Some methods
may be complex to implement, such as ::transliterateDrupalFilters(). While it
can have a basic implementation, consider providing a better implementation for
performances (see "Upgrading v2 storage clients" related part).
Also, the ::save() method is responsible to update the entity object identifier
for new entities. See how the REST client does it to have an idea on how to
proceed. Indeed, the ::save() method does not return the entity identifier but
a status (SAVED_NEW or SAVED_UPDATED) so the only way to return the new
identifier is through the (mapped) entity object.
## Creating a field mapper plugin
......@@ -732,6 +741,11 @@ Drupal\external_entities\Plugin\ExternalEntities\DataAggregator\GroupAggregator
for a complex example. It could be used as a base class as it provides many
usefull features. Horizontal and vertical data aggregators are examples of
derived plugins from the GroupAggregator.
When playing with "foreign keys" (ie. field of one source data is used as
identifier on another one), the data aggregator is responsile to provide the
appropriate field mapping to the second data source to let that source know
which (Drupal entity) field is mapped to that data source identifier and also
temporarily adjust the provided entity object identifier.
## Creating external entity types programmatically
......
......@@ -9,8 +9,5 @@
},
"require": {
"galbar/jsonpath": "^2.0||^3.0"
},
"require-dev": {
"drupal/inline_entity_form": "^3.0@RC"
}
}
plugin.plugin_configuration.external_entities_data_aggregator.single:
type: config_object
type: mapping
label: 'External entities single storage client aggregation settings'
mapping:
storage_clients:
......@@ -12,7 +12,7 @@ plugin.plugin_configuration.external_entities_data_aggregator.single:
nullable: true
plugin.plugin_configuration.external_entities_data_aggregator.group:
type: config_object
type: mapping
label: 'External entities group aggregator settings'
mapping:
storage_clients:
......
plugin.plugin_configuration.external_entities_data_processor.default:
type: config_object
type: mapping
label: 'External entities default data processor config'
mapping:
debug_level:
......@@ -8,7 +8,7 @@ plugin.plugin_configuration.external_entities_data_processor.default:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.boolean:
type: config_object
type: mapping
label: 'External entities boolean data processor config'
mapping:
debug_level:
......@@ -17,7 +17,7 @@ plugin.plugin_configuration.external_entities_data_processor.boolean:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.datetime:
type: config_object
type: mapping
label: 'External entities date and time data processor config'
mapping:
source_format:
......@@ -35,7 +35,7 @@ plugin.plugin_configuration.external_entities_data_processor.datetime:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.hash:
type: config_object
type: mapping
label: 'External entities hash data processor config'
mapping:
hash:
......@@ -47,7 +47,7 @@ plugin.plugin_configuration.external_entities_data_processor.hash:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.numeric:
type: config_object
type: mapping
label: 'External entities numeric data processor config'
mapping:
position:
......@@ -59,7 +59,7 @@ plugin.plugin_configuration.external_entities_data_processor.numeric:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.numericunit:
type: config_object
type: mapping
label: 'External entities numeric unit data processor config'
mapping:
metric:
......@@ -74,7 +74,7 @@ plugin.plugin_configuration.external_entities_data_processor.numericunit:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.stringcase:
type: config_object
type: mapping
label: 'External entities string character case altering data processor config'
mapping:
format:
......@@ -89,7 +89,7 @@ plugin.plugin_configuration.external_entities_data_processor.stringcase:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.mapping:
type: config_object
type: mapping
label: 'External entities value mapping data processor config'
mapping:
mapping:
......@@ -103,7 +103,7 @@ plugin.plugin_configuration.external_entities_data_processor.mapping:
nullable: true
plugin.plugin_configuration.external_entities_data_processor.version:
type: config_object
type: mapping
label: 'External entities version data processor config'
mapping:
elements:
......
plugin.plugin_configuration.external_entities_field_mapper.generic:
type: config_object
type: mapping
label: 'External entities generic field mapper settings'
mapping:
property_mappings:
......@@ -13,7 +13,7 @@ plugin.plugin_configuration.external_entities_field_mapper.generic:
nullable: true
plugin.plugin_configuration.external_entities_field_mapper.text:
type: config_object
type: mapping
label: 'External entities formatted text field mapper settings'
mapping:
property_mappings:
......
plugin.plugin_configuration.external_entities_property_mapper.constant:
type: config_object
type: mapping
label: 'External entities constant property value settings'
mapping:
mapping:
......@@ -22,7 +22,7 @@ plugin.plugin_configuration.external_entities_property_mapper.constant:
label: 'Description'
plugin.plugin_configuration.external_entities_property_mapper.direct:
type: config_object
type: mapping
label: 'External entities raw field property mapper settings'
mapping:
mapping:
......@@ -50,7 +50,7 @@ plugin.plugin_configuration.external_entities_property_mapper.direct:
label: 'Description'
plugin.plugin_configuration.external_entities_property_mapper.simple:
type: config_object
type: mapping
label: 'External entities simple property mapper settings'
mapping:
mapping:
......@@ -78,7 +78,7 @@ plugin.plugin_configuration.external_entities_property_mapper.simple:
label: 'Description'
plugin.plugin_configuration.external_entities_property_mapper.jsonpath:
type: config_object
type: mapping
label: 'External entities JSONPath field mapper settings'
mapping:
mapping:
......
......@@ -26,9 +26,6 @@ external_entities.external_entity_type.*:
constraints:
Range:
min: 0
generate_aliases:
type: boolean
label: 'Automatically generate aliases'
field_mappers:
type: sequence
label: 'Field mapper plugin settings'
......@@ -57,9 +54,11 @@ external_entities.external_entity_type.*:
annotation_field_name:
type: string
label: 'Annotation field name'
inherits_annotation_fields:
type: boolean
label: 'Inherits annotation fields'
annotation_inherited_fields:
type: sequence
label: 'Inherited annotation fields'
sequence:
type: string
external_entities.external_entities_field_mapper_settings:
type: mapping
......
plugin.plugin_configuration.external_entities_storage_client.rest:
type: config_object
type: mapping
label: 'External entities REST storage client settings'
mapping:
endpoint:
......@@ -150,7 +150,7 @@ plugin.plugin_configuration.external_entities_storage_client.jsonapi:
type: plugin.plugin_configuration.external_entities_storage_client.rest
plugin.plugin_configuration.external_entities_storage_client.file_base:
type: config_object
type: mapping
label: 'External entities file base storage client settings'
mapping:
root:
......
......@@ -2,4 +2,4 @@ name: External Entities
type: module
description: 'Allows using remote entities, for example through a REST interface.'
package: External Entities
core_version_requirement: ^10 || ^11
core_version_requirement: ^10.1 || ^11
......@@ -58,6 +58,14 @@ function external_entities_schema() {
'length' => 2083,
'not null' => TRUE,
],
// MD5 hash added for issue #3475768 as unique key on long string is not
// supported by all databases.
'ephash' => [
'description' => 'MD5 hash of the endpoint URL. Used as a unique key for query limiting and upserts.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
],
'qtimes' => [
'description' => 'Sorted array of query times',
'type' => 'text',
......@@ -77,6 +85,7 @@ function external_entities_schema() {
],
],
'primary key' => ['qid'],
'unique keys' => ['ephash' => ['ephash']],
];
return $schema;
......@@ -823,3 +832,58 @@ function external_entities_update_93017(&$sandbox) {
}
}
}
/**
* Convert "inherits_annotation_fields" to "annotation_inherited_fields".
*/
function external_entities_update_93018(&$sandbox) {
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
$entity_field_manager = \Drupal::service('entity_field.manager');
/** @var \Drupal\external_entities\Entity\ExternalEntityTypeInterface[] $external_entity_types */
$external_entity_types = \Drupal::entityTypeManager()
->getStorage('external_entity_type')
->loadByProperties();
foreach ($external_entity_types as $external_entity_type) {
$config = \Drupal::configFactory()->getEditable("external_entities.external_entity_type.{$external_entity_type->id()}");
if (empty($config->get('annotation_inherited_fields'))) {
$config->set('annotation_inherited_fields', []);
if ($config->get('inherits_annotation_fields')
&& $config->get('annotation_entity_type_id')
&& $config->get('annotation_bundle_id')
) {
$field_definitions = $entity_field_manager->getFieldDefinitions($config->get('annotation_entity_type_id'), $config->get('annotation_bundle_id'));
$config->set('annotation_inherited_fields', array_keys($field_definitions));
}
}
$config->clear('inherits_annotation_fields');
$config->save();
}
}
/**
* Remove 'generate_aliases' settings if not external_entities_pathauto module.
*/
function external_entities_update_93019(&$sandbox) {
// Check if external_entities_pathauto sub-module is disabled.
$module_handler = \Drupal::moduleHandler();
if (!$module_handler->moduleExists('external_entities_pathauto')) {
// Module is disabled, remove 'generate_aliases' setting.
$xntt_storage = \Drupal::entityTypeManager()
->getStorage('external_entity_type');
$xntt_types = $xntt_storage
->getQuery()
->accessCheck(FALSE)
->execute();
$updated = [];
// Loop on external entity types.
foreach ($xntt_types as $entity_type_id) {
/** @var \Drupal\Core\Config\Config $config */
$config = \Drupal::configFactory()->getEditable("external_entities.external_entity_type.{$entity_type_id}");
$generate_aliases = $config->get('generate_aliases');
if (isset($generate_aliases)) {
$config->clear('generate_aliases');
$config->save();
}
}
}
}
......@@ -7,10 +7,9 @@
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Utility\DeprecationHelper;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
......@@ -18,34 +17,12 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\Core\Utility\Error;
use Drupal\external_entities\Entity\ConfigurableExternalEntityTypeInterface;
use Drupal\external_entities\Entity\ExternalEntityInterface;
use Drupal\external_entities\Entity\ExternalEntityTypeInterface;
use Drupal\external_entities\ExternalEntityStorageInterface;
use Drupal\external_entities\Plugin\ExternalEntities\StorageClient\RestClientInterface;
use Drupal\external_entities\Plugin\Field\AnnotationTitleFieldItemList;
/**
* Property indicating if the annotated external entity should not be saved.
*
* When an annotation is saved the associated external entity is saved as well.
* Sometimes this is undesired behavior and can therefor be prevent by setting
* this property on the annotation entity object before saving.
*
* @code
* $annotation->BYPASS_ANNOTATED_EXTERNAL_ENTITY_SAVE = TRUE;
* // Save the annotation without triggering an external entity save.
* $annotation->save();
* @endcode
*
* @see _external_entities_process_annotation_changes()
* @see \Drupal\external_entities\Form\ExternalEntityForm
*
* @internal
*/
define('EXTERNAL_ENTITIES_BYPASS_ANNOTATED_EXTERNAL_ENTITY_SAVE_PROPERTY', 'BYPASS_ANNOTATED_EXTERNAL_ENTITY_SAVE');
/**
* Implements hook_entity_type_build().
*/
......@@ -259,8 +236,14 @@ function external_entities_form_field_storage_config_edit_form_alter(&$form, For
if (!empty($form['cardinality_container']['#element_validate'])) {
$entity_type = \Drupal::entityTypeManager()->getDefinition($form_state->get('entity_type_id'));
if ($entity_type && $entity_type->getProvider() === 'external_entities') {
$key = array_search('::validateCardinality', $form['cardinality_container']['#element_validate']);
if ($key !== FALSE) {
foreach ($form['cardinality_container']['#element_validate'] as $i => $callback) {
if ((is_string($callback) && $callback == '::validateCardinality')
|| (is_array($callback) && $callback[1] == 'validateCardinality')) {
$key = $i;
break;
}
}
if (isset($key)) {
$form['cardinality_container']['#element_validate'][$key] = 'external_entities_field_storage_config_edit_form_validate_cardinality';
}
}
......@@ -285,34 +268,6 @@ function external_entities_field_storage_config_edit_form_validate_cardinality(a
}
}
/**
* Implements hook_inline_entity_form_entity_form_alter().
*/
function external_entities_inline_entity_form_entity_form_alter(&$entity_form, FormStateInterface $form_state) {
$form_object = $form_state->getFormObject();
if (!$form_object instanceof EntityFormInterface) {
return;
}
/** @var \Drupal\Core\Entity\FieldableEntityInterface $annotation_entity */
$annotation_entity = $entity_form['#entity'];
$external_entity = $form_object->getEntity();
if ($annotation_entity->isNew() && $external_entity instanceof ExternalEntityInterface) {
$external_entity_type = $external_entity->getExternalEntityType();
if ($external_entity_type->isAnnotatable()
&& $entity_form['#entity_type'] === $external_entity_type->getAnnotationEntityTypeId()
&& $entity_form['#bundle'] === $external_entity_type->getAnnotationBundleId()) {
// Automatically set the reference to the external entity and hide the
// field altogether.
$annotation_reference_field_name = $external_entity_type->getAnnotationFieldName();
$annotation_entity->set($annotation_reference_field_name, $external_entity->id());
if (!empty($entity_form[$annotation_reference_field_name])) {
$entity_form[$annotation_reference_field_name]['#access'] = FALSE;
}
}
}
}
/**
* Implements hook_entity_bundle_field_info_alter().
*/
......@@ -415,45 +370,6 @@ function external_entities_entity_view_alter(array &$build, EntityInterface $ent
}
}
/**
* Implements hook_entity_storage_load().
*/
function external_entities_entity_storage_load(array $entities, $entity_type) {
/** @var \Drupal\external_entities\Entity\ExternalEntity $external_entity_type */
$external_entity_type = \Drupal::entityTypeManager()->getStorage('external_entity_type')->load($entity_type);
if (!$external_entity_type) {
return;
}
if (!$external_entity_type->automaticallyGenerateAliases()) {
return;
}
// Ensure the pathauto module is enabled.
$moduleHandler = \Drupal::service('module_handler');
if (!$moduleHandler->moduleExists('pathauto')) {
return;
}
/** @var \Drupal\pathauto\PathautoGeneratorInterface $pathauto_generator */
$pathauto_generator = \Drupal::service('pathauto.generator');
/** @var \Drupal\path_alias\AliasManagerInterface $path_alias_manager */
$path_alias_manager = \Drupal::service('path_alias.manager');
/** @var \Drupal\external_entities\Entity\ExternalEntityInterface $entity */
foreach ($entities as $entity) {
$path = '/' . $entity->toUrl()->getInternalPath();
$alias = $path_alias_manager->getAliasByPath($path, $entity->language()->getId());
if ($alias !== $path) {
continue;
}
// Generate an alias.
$entity->path = $pathauto_generator->updateEntityAlias($entity, 'insert');
}
}
/**
* Implements hook_entity_insert().
*/
......@@ -489,7 +405,7 @@ function external_entities_entity_delete(EntityInterface $entity) {
* visible.
*
* Another example use case: a pathauto pattern is configured for an annotatable
* external entity, and the pattern uses an inherited annotated field. Saving
* external entity, and the pattern uses an inherited annotation field. Saving
* the external entity on annotation change will make sure the generated path
* is updated.
*
......@@ -501,7 +417,7 @@ function external_entities_entity_delete(EntityInterface $entity) {
* @throws \Drupal\Core\Entity\EntityStorageException
*/
function _external_entities_save_annotated_external_entity(EntityInterface $entity) {
if (!empty($entity->{EXTERNAL_ENTITIES_BYPASS_ANNOTATED_EXTERNAL_ENTITY_SAVE_PROPERTY})) {
if (!empty($entity->{ExternalEntityInterface::ANNOTATION_AUTO_SAVE_INDUCED_BY_EXTERNAL_ENTITY_CHANGE_PROPERTY})) {
return;
}
......@@ -531,11 +447,12 @@ function _external_entities_save_annotated_external_entity(EntityInterface $enti
continue;
}
if (!empty($entity->original) && $external_entity_type->inheritsAnnotationFields()) {
if (!empty($entity->original) && !empty($external_entity_type->getInheritedAnnotationFields())) {
$referenced_entity->original = clone $referenced_entity;
$referenced_entity->original->mapAnnotationFields($entity->original);
}
$referenced_entity->{ExternalEntityStorageInterface::BYPASS_STORAGE_CLIENT_SAVE_PROPERTY} = TRUE;
$referenced_entity->{ExternalEntityInterface::EXTERNAL_ENTITY_AUTO_SAVE_INDUCED_BY_ANNOTATION_CHANGE_PROPERTY} = TRUE;
$referenced_entity->save();
}
}
......@@ -567,7 +484,7 @@ function external_entities_field_config_presave(EntityInterface $entity): void {
->loadMultiple();
}
catch (InvalidPluginDefinitionException | PluginNotFoundException $exception) {
DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '10.1.0', fn() => Error::logException(\Drupal::logger('external_entities'), $exception), fn() => watchdog_exception('external_entities', $exception));
\Drupal::logger('external_entities')->error($exception);
return;
}
if (array_key_exists($entity->get('entity_type'), $external_entity_types)) {
......@@ -674,7 +591,7 @@ function external_entities_regenerate_index_file_process($params, $mode, &$conte
$config =
$params['config']
+ [
ExternalEntityTypeInterface::XNTT_TYPE_PROP => $xntt_type,
ExternalEntityTypeInterface::XNTT_TYPE_PROP => $params['xntt'],
'debug_level' => 0,
];
$storage_client =
......@@ -925,3 +842,47 @@ function external_entities_regenerate_index_file_finished($success, $results, $o
\Drupal::messenger()->addError($message);
}
}
/**
* Implements hook_form_alter().
*/
function external_entities_form_alter(array &$form, FormStateInterface $form_state, string $form_id) {
$form_object = $form_state->getFormObject();
if (!$form_object instanceof ContentEntityFormInterface) {
return;
}
$entity = $form_object->getEntity();
if (!$entity instanceof ExternalEntityInterface) {
return;
}
// Hide untranslatable fields on non-default translation forms. This is
// done by Drupal core for regular fields, but since our annotation fields
// are computed we have to do it ourselves.
// @see \Drupal\content_translation\ContentTranslationHandler::entityFormSharedElements()
// @see \Drupal\Core\Entity\EntityChangesDetectionTrait::getFieldsToSkipFromTranslationChangesCheck()
// @todo Is this a sign that our annotation fields should be marked as having
// a custom storage instead of being computed?
if ($entity->getExternalEntityType()->isAnnotatable()
&& $entity->isDefaultTranslationAffectedOnly()
&& !$entity->isDefaultTranslation()
) {
$inherited_annotation_fields = $entity
->getExternalEntityType()
->getInheritedAnnotationFields();
foreach ($inherited_annotation_fields as $field_definition) {
$inherited_field_name = ExternalEntityInterface::ANNOTATION_FIELD_PREFIX . $field_definition->getName();
if (empty($form[$inherited_field_name])) {
continue;
}
$inherited_field_definition = $entity
->get($inherited_field_name)
->getFieldDefinition();
if (!$inherited_field_definition->isTranslatable()) {
$form[$inherited_field_name]['#access'] = FALSE;
}
}
}
}
......@@ -6,7 +6,6 @@ label: 'Drupal.org module - JSONAPI'
label_plural: 'Drupal.org modules - JSONAPI'
description: 'Drupal.org modules via JSONAPI.'
content_class: Drupal\external_entities\Entity\ExternalEntity
generate_aliases: true
read_only: false
debug_level: 0
field_mappers:
......@@ -101,7 +100,7 @@ data_aggregator:
http:
headers: 'Accept: application/vnd.api+json'
parameters:
list:
list: null
list_param_mode: query
single:
'filter[drupal_internal__nid]': '{id}'
......
......@@ -6,7 +6,6 @@ label: 'Drupal.org issue - REST'
label_plural: 'Drupal.org issues - REST'
description: 'Drupal.org issues via REST.'
content_class: Drupal\external_entities\Entity\ExternalEntity
generate_aliases: true
read_only: false
debug_level: 0
field_mappers:
......
......@@ -5,3 +5,4 @@ package: External Entities
core_version_requirement: ^9 || ^10 || ^11
dependencies:
- external_entities:external_entities
- pathauto:pathauto
......@@ -5,15 +5,117 @@
* Hooks for external_entities_pathauto.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\external_entities\Entity\ConfigurableExternalEntityTypeInterface;
use Drupal\external_entities\Form\ExternalEntityTypeForm;
use Drupal\external_entities_pathauto\Plugin\pathauto\AliasType\ExternalEntityAliasTypeBase;
/**
* Implements hook_pathauto_alias_types_alter().
*/
function external_entities_pathauto_alias_types_alter(&$types) {
function external_entities_pathauto_pathauto_alias_types_alter(&$types) {
foreach (array_keys($types) as $plugin_id) {
if (!empty($types[$plugin_id]['provider']) && $types[$plugin_id]['provider'] === 'external_entities') {
$types[$plugin_id]['class'] = ExternalEntityAliasTypeBase::class;
}
}
}
/**
* Implements hook_config_schema_info_alter().
*/
function external_entities_pathauto_config_schema_info_alter(&$definitions) {
// Adds 'generate_aliases' property to external entity type config schema.
$definitions['external_entities.external_entity_type.*']['mapping']['generate_aliases'] ??= [
'type' => 'boolean',
'label' => 'Automatically generate aliases',
// Let it be nullable for config saved before enabling the module.
'nullable' => TRUE,
];
}
/**
* Implements hook_form_alter().
*/
function external_entities_pathauto_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// Add config checkbox for 'generate_aliases' setting.
// Only work on external entity type forms.
if ((('external_entity_type_edit_form' == $form_id)
|| ('external_entity_type_add_form' == $form_id))
&& ($form_state->getFormObject() instanceof ExternalEntityTypeForm)
) {
$external_entity_type = $form_state->getFormObject()->getEntity();
// Add alias generation checkbox.
$form['generate_aliases'] = [
'#title' => t('Automatically generate aliases'),
'#type' => 'checkbox',
'#default_value' => $external_entity_type->getThirdPartySetting('external_entities_pathauto', 'generate_aliases'),
'#description' => t('Whether or not to automatically generate aliases for this external entity type.'),
];
$form['#entity_builders'][] = 'external_entities_pathauto_xntt_form_builder';
}
}
/**
* Saves 'generate_aliases' property added to ExternalEntityTypeForm form.
*
* @param string $entity_type
* Entity type.
* @param \Drupal\external_entities\Entity\ConfigurableExternalEntityTypeInterface $entity
* External entity type (config entity).
* @param array &$form
* External entity type config form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Form state.
*/
function external_entities_pathauto_xntt_form_builder(
string $entity_type,
ConfigurableExternalEntityTypeInterface $entity,
array &$form,
FormStateInterface $form_state,
) {
// Property saved as a third party setting.
$entity->setThirdPartySetting(
'external_entities_pathauto',
'generate_aliases',
$form_state->getValue('generate_aliases')
);
}
/**
* Implements hook_entity_storage_load().
*/
function external_entities_pathauto_entity_storage_load(array $entities, $entity_type) {
/** @var \Drupal\external_entities\Entity\ExternalEntity $external_entity_type */
$external_entity_type = \Drupal::entityTypeManager()
->getStorage('external_entity_type')
->load($entity_type);
if (!$external_entity_type) {
return;
}
$generate_aliases = $external_entity_type
->getThirdPartySetting('external_entities_pathauto', 'generate_aliases');
if (!$generate_aliases) {
return;
}
/** @var \Drupal\pathauto\PathautoGeneratorInterface $pathauto_generator */
$pathauto_generator = \Drupal::service('pathauto.generator');
/** @var \Drupal\path_alias\AliasManagerInterface $path_alias_manager */
$path_alias_manager = \Drupal::service('path_alias.manager');
/** @var \Drupal\external_entities\Entity\ExternalEntityInterface $entity */
foreach ($entities as $entity) {
$path = '/' . $entity->toUrl()->getInternalPath();
$alias = $path_alias_manager->getAliasByPath($path, $entity->language()->getId());
if ($alias !== $path) {
continue;
}
// Generate an alias.
$entity->path = $pathauto_generator->updateEntityAlias($entity, 'insert');
}
}
......@@ -8,7 +8,6 @@ description: 'Programmatic external entity type used to import Drupal 7 content.
content_class: Drupal\external_entities\Entity\ExternalEntity
read_only: true
debug_level: 0
generate_aliases: false
field_mappers:
id:
id: generic
......@@ -137,4 +136,4 @@ persistent_cache_max_age: 0
annotation_entity_type_id: null
annotation_bundle_id: null
annotation_field_name: null
inherits_annotation_fields: false
annotation_inherited_fields: { }
......@@ -889,14 +889,14 @@ class XnttStream extends LocalStream {
* {@inheritdoc}
*/
public function getName() {
return $this->t('External files');
return t('External files');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('External files stored anywhere.');
return t('External files stored anywhere.');
}
}
......@@ -129,10 +129,8 @@ function xntt_file_field_entity_preload(array $ids, string $entity_type_id) {
'filename' => $filename,
];
ExternalFile::preCreate($storage, $file_data);
$entities[$id] = ExternalFile::create();
$entities[$id] = ExternalFile::create($file_data);
$entities[$id]->set('fid', $id);
$entities[$id]->setFileUri($file_data['uri']);
$entities[$id]->setFilename($file_data['filename']);
$entities[$id]->setPermanent();
}
}
......
......@@ -2,7 +2,10 @@
namespace Drupal\xntt_views\Entity\Render;
use Drupal\Core\Entity\EntityInterface;
use Drupal\views\Entity\Render\EntityFieldRenderer;
use Drupal\views\Plugin\views\PluginBase;
use Drupal\views\ResultRow;
/**
* Renders entity fields.
......
......@@ -167,6 +167,7 @@ class ExternalEntityField extends EntityField {
if (isset($this->definition['field_name']) && isset($base_fields[$this->definition['field_name']])) {
return $base_fields[$this->definition['field_name']]->getFieldStorageDefinition();
}
throw new \Exception("No field storage definition found for entity type {$this->definition['entity_type']} and field {$this->definition['field_name']} on view {$this->view->storage->id()}");
}
/**
......@@ -335,6 +336,8 @@ class ExternalEntityField extends EntityField {
}
return $this->renderer->render($build);
}
// No items.
return '';
}
/**
......