4

I just making an upgrade script for replacing all the MODX snippet tags to a newer format:

Old one: [~123~]

New one: [[~123]]

(of course, 123 - it is an example — there are a lot of different numbers)

Also I wanted to replace all the custom old snippets to a newer ones:

Old snippet format:

[!MySnippetName? &param1=`value1` &param2=`value2` !]

New one:

[[!MySnippetName? &param1=`value1` &param2=`value2` ]]

(of course, &param1=value1 &param2=value2 is just an example and it is different in real snippets)

How to use a preg_replace function to make a global replacements? I supposed to create like this:

$doc[ 'content' ] = $this->preg_replace_all(
        array(
                '/\[~([0-9]+)~\]/',
                '\[!LatestUpdates(.*)!\]',
                '\[!ArticleSummary(.*)!\]',
            ), array(
                '[[~\1]]',
                '[[!LatestUpdates\1]]',
                '[[!ArticleSummary\1]]',
            ),
            $doc[ 'content' ]
        );

preg_replace_all function:

private function preg_replace_all( $find, $replacement, $s )
{
    while(preg_match($find, $s)) {
        $s = preg_replace($find, $replacement, $s);
    }
    return $s;
}

But it doesn't work. Please help to figure out the problem. Thanks in advance.

curveball
  • 4,320
  • 15
  • 39
  • 49
Serhii Matrunchyk
  • 9,083
  • 6
  • 34
  • 47

2 Answers2

7

The preg_replace function performs already a global replacement and since only matching substrings are replaced, you don't need to test the existence of these substrings with preg_match.

You can reduce the three patterns to only one pattern:

$pattern = '/\[(?|(!LatestUpdates|!ArticleSummary)(.*?)!]|(~)([0-9]+)~])/';
$replacement = '[[$1$2]]';
$doc['content'] = preg_replace($pattern, $replacement, $doc['content']);

This pattern use the branch reset feature that allows capture groups to have the same number in each alternative.

If it is possible (if it doesn't change tags you want to preserve), you can do the same with strtr:

$doc['content'] = strtr($doc['content'], array('[!'=>'[[!', '[~'=>'[[~', '~]'=>']]', '!]'=>']]'));

Note that if you can use it, don't hesitate since this way is much faster.

Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
  • I'd like to use strtr, but I'm afraid of accidental extra replacement. But thanks for the 3-line regexp solution. I didn't know how to substitute capture groups in preg_replace, but I see that it's easier than I thought. – Serhii Matrunchyk Nov 02 '14 at 18:36
  • 1
    @SergiyMatrunchyk: The branch reset feature is indeed a very handy feature. But if you want to perform more complicated replacement, take a look to the `preg_replace_callback` function. About "accidental extra replacement", keep in mind that the most of the time, template systems are designed to avoid ambiguities. – Casimir et Hippolyte Nov 02 '14 at 18:48
1

Why are you using PHP to do this - have you written a plugin to convert all the Evolution tags to Revolution format whenever a page is parsed?

If that's the case, this is inefficient and it would be better to replace all the tags in the database, where the content, templates, chunks, etc are stored.

You could do that easily using a query like this:

UPDATE modx_site_content SET content = REPLACE(content, '[!', '[[!');

You would repeat this for all the other open and close tags, and in the other database tables.

Backup your database before attempting this...

okyanet
  • 3,106
  • 1
  • 22
  • 16