Skip to content

Instantly share code, notes, and snippets.

@xurizaemon
Last active May 11, 2024 03:42
Show Gist options
  • Save xurizaemon/128a5fe7741e5998aed015460363d919 to your computer and use it in GitHub Desktop.
Save xurizaemon/128a5fe7741e5998aed015460363d919 to your computer and use it in GitHub Desktop.
Drupal ContentEntity source with conditions feature - content_entity_conditions - web/modules/custom/foo_migrate/src/Plugin/migrate/source/ContentEntityWithConditions.php
<?php
namespace Drupal\foo_migrate\Plugin\migrate\source;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_drupal\Plugin\migrate\source\ContentEntity;
/**
* Source plugin to add conditions to Drupal's content_entity source.
*
* This plugin uses the Entity API to export entity data. If the source entity
* type has custom field storage fields or computed fields, this class will need
* to be extended and the new class will need to load/calculate the values for
* those fields.
*
* Available configuration keys:
* - entity_type: The entity type ID of the entities being exported. This is
* calculated dynamically by the deriver so it is only needed if the deriver
* is not utilized, i.e., a custom source plugin.
* - bundle: (optional) If the entity type is bundleable, only return entities
* of this bundle.
* - include_translations: (optional) Indicates if the entity translations
* should be included, defaults to TRUE.
* - add_revision_id: (optional) Indicates if the revision key is added to the
* source IDs, defaults to TRUE.
* - conditions: (optional) Conditions to add to the query. This should be in
* array format with each array item providing values for field, value
* (optional, defaults to NULL) and operator (optional, defaults to '=').
* Defaults to an empty array. For more documentation refer to
* \Drupal\Core\Entity\Query\QueryInterface::condition().
*
* As this plugin adds conditions to the content_entity plugin, usage with
* conditions only is documented here. If you're not using conditions, use
* the content_entity source instead.
*
* Examples:
*
* This will only return nodes of type 'article' where the title is "Fox".
* @code
* source:
* plugin: content_entity_conditions:node
* bundle: article
* conditions:
* -
* field: title
* value: Fox
* @endcode
*
* This will return nodes of type 'resource' where the body contains "<table".
* @code
* source:
* plugin: content_entity:node
* bundle: resource
* conditions:
* -
* field: body.value
* value: '<table'
* operator: CONTAINS
* @endcode
*
* For additional configuration keys, refer to ancestor classes:
* @see \Drupal\migrate_drupal\Plugin\migrate\source\ContentEntity
* @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
*
* @MigrateSource(
* id = "content_entity_conditions",
* source_module = "foo_migrate",
* deriver = "\Drupal\migrate_drupal\Plugin\migrate\source\ContentEntityDeriver",
* )
*/
class ContentEntityWithConditions extends ContentEntity {
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
parent::__construct($configuration + $this->defaultConfiguration, $plugin_id, $plugin_definition, $migration, $entity_type_manager, $entity_field_manager, $entity_type_bundle_info);
// Plugin only supports use with conditions; otherwise use content_entity.
if (!isset($this->configuration['conditions'])) {
throw new \InvalidArgumentException(sprintf("Migration '%s' uses source plugin '%s' with no conditions.", $migration->id(), $migration->getSourceConfiguration()['plugin']));
}
// Validate 'conditions' configuration key.
foreach ($this->configuration['conditions'] as $condition) {
if (!is_array($condition) || !isset($condition['field'])) {
throw new \InvalidArgumentException("Each 'conditions' array item must be an array including field, value (optional), and operator (optional) keys.");
}
}
}
/**
* {@inheritdoc}
*/
public function query() {
$query = parent::query();
// Apply configured conditions.
foreach ($this->configuration['conditions'] as $condition) {
$query->condition($condition['field'], $condition['value'] ?? NULL, $condition['operator'] ?? '=');
}
return $query;
}
}
@benjifisher
Copy link

I am sorry if this suggestion is half-baked, but can you start with parent::query() and then add the conditions? Or is there a reason for completely rewriting the query() method?

@xurizaemon
Copy link
Author

xurizaemon commented Apr 14, 2023

That was the right thing to do, thanks Benji! Updated gist.

@mstrelan
Copy link

Thanks for this @xurizaemon

Minor issue in the docs, I guess content_entity:node should be content_entity_conditions:node.

@xurizaemon
Copy link
Author

Thanks @mstrelan !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment