Skip to content

Commit 86bca45

Browse files
author
Oleksii Korshenko
committed
Merge branch 'MAGETWO-53121-502-Bad-Gateway' into merged-prs
2 parents b7c5930 + 5965448 commit 86bca45

File tree

27 files changed

+943
-218
lines changed

27 files changed

+943
-218
lines changed

app/code/Magento/Backup/Model/Fs/Collection.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,10 @@ protected function _generateRow($filename)
110110
$row[$key] = $value;
111111
}
112112
$row['size'] = $this->_varDirectory->stat($this->_varDirectory->getRelativePath($filename))['size'];
113-
$row['id'] = $row['time'] . '_' . $row['type'];
113+
if (isset($row['display_name']) && $row['display_name'] == '') {
114+
$row['display_name'] = 'WebSetupWizard';
115+
}
116+
$row['id'] = $row['time'] . '_' . $row['type'] . (isset($row['display_name']) ? $row['display_name'] : '');
114117
return $row;
115118
}
116119
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Theme\Model\Design\Config;
7+
8+
use \Magento\Framework\Exception\LocalizedException;
9+
use \Magento\Theme\Api\Data\DesignConfigInterface;
10+
use \Magento\Theme\Api\Data\DesignConfigDataInterface;
11+
use \Magento\Framework\Mail\TemplateInterfaceFactory as TemplateFactory;
12+
use \Magento\Framework\Filter\Template;
13+
use \Magento\Framework\Filter\Template\Tokenizer\Parameter as ParameterTokenizer;
14+
15+
/**
16+
* Design configuration validator
17+
*/
18+
class Validator
19+
{
20+
/**
21+
* @var string[]
22+
*/
23+
private $fields = [];
24+
25+
/**
26+
* @var TemplateFactory
27+
*/
28+
private $templateFactory;
29+
30+
/**
31+
* Initialize dependencies.
32+
*
33+
* @param TemplateFactory $templateFactory
34+
* @param string[] $fields
35+
*/
36+
public function __construct(TemplateFactory $templateFactory, $fields = [])
37+
{
38+
$this->templateFactory = $templateFactory;
39+
$this->fields = $fields;
40+
}
41+
42+
/**
43+
* Validate if design configuration has recursive references
44+
*
45+
* @param DesignConfigInterface $designConfig
46+
*
47+
* @throws LocalizedException
48+
* @return void
49+
*/
50+
public function validate(DesignConfigInterface $designConfig)
51+
{
52+
/** @var DesignConfigDataInterface[] $designConfigData */
53+
$designConfigData = $designConfig->getExtensionAttributes()->getDesignConfigData();
54+
$elements = [];
55+
foreach ($designConfigData as $designElement) {
56+
if (!in_array($designElement->getFieldConfig()['field'], $this->fields)) {
57+
continue;
58+
}
59+
/* Save mapping between field names and config paths */
60+
$elements[$designElement->getFieldConfig()['field']] = [
61+
'config_path' => $designElement->getPath(),
62+
'value' => $designElement->getValue()
63+
];
64+
}
65+
66+
foreach ($elements as $name => $data) {
67+
// Load template object by configured template id
68+
$template = $this->templateFactory->create();
69+
$template->emulateDesign($designConfig->getScopeId());
70+
$templateId = $data['value'];
71+
if (is_numeric($templateId)) {
72+
$template->load($templateId);
73+
} else {
74+
$template->loadDefault($templateId);
75+
}
76+
$text = $template->getTemplateText();
77+
$template->revertDesign();
78+
// Check if template body has a reference to the same config path
79+
if (preg_match_all(Template::CONSTRUCTION_TEMPLATE_PATTERN, $text, $constructions, PREG_SET_ORDER)) {
80+
foreach ($constructions as $construction) {
81+
$configPath = isset($construction[2]) ? $construction[2] : '';
82+
$params = $this->getParameters($configPath);
83+
if (isset($params['config_path']) && $params['config_path'] == $data['config_path']) {
84+
throw new LocalizedException(
85+
__(
86+
"Incorrect configuration for %templateName. Template body has a reference to itself",
87+
["templateName" => $name]
88+
)
89+
);
90+
};
91+
}
92+
}
93+
}
94+
}
95+
96+
/**
97+
* Return associative array of parameters.
98+
*
99+
* @param string $value raw parameters
100+
* @return array
101+
*/
102+
private function getParameters($value)
103+
{
104+
$tokenizer = new ParameterTokenizer();
105+
$tokenizer->setString($value);
106+
$params = $tokenizer->tokenize();
107+
return $params;
108+
}
109+
}

app/code/Magento/Theme/Model/DesignConfigRepository.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ class DesignConfigRepository implements DesignConfigRepositoryInterface
2424
/** @var ConfigStorage */
2525
protected $configStorage;
2626

27+
/**
28+
* Design config validator
29+
*
30+
* @var \Magento\Theme\Model\Design\Config\Validator
31+
*/
32+
private $validator;
33+
2734
/**
2835
* @param ConfigStorage $configStorage
2936
* @param ReinitableConfigInterface $reinitableConfig
@@ -39,6 +46,23 @@ public function __construct(
3946
$this->configStorage = $configStorage;
4047
}
4148

49+
/**
50+
* Get config validator
51+
*
52+
* @return Design\Config\Validator
53+
*
54+
* @deprecated
55+
*/
56+
private function getValidator()
57+
{
58+
if (null === $this->validator) {
59+
$this->validator =\Magento\Framework\App\ObjectManager::getInstance()->get(
60+
\Magento\Theme\Model\Design\Config\Validator::class
61+
);
62+
}
63+
return $this->validator;
64+
}
65+
4266
/**
4367
* @inheritDoc
4468
*/
@@ -58,6 +82,8 @@ public function save(DesignConfigInterface $designConfig)
5882
throw new LocalizedException(__('Can not save empty config'));
5983
}
6084

85+
$this->getValidator()->validate($designConfig);
86+
6187
$this->configStorage->save($designConfig);
6288
$this->reinitableConfig->reinit();
6389
$this->reindexGrid();
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Theme\Test\Unit\Model\Config;
7+
8+
/**
9+
* Class ValidatorTest to test \Magento\Theme\Model\Design\Config\Validator
10+
*/
11+
class ValidatorTest extends \PHPUnit_Framework_TestCase
12+
{
13+
/**
14+
* @var \Magento\Theme\Model\Design\Config\Validator
15+
*/
16+
private $model;
17+
18+
/**
19+
* @var \Magento\Framework\Mail\TemplateInterfaceFactory
20+
*/
21+
private $templateFactoryMock;
22+
23+
protected function setUp()
24+
{
25+
$this->templateFactoryMock = $this->getMockBuilder(\Magento\Framework\Mail\TemplateInterfaceFactory::class)
26+
->disableOriginalConstructor()
27+
->setMethods(['create'])
28+
->getMock();
29+
30+
$objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
31+
$this->model = $objectManagerHelper->getObject(
32+
\Magento\Theme\Model\Design\Config\Validator::class,
33+
[
34+
"templateFactory" => $this->templateFactoryMock,
35+
"fields" => ["email_header_template", "no_reference"]
36+
]
37+
);
38+
}
39+
40+
/**
41+
* @expectedException \Magento\Framework\Exception\LocalizedException
42+
* @expectedExceptionMessage Incorrect configuration for email_header_template. Template body has a reference to
43+
*/
44+
public function testValidateHasRecursiveReference()
45+
{
46+
$fieldConfig = [
47+
'path' => 'design/email/header_template',
48+
'fieldset' => 'other_settings/email',
49+
'field' => 'email_header_template'
50+
];
51+
52+
$designConfigMock = $this->getMockBuilder(\Magento\Theme\Api\Data\DesignConfigInterface::class)
53+
->getMock();
54+
$designConfigExtensionMock =
55+
$this->getMockBuilder(\Magento\Theme\Api\Data\DesignConfigExtensionInterface::class)
56+
->setMethods(['getDesignConfigData'])
57+
->getMock();
58+
$designElementMock = $this->getMockBuilder(\Magento\Theme\Model\Data\Design\Config\Data::class)
59+
->disableOriginalConstructor()
60+
->getMock();
61+
62+
$designConfigMock->expects($this->once())
63+
->method('getExtensionAttributes')
64+
->willReturn($designConfigExtensionMock);
65+
$designConfigExtensionMock->expects($this->once())
66+
->method('getDesignConfigData')
67+
->willReturn([$designElementMock]);
68+
$designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig);
69+
$designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']);
70+
$designElementMock->expects($this->once())->method('getValue')->willReturn($fieldConfig['field']);
71+
72+
$templateMock = $this->getMockBuilder(\Magento\Email\Model\TemplateInterface::class)
73+
->setMethods(['getTemplateText', 'emulateDesign', 'loadDefault', 'revertDesign'])
74+
->getMock();
75+
76+
$this->templateFactoryMock->expects($this->once())->method('create')->willReturn($templateMock);
77+
$templateMock->expects($this->once())->method('getTemplateText')->willReturn(
78+
file_get_contents(__DIR__ . '/_files/template_fixture.html')
79+
);
80+
81+
$this->model->validate($designConfigMock);
82+
}
83+
84+
public function testValidateNoRecursiveReference()
85+
{
86+
$fieldConfig = [
87+
'path' => 'no/reference',
88+
'fieldset' => 'no/reference',
89+
'field' => 'no_reference'
90+
];
91+
92+
$designConfigMock = $this->getMockBuilder(\Magento\Theme\Api\Data\DesignConfigInterface::class)
93+
->getMock();
94+
$designConfigExtensionMock =
95+
$this->getMockBuilder(\Magento\Theme\Api\Data\DesignConfigExtensionInterface::class)
96+
->setMethods(['getDesignConfigData'])
97+
->getMock();
98+
$designElementMock = $this->getMockBuilder(\Magento\Theme\Model\Data\Design\Config\Data::class)
99+
->disableOriginalConstructor()
100+
->getMock();
101+
102+
$designConfigMock->expects($this->once())
103+
->method('getExtensionAttributes')
104+
->willReturn($designConfigExtensionMock);
105+
$designConfigExtensionMock->expects($this->once())
106+
->method('getDesignConfigData')
107+
->willReturn([$designElementMock]);
108+
$designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig);
109+
$designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']);
110+
$designElementMock->expects($this->once())->method('getValue')->willReturn($fieldConfig['field']);
111+
112+
$templateMock = $this->getMockBuilder(\Magento\Email\Model\TemplateInterface::class)
113+
->setMethods(['getTemplateText', 'emulateDesign', 'loadDefault', 'revertDesign'])
114+
->getMock();
115+
116+
$this->templateFactoryMock->expects($this->once())->method('create')->willReturn($templateMock);
117+
$templateMock->expects($this->once())->method('getTemplateText')->willReturn(
118+
file_get_contents(__DIR__ . '/_files/template_fixture.html')
119+
);
120+
121+
$this->model->validate($designConfigMock);
122+
}
123+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{{template config_path="design/email/header_template"}}
2+
3+
<p class="greeting">{{trans "%name," name=$customer.name}}</p>
4+
<p>{{trans "Welcome to %store_name." store_name=$store.getFrontendName()}}</p>
5+
<p>
6+
{{trans
7+
'To sign in to our site, use these credentials during checkout or on the <a href="%customer_url">My Account</a> page:'
8+
9+
customer_url=$this.getUrl($store,'customer/account/',[_nosid:1])
10+
|raw}}
11+
</p>
12+
<ul>
13+
<li><strong>{{trans "Email:"}}</strong> {{var customer.email}}</li>
14+
<li><strong>{{trans "Password:"}}</strong> <em>{{trans "Password you set when creating account"}}</em></li>
15+
</ul>
16+
<p>
17+
{{trans
18+
'Forgot your account password? Click <a href="%reset_url">here</a> to reset it.'
19+
20+
reset_url="$this.getUrl($store,'customer/account/createPassword/',[_query:[id:$customer.id,token:$customer.rp_token],_nosid:1])"
21+
|raw}}
22+
</p>
23+
<p>{{trans "When you sign in to your account, you will be able to:"}}</p>
24+
<ul>
25+
<li>{{trans "Proceed through checkout faster"}}</li>
26+
<li>{{trans "Check the status of orders"}}</li>
27+
<li>{{trans "View past orders"}}</li>
28+
<li>{{trans "Store alternative addresses (for shipping to multiple family members and friends)"}}</li>
29+
</ul>
30+
31+
{{template config_path="design/email/footer_template"}}

app/code/Magento/Theme/Test/Unit/Model/DesignConfigRepositoryTest.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use Magento\Theme\Model\Data\Design\Config;
99
use Magento\Theme\Model\DesignConfigRepository;
10+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
1011

1112
class DesignConfigRepositoryTest extends \PHPUnit_Framework_TestCase
1213
{
@@ -34,6 +35,11 @@ class DesignConfigRepositoryTest extends \PHPUnit_Framework_TestCase
3435
/** @var DesignConfigRepository */
3536
protected $repository;
3637

38+
/**
39+
* @var \PHPUnit_Framework_MockObject_MockObject
40+
*/
41+
protected $validator;
42+
3743
public function setUp()
3844
{
3945
$this->configStorage = $this->getMock('Magento\Theme\Model\Design\Config\Storage', [], [], '', false);
@@ -71,10 +77,24 @@ public function setUp()
7177
'',
7278
false
7379
);
74-
$this->repository = new DesignConfigRepository(
75-
$this->configStorage,
76-
$this->reinitableConfig,
77-
$this->indexerRegistry
80+
81+
$this->validator = $this->getMock(
82+
\Magento\Theme\Model\Design\Config\Validator::class,
83+
[],
84+
[],
85+
'',
86+
false,
87+
false
88+
);
89+
$objectManagerHelper = new ObjectManager($this);
90+
$this->repository = $objectManagerHelper->getObject(
91+
DesignConfigRepository::class,
92+
[
93+
'configStorage' => $this->configStorage,
94+
'reinitableConfig' => $this->reinitableConfig,
95+
'indexerRegistry' => $this->indexerRegistry,
96+
'validator' => $this->validator
97+
]
7898
);
7999
}
80100

@@ -97,6 +117,7 @@ public function testSave()
97117
->willReturn($this->indexer);
98118
$this->indexer->expects($this->once())
99119
->method('reindexAll');
120+
$this->validator->expects($this->once())->method('validate')->with($this->designConfig);
100121
$this->assertSame($this->designConfig, $this->repository->save($this->designConfig));
101122
}
102123

app/code/Magento/Theme/etc/adminhtml/di.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,12 @@
3333
</argument>
3434
</arguments>
3535
</type>
36+
<type name="Magento\Theme\Model\Design\Config\Validator">
37+
<arguments>
38+
<argument name="fields" xsi:type="array">
39+
<item name="header" xsi:type="string">email_header_template</item>
40+
<item name="footer" xsi:type="string">email_footer_template</item>
41+
</argument>
42+
</arguments>
43+
</type>
3644
</config>

0 commit comments

Comments
 (0)