DomApplyStyles.php in Migrate Plus 8.5
File
src/Plugin/migrate/process/DomApplyStyles.phpView source
<?php
namespace Drupal\migrate_plus\Plugin\migrate\process;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Apply Editor styles to configured elements.
*
* Replace HTML elements with elements and classes specified in the Styles menu
* of the WYSIWYG editor.
*
* Available configuration keys:
* - format: the text format to inspect for style options (optional,
* defaults to 'basic_html').
* - rules: an array of keyed arrays, with the following keys:
* - xpath: an XPath expression for the elements to replace.
* - style: the label of the item in the Styles menu to use.
* - depth: the number of parent elements to remove (optional, defaults to 0).
*
* Example:
*
* @code
* process:
* 'body/value':
* -
* plugin: dom
* method: import
* source: 'body/0/value'
* -
* plugin: dom_apply_styles
* format: full_html
* rules:
* -
* xpath: '//b'
* style: Bold
* -
* xpath: '//span/i'
* style: Italic
* depth: 1
* -
* plugin: dom
* method: export
* @endcode
*
* This will replace <b>...</b> with whatever style is labeled "Bold" in the
* Full HTML text format, perhaps <strong class="foo">...</strong>.
* It will also replace <span><i>...</i></span> with the style labeled "Italic"
* in that text format, perhaps <em class="foo bar">...</em>.
* You may get unexpected results if there is anything between the two opening
* tags or between the two closing tags. That is, the code assumes that
* '<span><i>' is closed with '</i></span>' exactly.
*
* @MigrateProcessPlugin(
* id = "dom_apply_styles"
* )
*/
class DomApplyStyles extends DomProcessBase implements ContainerFactoryPluginInterface {
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactory
*/
protected $configFactory;
/**
* Array of styles from the WYSIWYG editor.
*
* @var array
*/
protected $styles = [];
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactory $config_factory) {
$configuration += [
'format' => 'basic_html',
];
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->configFactory = $config_factory;
$this
->setStyles($configuration['format']);
$this
->validateRules();
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('config.factory'));
}
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$this
->init($value, $destination_property);
foreach ($this->configuration['rules'] as $rule) {
$this
->apply($rule);
}
return $this->document;
}
/**
* Retrieve the list of styles based on configuration.
*
* The styles configuration is a string: styles are separated by "\r\n", and
* each one has the format 'element(\.class)*|label'.
* Convert this to an array with 'label' => 'element.class', and save as
* $this->styles.
*
* @param string $format
* The text format from which to get configured styles.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
*/
protected function setStyles($format) {
if (empty($format) || !is_string($format)) {
$message = 'The "format" option must be a non-empty string.';
throw new InvalidPluginDefinitionException($this
->getPluginId(), $message);
}
$editor_styles = $this->configFactory
->get("editor.editor.{$format}")
->get('settings.plugins.stylescombo.styles');
foreach (explode("\r\n", $editor_styles) as $rule) {
if (preg_match('/(.*)\\|(.*)/', $rule, $matches)) {
$this->styles[$matches[2]] = $matches[1];
}
}
}
/**
* Validate the configured rules.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
*/
protected function validateRules() {
if (!array_key_exists('rules', $this->configuration) || !is_array($this->configuration['rules'])) {
$message = 'The "rules" option must be an array.';
throw new InvalidPluginDefinitionException($this
->getPluginId(), $message);
}
foreach ($this->configuration['rules'] as $rule) {
if (empty($rule['xpath']) || empty($rule['style'])) {
$message = 'The "xpath" and "style" options are required for each rule.';
throw new InvalidPluginDefinitionException($this
->getPluginId(), $message);
}
if (empty($this->styles[$rule['style']])) {
$message = sprintf('The style "%s" is not defined.', $rule['style']);
throw new InvalidPluginDefinitionException($this
->getPluginId(), $message);
}
}
}
/**
* Apply a rule to the document.
*
* Search $this->document for elements matching 'xpath' and replace them with
* the HTML elements and classes in $this->styles specified by 'style'.
* If 'depth' is positive, then replace additional parent elements as well.
*
* @param string[] $rule
* An array with keys 'xpath', 'style', and (optional) 'depth'.
*/
protected function apply(array $rule) {
// An entry in $this->styles has the format element(\.class)*: for example,
// 'p' or 'a.button' or 'div.col-xs-6.col-md-4'.
// @see setStyles()
[
$element,
$classes,
] = explode('.', $this->styles[$rule['style']] . '.', 2);
$classes = trim(str_replace('.', ' ', $classes));
foreach ($this->xpath
->query($rule['xpath']) as $node) {
$new_node = $this->document
->createElement($element);
foreach ($node->childNodes as $child) {
$new_node
->appendChild($child
->cloneNode(TRUE));
}
if ($classes) {
$new_node
->setAttribute('class', $classes);
}
$old_node = $node;
if (!empty($rule['depth'])) {
for ($i = 0; $i < $rule['depth']; $i++) {
$old_node = $old_node->parentNode;
}
}
$old_node->parentNode
->replaceChild($new_node, $old_node);
}
}
}
Classes
Name![]() |
Description |
---|---|
DomApplyStyles | Apply Editor styles to configured elements. |