Skip to content

Commit

Permalink
Merge branch '2.4-develop' of https://github.com/mage-os/mirror-magento2
Browse files Browse the repository at this point in the history
 into 2.4-develop
  • Loading branch information
mage-os-ci committed Jun 23, 2024
2 parents 5423a1f + a12063b commit 3aefde8
Show file tree
Hide file tree
Showing 13 changed files with 495 additions and 34 deletions.
74 changes: 57 additions & 17 deletions app/code/Magento/Analytics/Model/ReportWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use Magento\Analytics\ReportXml\DB\ReportValidator;
use Magento\Framework\Filesystem\Directory\WriteInterface;
use Magento\Framework\Filesystem\File\WriteInterface as FileWriteInterface;

/**
* Writes reports in files in csv format
Expand Down Expand Up @@ -69,23 +70,7 @@ public function write(WriteInterface $directory, $path)
continue;
}
}
/** @var $providerObject */
$providerObject = $this->providerFactory->create($provider['class']);
$fileName = $provider['parameters'] ? $provider['parameters']['name'] : $provider['name'];
$fileFullPath = $path . $fileName . '.csv';
$fileData = $providerObject->getReport(...array_values($provider['parameters']));
$stream = $directory->openFile($fileFullPath, 'w+');
$stream->lock();
$headers = [];
foreach ($fileData as $row) {
if (!$headers) {
$headers = array_keys($row);
$stream->writeCsv($headers);
}
$stream->writeCsv($this->prepareRow($row));
}
$stream->unlock();
$stream->close();
$this->prepareData($provider, $directory, $path);
}
if ($errorsList) {
$errorStream = $directory->openFile($path . $this->errorsFileName, 'w+');
Expand All @@ -100,6 +85,61 @@ public function write(WriteInterface $directory, $path)
return true;
}

/**
* Prepare report data
*
* @param array $provider
* @param WriteInterface $directory
* @param string $path
* @return void
* @throws \Magento\Framework\Exception\FileSystemException
*/
private function prepareData(array $provider, WriteInterface $directory, string $path)
{
/** @var $providerObject */
$providerObject = $this->providerFactory->create($provider['class']);
$fileName = $provider['parameters'] ? $provider['parameters']['name'] : $provider['name'];
$fileFullPath = $path . $fileName . '.csv';

$stream = $directory->openFile($fileFullPath, 'w+');
$stream->lock();

$headers = [];
if ($providerObject instanceof \Magento\Analytics\ReportXml\BatchReportProviderInterface) {
$fileData = $providerObject->getBatchReport(...array_values($provider['parameters']));
do {
$this->doWrite($fileData, $stream, $headers);
$fileData = $providerObject->getBatchReport(...array_values($provider['parameters']));
$fileData->rewind();
} while ($fileData->valid());
} else {
$fileData = $providerObject->getReport(...array_values($provider['parameters']));
$this->doWrite($fileData, $stream, $headers);
}

$stream->unlock();
$stream->close();
}

/**
* Write data to file
*
* @param \Traversable $fileData
* @param FileWriteInterface $stream
* @param array $headers
* @return void
*/
private function doWrite(\Traversable $fileData, FileWriteInterface $stream, array $headers)
{
foreach ($fileData as $row) {
if (!$headers) {
$headers = array_keys($row);
$stream->writeCsv($headers);
}
$stream->writeCsv($this->prepareRow($row));
}
}

/**
* Replace wrong symbols in row
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
/************************************************************************
*
* Copyright 2023 Adobe
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe
* and its suppliers and are protected by all applicable intellectual
* property laws, including trade secret and copyright laws.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe.
* ************************************************************************
*/
declare(strict_types=1);

namespace Magento\Analytics\ReportXml;

interface BatchReportProviderInterface
{
public const BATCH_SIZE = 10000;

/**
* Returns one batch of the report data
*
* @param string $name
* @return \IteratorIterator
*/
public function getBatchReport(string $name): \IteratorIterator;
}
33 changes: 33 additions & 0 deletions app/code/Magento/Analytics/ReportXml/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class Query implements \JsonSerializable
*/
private $config;

/**
* @var Select
*/
private $selectCount;

/**
* Query constructor.
*
Expand Down Expand Up @@ -94,4 +99,32 @@ public function jsonSerialize()
'config' => $this->getConfig()
];
}

/**
* Get SQL for get record count
*
* @return Select
* @throws \Zend_Db_Select_Exception
*/
public function getSelectCountSql(): Select
{
if (!$this->selectCount) {
$this->selectCount = clone $this->getSelect();
$this->selectCount->reset(\Magento\Framework\DB\Select::ORDER);
$this->selectCount->reset(\Magento\Framework\DB\Select::LIMIT_COUNT);
$this->selectCount->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET);
$this->selectCount->reset(\Magento\Framework\DB\Select::COLUMNS);

$part = $this->getSelect()->getPart(\Magento\Framework\DB\Select::GROUP);
if (!is_array($part) || !count($part)) {
$this->selectCount->columns(new \Zend_Db_Expr('COUNT(*)'));
return $this->selectCount;
}

$this->selectCount->reset(\Magento\Framework\DB\Select::GROUP);
$group = $this->getSelect()->getPart(\Magento\Framework\DB\Select::GROUP);
$this->selectCount->columns(new \Zend_Db_Expr(("COUNT(DISTINCT ".implode(", ", $group).")")));
}
return $this->selectCount;
}
}
48 changes: 45 additions & 3 deletions app/code/Magento/Analytics/ReportXml/ReportProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/**
* Providers for reports data
*/
class ReportProvider
class ReportProvider implements BatchReportProviderInterface
{
/**
* @var QueryFactory
Expand All @@ -28,6 +28,26 @@ class ReportProvider
*/
private $iteratorFactory;

/**
* @var int
*/
private $currentPosition = 0;

/**
* @var int
*/
private $countTotal = 0;

/**
* @var \Magento\Framework\DB\Adapter\AdapterInterface
*/
private $connection;

/**
* @var Query
*/
private $dataSelect;

/**
* ReportProvider constructor.
*
Expand All @@ -46,8 +66,7 @@ public function __construct(
}

/**
* Returns custom iterator name for report
* Null for default
* Returns custom iterator name for report. Null for default
*
* @param Query $query
* @return string|null
Expand All @@ -71,4 +90,27 @@ public function getReport($name)
$statement = $connection->query($query->getSelect());
return $this->iteratorFactory->create($statement, $this->getIteratorName($query));
}

/**
* @inheritdoc
*/
public function getBatchReport(string $name): \IteratorIterator
{
if (!$this->dataSelect || $this->dataSelect->getConfig()['name'] !== $name) {
$this->dataSelect = $this->queryFactory->create($name);
$this->currentPosition = 0;
$this->connection = $this->connectionFactory->getConnection($this->dataSelect->getConnectionName());
$this->countTotal = $this->connection->fetchOne($this->dataSelect->getSelectCountSql());
}

if ($this->currentPosition >= $this->countTotal) {
return $this->iteratorFactory->create(new \ArrayIterator([]), $this->getIteratorName($this->dataSelect));
}

$statement = $this->connection->query(
$this->dataSelect->getSelect()->limit(self::BATCH_SIZE, $this->currentPosition)
);
$this->currentPosition += self::BATCH_SIZE;
return $this->iteratorFactory->create($statement, $this->getIteratorName($this->dataSelect));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ protected function setUp(): void
*/
public function testWrite(array $configData, array $fileData, array $expectedFileData): void
{
$fileData = new \IteratorIterator(new \ArrayIterator($fileData));
$emptyFileData = new \IteratorIterator(new \ArrayIterator([]));
$errors = [];
$this->configInterfaceMock
->expects($this->once())
Expand All @@ -121,10 +123,10 @@ public function testWrite(array $configData, array $fileData, array $expectedFil
$parameterName = isset(reset($configData)[0]['parameters']['name'])
? reset($configData)[0]['parameters']['name']
: '';
$this->reportProviderMock->expects($this->once())
->method('getReport')
$this->reportProviderMock->expects($this->exactly(2))
->method('getBatchReport')
->with($parameterName ?: null)
->willReturn($fileData);
->willReturnOnConsecutiveCalls($fileData, $emptyFileData);
$errorStreamMock = $this->getMockBuilder(
FileWriteInterface::class
)->getMockForAbstractClass();
Expand Down
27 changes: 27 additions & 0 deletions app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,31 @@ public function testJsonSerialize()

$this->assertSame($expectedResult, $this->query->jsonSerialize());
}

public function testGetSelectCountSql()
{
$resetParams = [
Select::ORDER,
Select::LIMIT_COUNT,
Select::LIMIT_OFFSET,
Select::COLUMNS
];

$this->selectMock
->expects($this->exactly(4))
->method('reset')
->willReturnCallback(
function (string $value) use (&$resetParams) {
$this->assertEquals(array_shift($resetParams), $value);
}
);

$this->selectMock
->expects($this->once())
->method('columns')
->with(new \Zend_Db_Expr('COUNT(*)'))
->willReturnSelf();

$this->assertEquals($this->selectMock, $this->query->getSelectCountSql());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,55 @@ public function testGetReport()
->willReturn($this->iteratorMock);
$this->assertEquals($this->iteratorMock, $this->subject->getReport($reportName));
}

/**
* @return void
*/
public function testGetBatchReport()
{
$reportName = 'test_report';
$connectionName = 'sales';

$this->queryFactoryMock->expects($this->once())
->method('create')
->with($reportName)
->willReturn($this->queryMock);

$this->connectionFactoryMock->expects($this->once())
->method('getConnection')
->with($connectionName)
->willReturn($this->connectionMock);

$this->queryMock->expects($this->once())
->method('getConnectionName')
->willReturn($connectionName);

$this->selectMock->expects($this->once())
->method('limit')
->with(ReportProvider::BATCH_SIZE, 0)
->willReturn($this->selectMock);

$this->queryMock->expects($this->once())
->method('getConfig')
->willReturn(
[
'connection' => $connectionName
]
);

$this->connectionMock->expects($this->once())
->method('query')
->with($this->selectMock)
->willReturn($this->statementMock);

$this->connectionMock->expects($this->once())
->method('fetchOne')
->willReturn(5);

$this->iteratorFactoryMock->expects($this->once())
->method('create')
->with($this->statementMock, null)
->willReturn($this->iteratorMock);
$this->assertEquals($this->iteratorMock, $this->subject->getBatchReport($reportName));
}
}
1 change: 1 addition & 0 deletions app/code/Magento/Catalog/Block/Widget/RecentlyViewed.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@
*/
class RecentlyViewed extends Wrapper implements \Magento\Widget\Block\BlockInterface
{
protected const RENDER_TYPE = 'html';
}
4 changes: 3 additions & 1 deletion app/code/Magento/Ui/Block/Wrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
class Wrapper extends \Magento\Framework\View\Element\Template
{
protected const RENDER_TYPE = '';

/**
* @var UiComponentGenerator
*/
Expand Down Expand Up @@ -91,6 +93,6 @@ public function renderApp($data = [])
->generateUiComponent($this->getData('uiComponent'), $this->getLayout());
$this->injectDataInDataSource($uiComponent, $this->getData());
$this->addDataToChildComponents($uiComponent, $data);
return (string) $uiComponent->render();
return (string) $uiComponent->render(static::RENDER_TYPE);
}
}
Loading

0 comments on commit 3aefde8

Please sign in to comment.