Skip to content

Follow up to 16322: Fix non-existent snippet tags being broken up by an @ tag #16682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 184 additions & 17 deletions _build/test/Tests/Model/modParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
*/
namespace MODX\Revolution\Tests\Model;


use MODX\Revolution\modElementPropertySet;
use MODX\Revolution\modPropertySet;
use MODX\Revolution\modSnippet;
use MODX\Revolution\modX;
use MODX\Revolution\MODxTestCase;
use MODX\Revolution\MODxTestHarness;
Expand Down Expand Up @@ -764,23 +766,188 @@ public function providerProcessElementTags() {
],
// tags directly within brackets
// @todo this test fails
// [
// [
// 'processed' => 1,
// 'content' => '<input type="text" name="item[Tag2][name]" />'
// ],
// '[[+tag1:notempty=`<input type="text" name="item[[[+tag2]]][name]" />`]]',
// [
// 'parentTag' => '',
// 'processUncacheable' => true,
// 'removeUnprocessed' => false,
// 'prefix' => '[[',
// 'suffix' => ']]',
// 'tokens' => [],
// 'depth' => 1
// ]
// ],
// [
// [
// 'processed' => 1,
// 'content' => '<input type="text" name="item[Tag2][name]" />'
// ],
// '[[+tag1:notempty=`<input type="text" name="item[[[+tag2]]][name]" />`]]',
// [
// 'parentTag' => '',
// 'processUncacheable' => true,
// 'removeUnprocessed' => false,
// 'prefix' => '[[',
// 'suffix' => ']]',
// 'tokens' => [],
// 'depth' => 1
// ]
// ],

// #16318 parsing tags with @ in the value causes it to break the tag
[
[
'processed' => 1,
'content' => "aaa
[[nonExistentSnippet? &x=`bbb@ccc`]]
ddd
eee"
],
"[[+empty_content:empty=`aaa
[[nonExistentSnippet? &x=`bbb@ccc`]]
ddd
`]]eee",
[
'parentTag' => '',
'processUncacheable' => true,
'removeUnprocessed' => false,
'prefix' => '[[',
'suffix' => ']]',
'tokens' => [],
'depth' => 0
]
]
];
}

/**
* @dataProvider providerPropertySetCall
* @param $content
* @param $expected
* @param $propertySet
* @param $params
* @return void
*/
public function testPropertySetCall($content, $expected, $propertySet, $params)
{
/** @var modPropertySet $set */
$set = $this->modx->newObject(modPropertySet::class);
$set->set('name', 'propset_' . bin2hex(random_bytes(4)));
$set->setProperties($propertySet);
self::assertTrue($set->save());

/** @var modSnippet $set */
$snippet = $this->modx->newObject(modSnippet::class);
$snippet->set('name', 'snippet_' . bin2hex(random_bytes(4)));
$snippet->set('content', '<?php
return $scriptProperties["prop"] ?? "";');
self::assertTrue($snippet->save());

$join = $this->modx->newObject(modElementPropertySet::class);
$join->fromArray([
'element' => $snippet->get('id'),
'element_class' => $snippet->_class,
'property_set' => $set->get('id'),
], '', true);
$join->save();
self::assertTrue($join->save());

$content = str_replace('propSetName', $set->get('name'), $content);
$content = str_replace('snippetName', $snippet->get('name'), $content);

$c = $content;

$this->modx->parser->processElementTags(
$params['parentTag'],
$content,
$params['processUncacheable'],
$params['removeUnprocessed'],
$params['prefix'],
$params['suffix'],
$params['tokens'],
$params['depth']
);

$set->remove();
$snippet->remove();
$join->remove();

$this->assertEquals($expected, $content, "Did not get expected results from parsing {$c}.");
}
public function providerPropertySetCall()
{
// In this test, snippetName and propSetName are replaced with a random string
// for each run
return [
[
'[[snippetName? &prop=`123`]]',
'123',
[],
[
'parentTag' => '',
'processUncacheable' => true,
'removeUnprocessed' => false,
'prefix' => '[[',
'suffix' => ']]',
'tokens' => [],
'depth' => 10
]
],
[
'[[snippetName@propSetName]]',
'123',
[
'prop' => '123',
],
[
'parentTag' => '',
'processUncacheable' => true,
'removeUnprocessed' => false,
'prefix' => '[[',
'suffix' => ']]',
'tokens' => [],
'depth' => 10
]
],
[
'[[snippetName@propSetName? &otherProp=`foo`]]',
'789',
[
'prop' => '789',
],
[
'parentTag' => '',
'processUncacheable' => true,
'removeUnprocessed' => false,
'prefix' => '[[',
'suffix' => ']]',
'tokens' => [],
'depth' => 10
]
],
[
'[[snippetName@propSetName? &prop=`123`]]',
'123',
[
'prop' => '456', // needs to be ignored because &prop is specified as override
],
[
'parentTag' => '',
'processUncacheable' => true,
'removeUnprocessed' => false,
'prefix' => '[[',
'suffix' => ']]',
'tokens' => [],
'depth' => 10
]
],
[
'This is a [[snippetName@propSetName:default=`default value`]]',
'This is a default value',
[
'otherProp' => 'not this one', // props other than the test 'prop' should have no effect on output
],
[
'parentTag' => '',
'processUncacheable' => true,
'removeUnprocessed' => false,
'prefix' => '[[',
'suffix' => ']]',
'tokens' => [],
'depth' => 10
]
],
];

}

/**
Expand Down
30 changes: 17 additions & 13 deletions core/src/Revolution/modElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -726,19 +726,23 @@ public function getPropertySet($setName = null)
{
$propertySet = null;
$name = $this->get('name');
if (strpos($name, '@') !== false) {
$psName = '';
$split = xPDO:: escSplit('@', $name);
if ($split && isset($split[1])) {
$name = $split[0];
$psName = $split[1];
$filters = xPDO:: escSplit(':', $setName);
if ($filters && isset($filters[1]) && !empty($filters[1])) {
$psName = $filters[0];
$name .= ':' . $filters[1];
}
$this->set('name', $name);
}

$startFiltersIndex = strpos($name, ':');

if ($startFiltersIndex !== false) {
$tagStart = mb_substr($name, 0, $startFiltersIndex);
$tagEnd = mb_substr($name, $startFiltersIndex);
} else {
$tagStart = $name;
$tagEnd = '';
}

if (strpos($tagStart, '@') !== false) {
$split = xPDO:: escSplit('@', $tagStart);
$psName = $split[1];

$this->set('name', $split[0] . $tagEnd);

if (!empty($psName)) {
$psObj = $this->xpdo->getObjectGraph(modPropertySet::class, '{"Elements":{}}', [
'Elements.element' => $this->id,
Expand Down
30 changes: 17 additions & 13 deletions core/src/Revolution/modTag.php
Original file line number Diff line number Diff line change
Expand Up @@ -511,19 +511,23 @@ public function getPropertySet($setName = null)
{
$propertySet = null;
$name = $this->get('name');
if (strpos($name, '@') !== false) {
$psName = '';
$split = xPDO:: escSplit('@', $name);
if ($split && isset($split[1])) {
$name = $split[0];
$psName = $split[1];
$filters = xPDO:: escSplit(':', $setName);
if ($filters && isset($filters[1]) && !empty($filters[1])) {
$psName = $filters[0];
$name .= ':' . $filters[1];
}
$this->set('name', $name);
}

$startFiltersIndex = strpos($name, ':');

if ($startFiltersIndex !== false) {
$tagStart = mb_substr($name, 0, $startFiltersIndex);
$tagEnd = mb_substr($name, $startFiltersIndex);
} else {
$tagStart = $name;
$tagEnd = '';
}

if (strpos($tagStart, '@') !== false) {
$split = xPDO:: escSplit('@', $tagStart);
$psName = $split[1];

$this->set('name', $split[0] . $tagEnd);

if (!empty($psName)) {
$psObj = $this->modx->getObject(modPropertySet::class, ['name' => $psName]);
if ($psObj) {
Expand Down
Loading