. */ namespace Fisharebest\Webtrees\Module\BatchUpdate; use Fisharebest\Webtrees\Filter; use Fisharebest\Webtrees\Functions\FunctionsEdit; use Fisharebest\Webtrees\I18N; /** * Class BatchUpdateSearchReplacePlugin Batch Update plugin: search/replace */ class BatchUpdateSearchReplacePlugin extends BatchUpdateBasePlugin { /** @var string Search string */ private $search; /** @var string Replace string */ private $replace; /** @var string simple/wildcards/regex */ private $method; /** @var string Search string, converted to a regex */ private $regex; /** @var string "i" for case insensitive, "" for case sensitive */ private $case; /** @var string Message for bad user parameters */ private $error; /** * User-friendly name for this plugin. * * @return string */ public function getName() { return I18N::translate('Search and replace'); } /** * Description / help-text for this plugin. * * @return string */ public function getDescription() { return /* I18N: Description of the “Search and replace” option of the batch update module */ I18N::translate('Search and replace text, using simple searches or advanced pattern matching.'); } /** * This plugin will update all types of record. * * @return string[] */ public function getRecordTypesToUpdate() { return array('INDI', 'FAM', 'SOUR', 'REPO', 'NOTE', 'OBJE'); } /** * Does this record need updating? * * @param string $xref * @param string $gedrec * * @return bool */ public function doesRecordNeedUpdate($xref, $gedrec) { return !$this->error && preg_match('/(?:' . $this->regex . ')/mu' . $this->case, $gedrec); } /** * Apply any updates to this record * * @param string $xref * @param string $gedrec * * @return string */ public function updateRecord($xref, $gedrec) { // Allow "\n" to indicate a line-feed in replacement text. // Back-references such as $1, $2 are handled automatically. return preg_replace('/' . $this->regex . '/mu' . $this->case, str_replace('\n', "\n", $this->replace), $gedrec); } /** * Process the user-supplied options. */ public function getOptions() { parent::getOptions(); $this->search = Filter::get('search'); $this->replace = Filter::get('replace'); $this->method = Filter::get('method', 'exact|words|wildcards|regex', 'exact'); $this->case = Filter::get('case', 'i'); $this->error = ''; switch ($this->method) { case 'exact': $this->regex = preg_quote($this->search, '/'); break; case 'words': $this->regex = '\b' . preg_quote($this->search, '/') . '\b'; break; case 'wildcards': $this->regex = '\b' . str_replace(array('\*', '\?'), array('.*', '.'), preg_quote($this->search, '/')) . '\b'; break; case 'regex': $this->regex = $this->search; // Check for invalid regular expressions. // A valid regex on a null string returns zero. // An invalid regex on a null string returns false and throws a warning. try { preg_match('/' . $this->search . '/', null); } catch (\ErrorException $ex) { $this->error = '
' . /* I18N: http://en.wikipedia.org/wiki/Regular_expression */ I18N::translate('The regular expression appears to contain an error. It can’t be used.') . '
'; } break; } } /** * Generate a form to ask the user for options. * * @return string */ public function getOptionsForm() { $descriptions = array( 'exact' => I18N::translate('Match the exact text, even if it occurs in the middle of a word.'), 'words' => I18N::translate('Match the exact text, unless it occurs in the middle of a word.'), 'wildcards' => I18N::translate('Use a “?” to match a single character, use “*” to match zero or more characters.'), 'regex' => /* I18N: http://en.wikipedia.org/wiki/Regular_expression */ I18N::translate('Regular expressions are an advanced pattern matching technique.') . '
' . /* I18N: %s is a URL */ I18N::translate('See %s for more information.', 'php.net/manual/regexp.reference.php'), ); return '
' . '' . '
' . '' . '
' . '
' . '' . '
' . '' . '
' . '
' . '' . '
' . '' . '

' . $descriptions[$this->method] . '

' . $this->error . '
' . '
' . '' . '
' . FunctionsEdit::radioButtons('case', array('I' => I18N::translate('no'), 'i' => I18N::translate('yes')), ($this->case ? 'i' : 'I'), 'class="radio-inline" onchange="this.form.submit();"') . '

' . /* I18N: Help text for "Case insensitive" searches */ I18N::translate('Match both upper and lower case letters.') . '

' . '
' . parent::getOptionsForm(); } }