annotate modules/contrib/migrate_plus/src/Plugin/migrate/process/DomStrReplace.php @ 5:12f9dff5fda9 tip

Update to Drupal core 8.7.1
author Chris Cannam
date Thu, 09 May 2019 15:34:47 +0100
parents
children
rev   line source
Chris@5 1 <?php
Chris@5 2
Chris@5 3 namespace Drupal\migrate_plus\Plugin\migrate\process;
Chris@5 4
Chris@5 5 use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
Chris@5 6 use Drupal\migrate\MigrateExecutableInterface;
Chris@5 7 use Drupal\migrate\Row;
Chris@5 8
Chris@5 9 /**
Chris@5 10 * String replacements on a source dom.
Chris@5 11 *
Chris@5 12 * Analogous to str_replace process plugin, but based on a \DOMDocument instead
Chris@5 13 * of a string.
Chris@5 14 * Meant to be used after dom process plugin.
Chris@5 15 *
Chris@5 16 * Available configuration keys:
Chris@5 17 * - mode: What to modify. Possible values:
Chris@5 18 * - attribute: One element attribute.
Chris@5 19 * - expression: XPath query expression that will produce the \DOMNodeList to
Chris@5 20 * walk.
Chris@5 21 * - attribute_options: A map of options related to the attribute mode. Required
Chris@5 22 * when mode is attribute. The keys can be:
Chris@5 23 * - name: Name of the attribute to match and modify.
Chris@5 24 * - search: pattern to match.
Chris@5 25 * - replace: value to replace the searched pattern with.
Chris@5 26 * - regex: Use regular expression replacement.
Chris@5 27 * - case_insensitive: Case insensitive search. Only valid when regex is false.
Chris@5 28 *
Chris@5 29 * Examples:
Chris@5 30 *
Chris@5 31 * @code
Chris@5 32 * process:
Chris@5 33 * 'body/value':
Chris@5 34 * -
Chris@5 35 * plugin: dom
Chris@5 36 * method: import
Chris@5 37 * source: 'body/0/value'
Chris@5 38 * -
Chris@5 39 * plugin: dom_str_replace
Chris@5 40 * mode: attribute
Chris@5 41 * expression: '//a'
Chris@5 42 * attribute_options:
Chris@5 43 * name: href
Chris@5 44 * search: 'foo'
Chris@5 45 * replace: 'bar'
Chris@5 46 * -
Chris@5 47 * plugin: dom_str_replace
Chris@5 48 * mode: attribute
Chris@5 49 * expression: '//a'
Chris@5 50 * attribute_options:
Chris@5 51 * name: href
Chris@5 52 * regex: true
Chris@5 53 * search: '/foo/'
Chris@5 54 * replace: 'bar'
Chris@5 55 * -
Chris@5 56 * plugin: dom
Chris@5 57 * method: export
Chris@5 58 * @endcode
Chris@5 59 *
Chris@5 60 * @MigrateProcessPlugin(
Chris@5 61 * id = "dom_str_replace"
Chris@5 62 * )
Chris@5 63 */
Chris@5 64 class DomStrReplace extends DomProcessBase {
Chris@5 65
Chris@5 66 /**
Chris@5 67 * {@inheritdoc}
Chris@5 68 */
Chris@5 69 public function __construct(array $configuration, $plugin_id, $plugin_definition) {
Chris@5 70 parent::__construct($configuration, $plugin_id, $plugin_definition);
Chris@5 71 $this->configuration += [
Chris@5 72 'case_insensitive' => FALSE,
Chris@5 73 'regex' => FALSE,
Chris@5 74 ];
Chris@5 75 $options_validation = [
Chris@5 76 'expression' => NULL,
Chris@5 77 'mode' => ['attribute'],
Chris@5 78 // @todo Move out once another mode is supported.
Chris@5 79 // @see https://www.drupal.org/project/migrate_plus/issues/3042833
Chris@5 80 'attribute_options' => NULL,
Chris@5 81 'search' => NULL,
Chris@5 82 'replace' => NULL,
Chris@5 83 ];
Chris@5 84 foreach ($options_validation as $option_name => $possible_values) {
Chris@5 85 if (empty($this->configuration[$option_name])) {
Chris@5 86 throw new InvalidPluginDefinitionException(
Chris@5 87 $this->getPluginId(),
Chris@5 88 "Configuration option '$option_name' is required."
Chris@5 89 );
Chris@5 90 }
Chris@5 91 if (!is_null($possible_values) && !in_array($this->configuration[$option_name], $possible_values)) {
Chris@5 92 throw new InvalidPluginDefinitionException(
Chris@5 93 $this->getPluginId(),
Chris@5 94 sprintf(
Chris@5 95 'Configuration option "%s" only accepts the following values: %s.',
Chris@5 96 $option_name,
Chris@5 97 implode(', ', $possible_values)
Chris@5 98 )
Chris@5 99 );
Chris@5 100 }
Chris@5 101 }
Chris@5 102 }
Chris@5 103
Chris@5 104 /**
Chris@5 105 * {@inheritdoc}
Chris@5 106 */
Chris@5 107 public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
Chris@5 108 $this->init($value, $destination_property);
Chris@5 109
Chris@5 110 foreach ($this->xpath->query($this->configuration['expression']) as $html_node) {
Chris@5 111 $subject = $this->getSubject($html_node);
Chris@5 112 if (empty($subject)) {
Chris@5 113 // Could not find subject, skip processing.
Chris@5 114 continue;
Chris@5 115 }
Chris@5 116 $search = $this->getSearch();
Chris@5 117 $replace = $this->getReplace();
Chris@5 118 $this->doReplace($html_node, $search, $replace, $subject);
Chris@5 119 }
Chris@5 120
Chris@5 121 return $this->document;
Chris@5 122 }
Chris@5 123
Chris@5 124 /**
Chris@5 125 * Retrieves the right subject string.
Chris@5 126 *
Chris@5 127 * @param \DOMElement $node
Chris@5 128 * The current element from iteration.
Chris@5 129 *
Chris@5 130 * @return string
Chris@5 131 * The string to use a subject on search.
Chris@5 132 */
Chris@5 133 protected function getSubject(\DOMElement $node) {
Chris@5 134 switch ($this->configuration['mode']) {
Chris@5 135 case 'attribute':
Chris@5 136 return $node->getAttribute($this->configuration['attribute_options']['name']);
Chris@5 137 }
Chris@5 138 }
Chris@5 139
Chris@5 140 /**
Chris@5 141 * Retrieves the right search string based on configuration.
Chris@5 142 *
Chris@5 143 * @return string
Chris@5 144 * The value to be searched.
Chris@5 145 */
Chris@5 146 protected function getSearch() {
Chris@5 147 switch ($this->configuration['mode']) {
Chris@5 148 case 'attribute':
Chris@5 149 return $this->configuration['search'];
Chris@5 150 }
Chris@5 151 }
Chris@5 152
Chris@5 153 /**
Chris@5 154 * Retrieves the right replace string based on configuration.
Chris@5 155 *
Chris@5 156 * @return string
Chris@5 157 * The value to use for replacement.
Chris@5 158 */
Chris@5 159 protected function getReplace() {
Chris@5 160 switch ($this->configuration['mode']) {
Chris@5 161 case 'attribute':
Chris@5 162 return $this->configuration['replace'];
Chris@5 163 }
Chris@5 164 }
Chris@5 165
Chris@5 166 /**
Chris@5 167 * Retrieves the right replace string based on configuration.
Chris@5 168 *
Chris@5 169 * @param \DOMElement $html_node
Chris@5 170 * The current element from iteration.
Chris@5 171 * @param string $search
Chris@5 172 * The search string or pattern.
Chris@5 173 * @param string $replace
Chris@5 174 * The replacement string.
Chris@5 175 * @param string $subject
Chris@5 176 * The string on which to perform the substitution.
Chris@5 177 */
Chris@5 178 protected function doReplace(\DOMElement $html_node, $search, $replace, $subject) {
Chris@5 179 if ($this->configuration['regex']) {
Chris@5 180 $function = 'preg_replace';
Chris@5 181 }
Chris@5 182 elseif ($this->configuration['case_insensitive']) {
Chris@5 183 $function = 'str_ireplace';
Chris@5 184 }
Chris@5 185 else {
Chris@5 186 $function = "str_replace";
Chris@5 187 }
Chris@5 188 $new_subject = $function($search, $replace, $subject);
Chris@5 189 $this->postReplace($html_node, $new_subject);
Chris@5 190 }
Chris@5 191
Chris@5 192 /**
Chris@5 193 * Performs post-replace actions.
Chris@5 194 *
Chris@5 195 * @param \DOMElement $html_node
Chris@5 196 * The current element from iteration.
Chris@5 197 * @param string $new_subject
Chris@5 198 * The new value to use.
Chris@5 199 */
Chris@5 200 protected function postReplace(\DOMElement $html_node, $new_subject) {
Chris@5 201 switch ($this->configuration['mode']) {
Chris@5 202 case 'attribute':
Chris@5 203 $html_node->setAttribute($this->configuration['attribute_options']['name'], $new_subject);
Chris@5 204 }
Chris@5 205 }
Chris@5 206
Chris@5 207 }