Skip to content

Commit 27ec0ae

Browse files
committed
Fix Arabic & Hebrew in invoices
Use rtl text handler in invoice PDF generation
1 parent 876519b commit 27ec0ae

File tree

5 files changed

+57
-86
lines changed

5 files changed

+57
-86
lines changed

app/code/Magento/Sales/Model/Order/Address/Renderer.php

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
use Magento\Customer\Model\Address\Config as AddressConfig;
1010
use Magento\Framework\Event\ManagerInterface as EventManager;
1111
use Magento\Sales\Model\Order\Address;
12-
use Magento\Framework\Stdlib\StringUtils;
13-
use Magento\Framework\App\ObjectManager;
1412

1513
/**
1614
* Class Renderer used for formatting an order address
@@ -29,26 +27,18 @@ class Renderer
2927
*/
3028
protected $eventManager;
3129

32-
/**
33-
* @var StringUtils
34-
*/
35-
private $stringUtils;
36-
3730
/**
3831
* Constructor
3932
*
4033
* @param AddressConfig $addressConfig
4134
* @param EventManager $eventManager
42-
* @param StringUtils $stringUtils
4335
*/
4436
public function __construct(
4537
AddressConfig $addressConfig,
46-
EventManager $eventManager,
47-
StringUtils $stringUtils = null
38+
EventManager $eventManager
4839
) {
4940
$this->addressConfig = $addressConfig;
5041
$this->eventManager = $eventManager;
51-
$this->stringUtils = $stringUtils ?: ObjectManager::getInstance()->get(StringUtils::class);
5242
}
5343

5444
/**
@@ -68,50 +58,4 @@ public function format(Address $address, $type)
6858
$this->eventManager->dispatch('customer_address_format', ['type' => $formatType, 'address' => $address]);
6959
return $formatType->getRenderer()->renderArray($address->getData());
7060
}
71-
72-
/**
73-
* Detect an input string is Arabic
74-
*
75-
* @param string $subject
76-
* @return bool
77-
*/
78-
public function isArabic(string $subject): bool
79-
{
80-
return (preg_match('/\p{Arabic}/u', $subject) > 0);
81-
}
82-
83-
/**
84-
* Reverse text with Arabic characters
85-
*
86-
* @param string $string
87-
* @return string
88-
*/
89-
public function reverseArabicText($string)
90-
{
91-
$splitText = explode(' ', $string);
92-
for ($i = 0; $i < count($splitText); $i++) {
93-
if ($this->isArabic($splitText[$i])) {
94-
for ($j = $i + 1; $j < count($splitText); $j++) {
95-
$tmp = ($this->isArabic($splitText[$j]))
96-
? $this->stringUtils->strrev($splitText[$j]) : $splitText[$j];
97-
$splitText[$j] = ($this->isArabic($splitText[$i]))
98-
? $this->stringUtils->strrev($splitText[$i]) : $splitText[$i];
99-
$splitText[$i] = $tmp;
100-
}
101-
}
102-
}
103-
return implode(' ', $splitText);
104-
}
105-
106-
/**
107-
* Check and revert arabic text
108-
*
109-
* @param string $string
110-
* @return string
111-
*/
112-
public function processArabicText($string)
113-
{
114-
return ($this->isArabic($string))
115-
? $this->reverseArabicText($string) : $string;
116-
}
11761
}

app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
namespace Magento\Sales\Model\Order\Pdf;
88

99
use Magento\Framework\App\Filesystem\DirectoryList;
10+
use Magento\Framework\App\ObjectManager;
1011
use Magento\MediaStorage\Helper\File\Storage\Database;
12+
use Magento\Sales\Model\RtlTextHandler;
1113

1214
/**
1315
* Sales Order PDF abstract model
@@ -53,6 +55,11 @@ abstract class AbstractPdf extends \Magento\Framework\DataObject
5355
*/
5456
protected $_pdf;
5557

58+
/**
59+
* @var RtlTextHandler
60+
*/
61+
private $rtlTextHandler;
62+
5663
/**
5764
* Retrieve PDF
5865
*
@@ -142,6 +149,7 @@ abstract public function getPdf();
142149
* @param \Magento\Sales\Model\Order\Address\Renderer $addressRenderer
143150
* @param array $data
144151
* @param Database $fileStorageDatabase
152+
* @param RtlTextHandler|null $rtlTextHandler
145153
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
146154
*/
147155
public function __construct(
@@ -156,7 +164,8 @@ public function __construct(
156164
\Magento\Framework\Translate\Inline\StateInterface $inlineTranslation,
157165
\Magento\Sales\Model\Order\Address\Renderer $addressRenderer,
158166
array $data = [],
159-
Database $fileStorageDatabase = null
167+
Database $fileStorageDatabase = null,
168+
?RtlTextHandler $rtlTextHandler = null
160169
) {
161170
$this->addressRenderer = $addressRenderer;
162171
$this->_paymentData = $paymentData;
@@ -169,8 +178,8 @@ public function __construct(
169178
$this->_pdfTotalFactory = $pdfTotalFactory;
170179
$this->_pdfItemsFactory = $pdfItemsFactory;
171180
$this->inlineTranslation = $inlineTranslation;
172-
$this->fileStorageDatabase = $fileStorageDatabase ?:
173-
\Magento\Framework\App\ObjectManager::getInstance()->get(Database::class);
181+
$this->fileStorageDatabase = $fileStorageDatabase ?: ObjectManager::getInstance()->get(Database::class);
182+
$this->rtlTextHandler = $rtlTextHandler ?: ObjectManager::getInstance()->get(RtlTextHandler::class);
174183
parent::__construct($data);
175184
}
176185

@@ -501,8 +510,7 @@ protected function insertOrder(&$page, $obj, $putOrderId = true)
501510
if ($value !== '') {
502511
$text = [];
503512
foreach ($this->string->split($value, 45, true, true) as $_value) {
504-
$text[] = ($this->addressRenderer->isArabic($_value))
505-
? $this->addressRenderer->reverseArabicText($_value) : $_value;
513+
$text[] = $this->rtlTextHandler->reverseRtlText($_value);
506514
}
507515
foreach ($text as $part) {
508516
$page->drawText(strip_tags(ltrim($part)), 35, $this->y, 'UTF-8');
@@ -519,8 +527,7 @@ protected function insertOrder(&$page, $obj, $putOrderId = true)
519527
if ($value !== '') {
520528
$text = [];
521529
foreach ($this->string->split($value, 45, true, true) as $_value) {
522-
$text[] = ($this->addressRenderer->isArabic($_value))
523-
? $this->addressRenderer->reverseArabicText($_value) : $_value;
530+
$text[] = $this->rtlTextHandler->reverseRtlText($_value);
524531
}
525532
foreach ($text as $part) {
526533
$page->drawText(strip_tags(ltrim($part)), 285, $this->y, 'UTF-8');

app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
namespace Magento\Sales\Model\Order\Pdf\Items\Invoice;
99

1010
use Magento\Framework\App\ObjectManager;
11-
use Magento\Sales\Model\Order\Address\Renderer;
11+
use Magento\Sales\Model\RtlTextHandler;
1212

1313
/**
1414
* Sales Order Invoice Pdf default items renderer
@@ -23,9 +23,9 @@ class DefaultInvoice extends \Magento\Sales\Model\Order\Pdf\Items\AbstractItems
2323
protected $string;
2424

2525
/**
26-
* @var \Magento\Sales\Model\Order\Address\Renderer
26+
* @var RtlTextHandler
2727
*/
28-
private $renderer;
28+
private $rtlTextHandler;
2929

3030
/**
3131
* @param \Magento\Framework\Model\Context $context
@@ -37,7 +37,7 @@ class DefaultInvoice extends \Magento\Sales\Model\Order\Pdf\Items\AbstractItems
3737
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
3838
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
3939
* @param array $data
40-
* @param \Magento\Sales\Model\Order\Address\Renderer $renderer
40+
* @param RtlTextHandler|null $rtlTextHandler
4141
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
4242
*/
4343
public function __construct(
@@ -50,7 +50,7 @@ public function __construct(
5050
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
5151
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
5252
array $data = [],
53-
Renderer $renderer = null
53+
?RtlTextHandler $rtlTextHandler = null
5454
) {
5555
$this->string = $string;
5656
parent::__construct(
@@ -63,7 +63,7 @@ public function __construct(
6363
$resourceCollection,
6464
$data
6565
);
66-
$this->renderer = $renderer ?: ObjectManager::getInstance()->get(Renderer::class);
66+
$this->rtlTextHandler = $rtlTextHandler ?: ObjectManager::getInstance()->get(RtlTextHandler::class);
6767
}
6868

6969
/**
@@ -82,16 +82,14 @@ public function draw()
8282
// draw Product name
8383
$lines[0] = [
8484
[
85-
// phpcs:ignore Magento2.Functions.DiscouragedFunction
86-
'text' => $this->string->split($this->renderer->processArabicText(html_entity_decode($item->getName())), 35, true, true),
85+
'text' => $this->string->split($this->prepareText((string)$item->getName()), 35, true, true),
8786
'feed' => 35
8887
]
8988
];
9089

9190
// draw SKU
9291
$lines[0][] = [
93-
// phpcs:ignore Magento2.Functions.DiscouragedFunction
94-
'text' => $this->string->split($this->renderer->processArabicText(html_entity_decode($this->getSku($item))), 17),
92+
'text' => $this->string->split($this->prepareText((string)$this->getSku($item)), 17),
9593
'feed' => 290,
9694
'align' => 'right',
9795
];
@@ -168,4 +166,16 @@ public function draw()
168166
$page = $pdf->drawLineBlocks($page, [$lineBlock], ['table_header' => true]);
169167
$this->setPage($page);
170168
}
169+
170+
/**
171+
* Returns prepared for PDF text, reversed in case of RTL text
172+
*
173+
* @param string $string
174+
* @return string
175+
*/
176+
private function prepareText(string $string): string
177+
{
178+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
179+
return $this->rtlTextHandler->reverseRtlText(html_entity_decode($string));
180+
}
171181
}

app/code/Magento/Sales/Model/RtlTextHandler.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ class RtlTextHandler
1616
*/
1717
private $stringUtils;
1818

19+
/**
20+
* @param StringUtils $stringUtils
21+
*/
1922
public function __construct(StringUtils $stringUtils)
2023
{
2124
$this->stringUtils = $stringUtils;
@@ -38,15 +41,17 @@ public function isRtlText(string $subject): bool
3841
* @param string $string
3942
* @return string
4043
*/
41-
public function reverseArabicText(string $string): string
44+
public function reverseRtlText(string $string): string
4245
{
4346
$splitText = explode(' ', $string);
44-
for ($i = 0; $i < count($splitText); $i++) {
47+
$splitTextAmount = count($splitText);
48+
49+
for ($i = 0; $i < $splitTextAmount; $i++) {
4550
if ($this->isRtlText($splitText[$i])) {
46-
for ($j = $i + 1; $j < count($splitText); $j++) {
47-
$tmp = ($this->isRtlText($splitText[$j]))
51+
for ($j = $i + 1; $j < $splitTextAmount; $j++) {
52+
$tmp = $this->isRtlText($splitText[$j])
4853
? $this->stringUtils->strrev($splitText[$j]) : $splitText[$j];
49-
$splitText[$j] = ($this->isRtlText($splitText[$i]))
54+
$splitText[$j] = $this->isRtlText($splitText[$i])
5055
? $this->stringUtils->strrev($splitText[$i]) : $splitText[$i];
5156
$splitText[$i] = $tmp;
5257
}

app/code/Magento/Sales/Test/Unit/Model/RtlTextHandlerTest.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
27

38
namespace Magento\Sales\Test\Unit\Model;
49

@@ -26,24 +31,24 @@ protected function setUp(): void
2631

2732
/**
2833
* @param string $str
29-
* @param bool $expected
34+
* @param bool $isRtl
3035
* @dataProvider provideRtlTexts
3136
*/
32-
public function testIsRtlText(string $str, bool $expected): void
37+
public function testIsRtlText(string $str, bool $isRtl): void
3338
{
34-
$this->assertEquals($expected, $this->rtlTextHandler->isRtlText($str));
39+
$this->assertEquals($isRtl, $this->rtlTextHandler->isRtlText($str));
3540
}
3641

3742
/**
3843
* @param string $str
39-
* @param bool $expected
44+
* @param bool $isRtl
4045
* @dataProvider provideRtlTexts
4146
*/
42-
public function testReverseArabicText(string $str, bool $expected): void
47+
public function testReverseRtlText(string $str, bool $isRtl): void
4348
{
44-
$expectedStr = $expected ? $this->stringUtils->strrev($str) : $str;
49+
$expectedStr = $isRtl ? $this->stringUtils->strrev($str) : $str;
4550

46-
$this->assertEquals($expectedStr, $this->rtlTextHandler->reverseArabicText($str));
51+
$this->assertEquals($expectedStr, $this->rtlTextHandler->reverseRtlText($str));
4752
}
4853

4954
public function provideRtlTexts(): array

0 commit comments

Comments
 (0)