Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -3,93 +3,134 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

declare(strict_types=1);

namespace Magento\Translation\Model;

class InlineParserTest extends \PHPUnit\Framework\TestCase
use Magento\Framework\App\Config\MutableScopeConfigInterface;
use Magento\Framework\App\State;
use Magento\Framework\Translate\Inline;
use Magento\Framework\App\Area;
use Magento\Store\Model\ScopeInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\Translation\Model\Inline\Parser;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

/**
* Test for \Magento\Translation\Model\Inline\Parser.
*/
class InlineParserTest extends TestCase
{
private const STUB_STORE = 'default';
private const XML_PATH_TRANSLATE_INLINE_ACTIVE = 'dev/translate_inline/active';

/**
* @var \Magento\Translation\Model\Inline\Parser
* @var Parser
*/
protected $_inlineParser;

/** @var string */
protected $_storeId = 'default';
private $model;

/**
* @inheritDoc
*/
protected function setUp(): void
{
/** @var $inline \Magento\Framework\Translate\Inline */
$inline = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
->create(\Magento\Framework\Translate\Inline::class);
$this->_inlineParser = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
\Magento\Translation\Model\Inline\Parser::class,
['translateInline' => $inline]
);
/* Called getConfig as workaround for setConfig bug */
\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
\Magento\Store\Model\StoreManagerInterface::class
)->getStore(
$this->_storeId
)->getConfig(
'dev/translate_inline/active'
);
\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
\Magento\Framework\App\Config\MutableScopeConfigInterface::class
)->setValue(
'dev/translate_inline/active',
true,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
$this->_storeId
);
$inline = Bootstrap::getObjectManager()->create(Inline::class);
$this->model = Bootstrap::getObjectManager()->create(Parser::class, ['translateInline' => $inline]);
Bootstrap::getObjectManager()->get(MutableScopeConfigInterface::class)
->setValue(self::XML_PATH_TRANSLATE_INLINE_ACTIVE, true, ScopeInterface::SCOPE_STORE, self::STUB_STORE);
}

/**
* Process ajax post test
*
* @dataProvider processAjaxPostDataProvider
*
* @param string $originalText
* @param string $translatedText
* @param string $area
* @param bool|null $isPerStore
* @return void
*/
public function testProcessAjaxPost($originalText, $translatedText, $isPerStore = null)
{
public function testProcessAjaxPost(
string $originalText,
string $translatedText,
string $area,
?bool $isPerStore = null
): void {
Bootstrap::getObjectManager()->get(State::class)
->setAreaCode($area);

$inputArray = [['original' => $originalText, 'custom' => $translatedText]];
if ($isPerStore !== null) {
$inputArray[0]['perstore'] = $isPerStore;
}
$this->_inlineParser->processAjaxPost($inputArray);
$this->model->processAjaxPost($inputArray);

$model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
\Magento\Translation\Model\StringUtils::class
);
$model = Bootstrap::getObjectManager()->create(StringUtils::class);
$model->load($originalText);

try {
$this->assertEquals($translatedText, $model->getTranslate());
$model->delete();
} catch (\Exception $e) {
$model->delete();
\Magento\TestFramework\Helper\Bootstrap::getObjectManager()
->get(\Psr\Log\LoggerInterface::class)
Bootstrap::getObjectManager()->get(LoggerInterface::class)
->critical($e);
}
}

/**
* Data provider for testProcessAjaxPost
*
* @return array
*/
public function processAjaxPostDataProvider()
public function processAjaxPostDataProvider(): array
{
return [
['original text 1', 'translated text 1'],
['original text 2', 'translated text 2', true]
['original text 1', 'translated text 1', Area::AREA_ADMINHTML],
['original text 1', 'translated text 1', Area::AREA_FRONTEND],
['original text 2', 'translated text 2', Area::AREA_ADMINHTML, true],
['original text 2', 'translated text 2', Area::AREA_FRONTEND, true],
];
}

public function testSetGetIsJson()
/**
* Set get is json test
*
* @dataProvider allowedAreasDataProvider
*
* @param string $area
* @return void
*/
public function testSetGetIsJson(string $area): void
{
$isJsonProperty = new \ReflectionProperty(get_class($this->_inlineParser), '_isJson');
Bootstrap::getObjectManager()->get(State::class)
->setAreaCode($area);

$isJsonProperty = new \ReflectionProperty(get_class($this->model), '_isJson');
$isJsonProperty->setAccessible(true);

$this->assertFalse($isJsonProperty->getValue($this->_inlineParser));
$this->assertFalse($isJsonProperty->getValue($this->model));

$setIsJsonMethod = new \ReflectionMethod($this->_inlineParser, 'setIsJson');
$setIsJsonMethod = new \ReflectionMethod($this->model, 'setIsJson');
$setIsJsonMethod->setAccessible(true);
$setIsJsonMethod->invoke($this->_inlineParser, true);
$setIsJsonMethod->invoke($this->model, true);

$this->assertTrue($isJsonProperty->getValue($this->_inlineParser));
$this->assertTrue($isJsonProperty->getValue($this->model));
}

/**
* Data provider for testSetGetIsJson
*
* @return array
*/
public function allowedAreasDataProvider(): array
{
return [
[Area::AREA_ADMINHTML],
[Area::AREA_FRONTEND]
];
}
}
111 changes: 76 additions & 35 deletions lib/internal/Magento/Framework/Translate/Inline.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,24 @@

namespace Magento\Framework\Translate;

class Inline implements \Magento\Framework\Translate\InlineInterface
use Magento\Framework\App\Area;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\ScopeInterface;
use Magento\Framework\App\ScopeResolverInterface;
use Magento\Framework\App\State;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Translate\Inline\ConfigInterface;
use Magento\Framework\Translate\Inline\ParserInterface;
use Magento\Framework\Translate\Inline\StateInterface;
use Magento\Framework\UrlInterface;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\LayoutInterface;

/**
* Translate Inline Class
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Inline implements InlineInterface
{
/**
* Indicator to hold state of whether inline translation is allowed
Expand All @@ -18,7 +35,7 @@ class Inline implements \Magento\Framework\Translate\InlineInterface
protected $isAllowed;

/**
* @var \Magento\Framework\Translate\Inline\ParserInterface
* @var ParserInterface
*/
protected $parser;

Expand All @@ -30,22 +47,22 @@ class Inline implements \Magento\Framework\Translate\InlineInterface
protected $isScriptInserted = false;

/**
* @var \Magento\Framework\UrlInterface
* @var UrlInterface
*/
protected $url;

/**
* @var \Magento\Framework\View\LayoutInterface
* @var LayoutInterface
*/
protected $layout;

/**
* @var \Magento\Framework\Translate\Inline\ConfigInterface
* @var ConfigInterface
*/
protected $config;

/**
* @var \Magento\Framework\App\ScopeResolverInterface
* @var ScopeResolverInterface
*/
protected $scopeResolver;

Expand All @@ -70,28 +87,39 @@ class Inline implements \Magento\Framework\Translate\InlineInterface
protected $state;

/**
* Initialize inline translation model
*
* @param \Magento\Framework\App\ScopeResolverInterface $scopeResolver
* @param \Magento\Framework\UrlInterface $url
* @param \Magento\Framework\View\LayoutInterface $layout
* @var array
*/
private $allowedAreas = [Area::AREA_FRONTEND, Area::AREA_ADMINHTML];

/**
* @var State
*/
private $appState;

/**
* @param ScopeResolverInterface $scopeResolver
* @param UrlInterface $url
* @param LayoutInterface $layout
* @param Inline\ConfigInterface $config
* @param Inline\ParserInterface $parser
* @param Inline\StateInterface $state
* @param string $templateFileName
* @param string $translatorRoute
* @param null $scope
* @param string|null $scope
* @param State|null $appState
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Framework\App\ScopeResolverInterface $scopeResolver,
\Magento\Framework\UrlInterface $url,
\Magento\Framework\View\LayoutInterface $layout,
\Magento\Framework\Translate\Inline\ConfigInterface $config,
\Magento\Framework\Translate\Inline\ParserInterface $parser,
\Magento\Framework\Translate\Inline\StateInterface $state,
ScopeResolverInterface $scopeResolver,
UrlInterface $url,
LayoutInterface $layout,
ConfigInterface $config,
ParserInterface $parser,
StateInterface $state,
$templateFileName = '',
$translatorRoute = '',
$scope = null
$scope = null,
?State $appState = null
) {
$this->scopeResolver = $scopeResolver;
$this->url = $url;
Expand All @@ -102,6 +130,7 @@ public function __construct(
$this->templateFileName = $templateFileName;
$this->translatorRoute = $translatorRoute;
$this->scope = $scope;
$this->appState = $appState ?: ObjectManager::getInstance()->get(State::class);
}

/**
Expand All @@ -112,12 +141,13 @@ public function __construct(
public function isAllowed()
{
if ($this->isAllowed === null) {
if (!$this->scope instanceof \Magento\Framework\App\ScopeInterface) {
$scope = $this->scopeResolver->getScope($this->scope);
}
$scope = $this->scope instanceof ScopeInterface ? null : $this->scopeResolver->getScope($this->scope);

$this->isAllowed = $this->config->isActive($scope)
&& $this->config->isDevAllowed($scope);
&& $this->config->isDevAllowed($scope)
&& $this->isAreaAllowed();
}

return $this->state->isEnabled() && $this->isAllowed;
}

Expand All @@ -134,7 +164,7 @@ public function getParser()
/**
* Replace translation templates with HTML fragments
*
* @param array|string &$body
* @param array|string $body
* @param bool $isJson
* @return $this
*/
Expand Down Expand Up @@ -189,7 +219,9 @@ protected function addInlineScript()
return;
}
if (!$this->isScriptInserted) {
$this->getParser()->setContent(str_ireplace('</body>', $this->getInlineScript() . '</body>', $content));
$this->getParser()->setContent(
str_ireplace('</body>', $this->getInlineScript() . '</body>', $content)
);
$this->isScriptInserted = true;
}
}
Expand All @@ -204,8 +236,8 @@ protected function addInlineScript()
*/
protected function getInlineScript()
{
/** @var $block \Magento\Framework\View\Element\Template */
$block = $this->layout->createBlock(\Magento\Framework\View\Element\Template::class);
/** @var $block Template */
$block = $this->layout->createBlock(Template::class);

$block->setAjaxUrl($this->getAjaxUrl());
$block->setTemplate($this->templateFileName);
Expand Down Expand Up @@ -238,15 +270,24 @@ protected function stripInlineTranslations(&$body)
foreach ($body as &$part) {
$this->stripInlineTranslations($part);
}
} else {
if (is_string($body)) {
$body = preg_replace(
'#' . \Magento\Framework\Translate\Inline\ParserInterface::REGEXP_TOKEN . '#',
'$1',
$body
);
}
} elseif (is_string($body)) {
$body = preg_replace('#' . ParserInterface::REGEXP_TOKEN . '#', '$1', $body);
}

return $this;
}

/**
* Indicates whether the current area is valid for inline translation
*
* @return bool
*/
private function isAreaAllowed(): bool
{
try {
return in_array($this->appState->getAreaCode(), $this->allowedAreas, true);
} catch (LocalizedException $e) {
return false;
}
}
}
Loading