Skip to content

Commit 35b1b1d

Browse files
Merge pull request #9007 from adobe-commerce-tier-4/T4-PR-06-14-2024
[Support Tier-4 chittima] 06-14-2024 Regular delivery of bugfixes and improvements
2 parents d290f35 + 76f8b02 commit 35b1b1d

File tree

14 files changed

+418
-194
lines changed

14 files changed

+418
-194
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Backend\ViewModel;
9+
10+
/**
11+
* View model interface for requirejs configuration modifier
12+
*/
13+
interface RequireJsConfigModifierInterface
14+
{
15+
/**
16+
* Modifies requirejs configuration
17+
*
18+
* @param array $config requirejs configuration
19+
* @return array
20+
*/
21+
public function modify(array $config): array;
22+
}

app/code/Magento/Backend/view/adminhtml/templates/page/js/require_js.phtml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
*/
66

77
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
8+
/** @var \Magento\Backend\Block\Page\RequireJs $block */
9+
10+
$requireJsConfig = [
11+
'baseUrl' => $block->getViewFileUrl('/'),
12+
];
13+
14+
$configModifier = $block->getConfigModifier();
15+
$requireJsConfig = $configModifier instanceof \Magento\Backend\ViewModel\RequireJsConfigModifierInterface
16+
? $configModifier->modify($requireJsConfig)
17+
: $requireJsConfig;
818

919
$scriptString = '
1020
var BASE_URL = \'' . /* @noEscape */ $block->getUrl('*') . '\';
1121
var FORM_KEY = \'' . /* @noEscape */ $block->getFormKey() . '\';
12-
var require = {
13-
\'baseUrl\': \'' . /* @noEscape */ $block->getViewFileUrl('/') . '\'
14-
};';
15-
16-
echo /* @noEscape */ $secureRenderer->renderTag('script', [], $scriptString, false);
22+
var require = ' . /* @noEscape */ json_encode($requireJsConfig) .';';
23+
?>
24+
<?= /* @noEscape */ $secureRenderer->renderTag('script', [], $scriptString, false) ?>

app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Magento\Framework\App\Config\ScopeConfigInterface;
1313
use Magento\Framework\App\Filesystem\DirectoryList;
1414
use Magento\Framework\App\ObjectManager;
15+
use Magento\Framework\Data\Collection;
1516
use Magento\Framework\Exception\LocalizedException;
1617

1718
/**
@@ -289,6 +290,7 @@ protected function createSubDirectories($path)
289290
*
290291
* @return array
291292
* @deprecated
293+
* @see isDirectoryAllowed
292294
*/
293295
protected function getConditionsForExcludeDirs()
294296
{
@@ -317,6 +319,7 @@ protected function getConditionsForExcludeDirs()
317319
* @param array $conditions
318320
* @return \Magento\Framework\Data\Collection\Filesystem
319321
* @deprecated
322+
* @see \Magento\Framework\Data\Collection\Filesystem::setDirsFilter
320323
*/
321324
protected function removeItemFromCollection($collection, $conditions)
322325
{
@@ -415,7 +418,7 @@ public function getFilesCollection($path, $type = null)
415418
$mimeType = $itemStats['mimetype'] ?? $this->mime->getMimeType($item->getFilename());
416419
$item->setMimeType($mimeType);
417420

418-
if ($this->isImage($item->getBasename())) {
421+
if ($this->isImageValid($item)) {
419422
$thumbUrl = $this->getThumbnailUrl($item->getFilename(), true);
420423
// generate thumbnail "on the fly" if it does not exists
421424
if (!$thumbUrl) {
@@ -435,6 +438,12 @@ public function getFilesCollection($path, $type = null)
435438
$this->logger->notice(sprintf("GetImageSize caused error: %s", $e->getMessage()));
436439
}
437440
} else {
441+
$this->logger->warning(
442+
sprintf(
443+
"The image %s is invalid and cannot be displayed in the gallery.",
444+
$item->getBasename()
445+
)
446+
);
438447
$thumbUrl = $this->_assetRepo->getUrl(self::THUMB_PLACEHOLDER_PATH_SUFFIX);
439448
}
440449

@@ -1058,4 +1067,15 @@ private function getAllowedDirMask(string $path)
10581067

10591068
return '/^(' . implode('|', array_unique(array_column($allowedDirs, $subfolderLevel - 1))) . ')$/';
10601069
}
1070+
1071+
/**
1072+
* Checks if the file is an image and has a size greater than 0 to validate it can be processes in the gallery.
1073+
*
1074+
* @param Collection $item
1075+
* @return bool
1076+
*/
1077+
private function isImageValid($item)
1078+
{
1079+
return $this->isImage($item->getBasename()) && $item->getSize() > 0;
1080+
}
10611081
}

app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php

Lines changed: 148 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Magento\Cms\Model\Wysiwyg\Images\Storage\CollectionFactory;
1717
use Magento\Framework\App\Config\ScopeConfigInterface;
1818
use Magento\Framework\App\Filesystem\DirectoryList;
19+
use Magento\Framework\DataObject;
20+
use Magento\Framework\Exception\FileSystemException;
1921
use Magento\Framework\Exception\LocalizedException;
2022
use Magento\Framework\Filesystem;
2123
use Magento\Framework\Filesystem\Directory\Write;
@@ -31,6 +33,7 @@
3133
use Magento\MediaStorage\Model\File\UploaderFactory;
3234
use PHPUnit\Framework\MockObject\MockObject;
3335
use PHPUnit\Framework\TestCase;
36+
use Psr\Log\LoggerInterface;
3437

3538
/**
3639
* @SuppressWarnings(PHPMD.LongVariable)
@@ -141,6 +144,16 @@ class StorageTest extends TestCase
141144
*/
142145
private $fileMock;
143146

147+
/**
148+
* @var LoggerInterface|MockObject
149+
*/
150+
private $loggerMock;
151+
152+
/**
153+
* @var Repository|MockObject
154+
*/
155+
private $assetRepo;
156+
144157
/**
145158
* @var array
146159
*/
@@ -206,7 +219,7 @@ function ($path) {
206219
$this->adapterFactoryMock = $this->createMock(AdapterFactory::class);
207220
$this->imageHelperMock = $this->createPartialMock(
208221
Images::class,
209-
['getStorageRoot', 'getCurrentPath']
222+
['getStorageRoot', 'getCurrentPath', 'getCurrentUrl']
210223
);
211224
$this->imageHelperMock->expects(
212225
$this->any()
@@ -234,6 +247,12 @@ function ($path) {
234247
Database::class
235248
);
236249

250+
$this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
251+
->disableOriginalConstructor()
252+
->getMock();
253+
254+
$this->assetRepo = $this->createMock(Repository::class);
255+
237256
$this->uploaderFactoryMock = $this->getMockBuilder(UploaderFactory::class)
238257
->disableOriginalConstructor()
239258
->getMock();
@@ -284,7 +303,7 @@ function ($path) {
284303
'coreFileStorageDb' => $this->coreFileStorageMock,
285304
'filesystem' => $this->filesystemMock,
286305
'imageFactory' => $this->adapterFactoryMock,
287-
'assetRepo' => $this->createMock(Repository::class),
306+
'assetRepo' => $this->assetRepo,
288307
'storageCollectionFactory' => $this->storageCollectionFactoryMock,
289308
'storageFileFactory' => $this->storageFileFactoryMock,
290309
'storageDatabaseFactory' => $this->storageDatabaseFactoryMock,
@@ -299,7 +318,8 @@ function ($path) {
299318
'data' => [],
300319
'file' => $this->fileMock,
301320
'ioFile' => $this->ioFileMock,
302-
'coreConfig' => $this->coreConfigMock
321+
'coreConfig' => $this->coreConfigMock,
322+
'logger' => $this->loggerMock
303323
]
304324
);
305325
}
@@ -368,6 +388,130 @@ public function testGetDirsCollectionCreateSubDirectories()
368388
);
369389
}
370390

391+
/**
392+
* Test getFilesCollection() with the set of valid and invalid files
393+
*
394+
* @return void
395+
* @throws LocalizedException
396+
* @throws FileSystemException
397+
* @dataProvider fileItemsDataProvider
398+
*/
399+
public function testGetFilesCollection(
400+
int $timesWarningTriggered,
401+
string $thumbnailPath,
402+
DataObject $imageItem
403+
) {
404+
/** @var StorageCollection|MockObject $storageCollectionMock */
405+
$storageCollectionMock = $this->getMockBuilder(StorageCollection::class)
406+
->disableOriginalConstructor()
407+
->getMock();
408+
$storageCollectionMock->expects($this->once())
409+
->method('setCollectDirs')
410+
->willReturnSelf();
411+
$storageCollectionMock->expects($this->once())
412+
->method('setCollectFiles')
413+
->willReturnSelf();
414+
$storageCollectionMock->expects($this->once())
415+
->method('setCollectRecursively')
416+
->willReturnSelf();
417+
$storageCollectionMock->expects($this->once())
418+
->method('setOrder')
419+
->willReturnSelf();
420+
$storageCollectionMock->method('getIterator')
421+
->willReturn(new \ArrayIterator([$imageItem]));
422+
423+
$this->storageCollectionFactoryMock->expects($this->once())
424+
->method('create')
425+
->willReturn($storageCollectionMock);
426+
427+
$this->driverMock->expects(self::once())
428+
->method('stat')
429+
->willReturn($imageItem->toArray());
430+
431+
$this->assetRepo->expects($this->exactly($timesWarningTriggered))
432+
->method('getUrl')
433+
->willReturn($thumbnailPath);
434+
435+
$this->loggerMock->expects($this->exactly($timesWarningTriggered))
436+
->method('warning')
437+
->with(
438+
sprintf(
439+
"The image %s is invalid and cannot be displayed in the gallery.",
440+
$imageItem->getBasename()
441+
)
442+
);
443+
444+
$this->imagesStorage->getFilesCollection('/webroot/pub/media/', 'image');
445+
}
446+
447+
/**
448+
* Returns a set of valid and invalid image files
449+
*
450+
* @return array[]
451+
*/
452+
public function fileItemsDataProvider()
453+
{
454+
return [
455+
// Images files with the size of 0 bytes should generate proper warnings
456+
[
457+
'timesWarningTriggered' => 1,
458+
'thumbnailPath' => Storage::THUMB_PLACEHOLDER_PATH_SUFFIX,
459+
'imageItem' =>
460+
new DataObject(
461+
[
462+
'mtime' => 0,
463+
'size' => 0,
464+
'filename' => '/webroot/pub/media/wysiwyg/zero-bytes.jpg',
465+
'basename' => 'zero-bytes.jpg',
466+
'id' => 1,
467+
'name' => 'zero-bytes.jpg',
468+
'short_name' => 'zero-bytes.jpg',
469+
'url' => 'https://magento.local/pub/media/wysiwyg/zero-bytes.jpg',
470+
'mime_type' => 'image/jpeg'
471+
]
472+
)
473+
],
474+
// Images files with incorrect not allowed extensions should generate proper warnings
475+
[
476+
'timesWarningTriggered' => 1,
477+
'thumbnailPath' => Storage::THUMB_PLACEHOLDER_PATH_SUFFIX,
478+
'imageItem' =>
479+
new DataObject(
480+
[
481+
'mtime' => 0,
482+
'size' => 1024,
483+
'filename' => '/webroot/pub/media/wysiwyg/wrong-image.exe',
484+
'basename' => 'wrong-image.exe',
485+
'id' => 1,
486+
'name' => 'wrong-image.exe',
487+
'short_name' => 'wrong-image.exe',
488+
'url' => 'https://magento.local/pub/media/wysiwyg/wrong-image.exe',
489+
'mime_type' => 'image/jpeg'
490+
]
491+
)
492+
],
493+
// Images with non-zero size and allowed extension should not generate warnings
494+
[
495+
'timesWarningTriggered' => 0,
496+
'thumbnailPath' => '',
497+
'imageItem' =>
498+
new DataObject(
499+
[
500+
'mtime' => 0,
501+
'size' => 1024,
502+
'filename' => '/webroot/pub/media/wysiwyg/image.jpg',
503+
'basename' => 'image.jpg',
504+
'id' => 1,
505+
'name' => 'image.jpg',
506+
'short_name' => 'image.jpg',
507+
'url' => 'https://magento.local/pub/media/wysiwyg/image.jpg',
508+
'mime_type' => 'image/jpeg'
509+
]
510+
)
511+
],
512+
];
513+
}
514+
371515
/**
372516
* @param $path
373517
* @param $callNum
@@ -432,7 +576,7 @@ public static function dirsCollectionDataProvider()
432576
protected function generalTestGetDirsCollection(string $path, int $callNum, string $dirsFilter)
433577
{
434578
/** @var StorageCollection|MockObject $storageCollectionMock */
435-
$storageCollectionMock = $this->getMockBuilder(\Magento\Cms\Model\Wysiwyg\Images\Storage\Collection::class)
579+
$storageCollectionMock = $this->getMockBuilder(StorageCollection::class)
436580
->disableOriginalConstructor()
437581
->getMock();
438582
$storageCollectionMock->expects($this->once())

app/code/Magento/NewRelicReporting/Model/NewRelicWrapper.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
*/
1515
class NewRelicWrapper
1616
{
17+
private const NEWRELIC_APPNAME = 'newrelic.appname';
18+
1719
/**
1820
* Wrapper for 'newrelic_add_custom_parameter' function
1921
*
@@ -69,6 +71,19 @@ public function setTransactionName(string $transactionName): void
6971
}
7072
}
7173

74+
/**
75+
* Wrapper to start background transaction
76+
*
77+
* @return void
78+
*/
79+
public function startBackgroundTransaction()
80+
{
81+
if ($this->isExtensionInstalled()) {
82+
newrelic_start_transaction(ini_get(self::NEWRELIC_APPNAME));
83+
newrelic_background_job();
84+
}
85+
}
86+
7287
/**
7388
* Wrapper for 'newrelic_end_transaction'
7489
*

app/code/Magento/NewRelicReporting/Plugin/StatPlugin.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public function beforeStart(Stat $schedule, ...$args): array
6464
$timerName = current($args);
6565

6666
if ($this->isCronJob($timerName)) {
67+
$this->newRelicWrapper->startBackgroundTransaction();
6768
$this->newRelicWrapper->setTransactionName(
6869
sprintf('Cron %s', $timerName)
6970
);

app/code/Magento/NewRelicReporting/Test/Unit/Plugin/StatPluginTest.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ protected function setUp(): void
5555
*/
5656
public function testNewRelicTransactionNameIsNotSetIfNotCronjobPattern()
5757
{
58+
$this->newRelicWrapperMock
59+
->expects($this->never())
60+
->method('startBackgroundTransaction');
5861
$this->newRelicWrapperMock
5962
->expects($this->never())
6063
->method('setTransactionName');
@@ -71,6 +74,9 @@ public function testNewRelicTransactionNameIsNotSetIfNotCronjobPattern()
7174
*/
7275
public function testNewRelicTransactionNameIsSetForCronjobNamePattern()
7376
{
77+
$this->newRelicWrapperMock
78+
->expects($this->once())
79+
->method('startBackgroundTransaction');
7480
$this->newRelicWrapperMock
7581
->expects($this->once())
7682
->method('setTransactionName');
@@ -90,7 +96,7 @@ private function getNewRelicWrapperMock(): NewRelicWrapper
9096
if (null === $this->newRelicWrapperMock) {
9197
$this->newRelicWrapperMock = $this->getMockBuilder(NewRelicWrapper::class)
9298
->disableOriginalConstructor()
93-
->onlyMethods(['setTransactionName', 'endTransaction'])
99+
->onlyMethods(['setTransactionName', 'endTransaction', 'startBackgroundTransaction'])
94100
->getMock();
95101
}
96102

app/code/Magento/NewRelicReporting/etc/di.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
<type name="Magento\NewRelicReporting\Plugin\CommandPlugin">
5050
<arguments>
5151
<argument name="skipCommands" xsi:type="array">
52-
<item xsi:type="boolean" name="cron:run">true</item>
5352
<item xsi:type="boolean" name="server:run">true</item>
5453
</argument>
5554
</arguments>

0 commit comments

Comments
 (0)