Skip to content

Commit 405ae40

Browse files
committed
Merge remote-tracking branch 'origin/ACP2E-4045' into PR_2025_09_25_muntianu
2 parents c5fa1f1 + 0402c72 commit 405ae40

File tree

9 files changed

+174
-16
lines changed

9 files changed

+174
-16
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Reports\Controller\Report\Product;
9+
10+
use Magento\Framework\App\Action\Context;
11+
use Magento\Customer\Model\Session;
12+
use Magento\Customer\Model\Visitor;
13+
use Magento\Framework\App\Action\HttpPostActionInterface;
14+
use Magento\Framework\App\RequestInterface;
15+
use Magento\Framework\Controller\Result\JsonFactory;
16+
use Magento\Reports\Model\Event;
17+
use Magento\Reports\Model\Product\Index\ViewedFactory;
18+
use Magento\Reports\Model\ReportStatus;
19+
use Magento\Reports\Observer\EventSaver;
20+
use Magento\Store\Model\StoreManagerInterface;
21+
22+
/**
23+
* Report Action
24+
*/
25+
class View implements HttpPostActionInterface
26+
{
27+
/**
28+
* @var RequestInterface
29+
*/
30+
private $request;
31+
32+
/**
33+
* @param Context $context
34+
* @param JsonFactory $resultJsonFactory
35+
* @param ReportStatus $reportStatus
36+
* @param StoreManagerInterface $storeManager
37+
* @param Session $customerSession
38+
* @param Visitor $customerVisitor
39+
* @param ViewedFactory $productIndexFactory
40+
* @param EventSaver $eventSaver
41+
*/
42+
public function __construct(
43+
private readonly Context $context,
44+
private readonly JsonFactory $resultJsonFactory,
45+
private readonly ReportStatus $reportStatus,
46+
private readonly StoreManagerInterface $storeManager,
47+
private readonly Session $customerSession,
48+
private readonly Visitor $customerVisitor,
49+
private readonly ViewedFactory $productIndexFactory,
50+
private readonly EventSaver $eventSaver
51+
) {
52+
$this->request = $context->getRequest();
53+
}
54+
55+
/**
56+
* @inheritdoc
57+
*/
58+
public function execute()
59+
{
60+
$result = $this->resultJsonFactory->create();
61+
62+
if ($this->reportStatus->isReportEnabled((string)Event::EVENT_PRODUCT_VIEW)) {
63+
$productId = $this->request->getParam('product_id');
64+
65+
$viewData['product_id'] = $productId;
66+
$viewData['store_id'] = $this->storeManager->getStore()->getId();
67+
if ($this->customerSession->isLoggedIn()) {
68+
$viewData['customer_id'] = $this->customerSession->getCustomerId();
69+
} else {
70+
$viewData['visitor_id'] = $this->customerVisitor->getId();
71+
}
72+
$this->productIndexFactory->create()->setData($viewData)->save()->calculate();
73+
$this->eventSaver->save(Event::EVENT_PRODUCT_VIEW, $productId);
74+
}
75+
76+
return $result->setData([]);
77+
}
78+
}

app/code/Magento/Reports/Observer/CatalogProductViewObserver.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\Reports\Observer;
77

@@ -11,6 +11,10 @@
1111
/**
1212
* Reports Event observer model
1313
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
14+
* @deprecated We cannot rely on the observer to count product page visits (GET requests)
15+
* because the observer will not be called due fact that pages rely heavily on cache.
16+
* Instead, a call from a product page should be made to a separate controller.
17+
* @see \Magento\Reports\Controller\Report\Product\View
1418
*/
1519
class CatalogProductViewObserver implements ObserverInterface
1620
{

app/code/Magento/Reports/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"magento/module-store": "*",
2323
"magento/module-tax": "*",
2424
"magento/module-widget": "*",
25+
"magento/module-theme": "*",
2526
"magento/module-wishlist": "*"
2627
},
2728
"type": "magento2-module",

app/code/Magento/Reports/etc/frontend/events.xml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2013 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
@@ -15,9 +15,6 @@
1515
<event name="customer_logout">
1616
<observer name="reports" instance="Magento\Reports\Observer\CustomerLogoutObserver" />
1717
</event>
18-
<event name="catalog_controller_product_view">
19-
<observer name="reports" instance="Magento\Reports\Observer\CatalogProductViewObserver" />
20-
</event>
2118
<event name="sendfriend_product">
2219
<observer name="reports" instance="Magento\Reports\Observer\SendfriendProductObserver" />
2320
</event>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
9+
<router id="standard">
10+
<route id="reports" frontName="reports">
11+
<module name="Magento_Reports" />
12+
</route>
13+
</router>
14+
</config>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright 2025 Adobe
5+
* All Rights Reserved.
6+
*/
7+
-->
8+
9+
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
10+
<body>
11+
<referenceContainer name="product.info.main">
12+
<block name="report.product.view.container" template="Magento_Theme::template.phtml" ifconfig="reports/options/enabled" after="-">
13+
<block class="Magento\Catalog\Block\Product\View" name="report.product.view" template="Magento_Reports::product/report_viewed_product.phtml" ifconfig="reports/options/product_view_enabled"/>
14+
</block>
15+
</referenceContainer>
16+
</body>
17+
</page>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
7+
/** @var \Magento\Reports\Block\Product\ViewedProduct $block */
8+
/** @var \Magento\Framework\Escaper $escaper */
9+
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
10+
?>
11+
<script type="text/x-magento-init">
12+
{
13+
"*": {
14+
"Magento_Reports/js/product-viewed": {
15+
"product_id": "<?= $escaper->escapeJs($block->getProduct()->getId()) ?>"
16+
}
17+
}
18+
}
19+
</script>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Copyright 2025 Adobe
3+
* All Rights Reserved.
4+
*/
5+
6+
define([
7+
'jquery',
8+
'mage/url'
9+
], function ($, urlBuilder) {
10+
'use strict';
11+
12+
return function (data) {
13+
$.ajax({
14+
url: urlBuilder.build('reports/report_product/view'),
15+
type: 'POST',
16+
data: {'product_id': data.product_id },
17+
dataType: 'json'
18+
});
19+
};
20+
});
Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2017 Adobe
4+
* All Rights Reserved.
55
*/
6-
namespace Magento\Backend\Block\Dashboard\Tab\Products;
6+
namespace Magento\Reports\Controller\Adminhtml\Report;
77

8-
use Magento\TestFramework\Helper\Bootstrap as BootstrapHelper;
9-
use Magento\Framework\ObjectManagerInterface;
10-
use Magento\Framework\View\LayoutInterface;
118
use Magento\Backend\Block\Dashboard\Tab\Products\Viewed as ViewedProductsTabBlock;
129
use Magento\Catalog\Model\ProductRepository;
10+
use Magento\Framework\App\Request\Http;
1311
use Magento\Framework\Event\ManagerInterface as EventManager;
12+
use Magento\Framework\ObjectManagerInterface;
13+
use Magento\Framework\View\LayoutInterface;
14+
use Magento\TestFramework\Helper\Bootstrap as BootstrapHelper;
15+
use function PHPUnit\Framework\assertEquals;
1416

1517
/**
1618
* @magentoAppArea frontend
1719
*/
18-
class ViewedTest extends \PHPUnit\Framework\TestCase
20+
class ViewedTest extends \Magento\TestFramework\TestCase\AbstractController
1921
{
2022
/**
2123
* @var ObjectManagerInterface
@@ -39,24 +41,30 @@ class ViewedTest extends \PHPUnit\Framework\TestCase
3941

4042
protected function setUp(): void
4143
{
44+
parent::setUp();
4245
$this->objectManager = BootstrapHelper::getObjectManager();
4346
$this->layout = $this->objectManager->get(LayoutInterface::class);
4447
$this->productRepository = $this->objectManager->get(ProductRepository::class);
4548
$this->eventManager = $this->objectManager->get(EventManager::class);
4649
}
4750

4851
/**
52+
* Assert viewed product in reports.
53+
*
4954
* @magentoDataFixture Magento/Catalog/_files/product_simple.php
5055
* @magentoDbIsolation enabled
5156
* @magentoAppIsolation enabled
5257
* @magentoConfigFixture default/reports/options/enabled 1
5358
*/
5459
public function testGetPreparedCollectionProductPrice()
5560
{
61+
$sku = 'simple';
62+
$product = $this->productRepository->get($sku);
63+
$this->getRequest()->setMethod(Http::METHOD_POST)->setPostValue('product_id', $product->getId());
64+
$this->dispatch('reports/report_product/view');
65+
5666
/** @var ViewedProductsTabBlock $viewedProductsTabBlock */
5767
$viewedProductsTabBlock = $this->layout->createBlock(ViewedProductsTabBlock::class);
58-
$product = $this->productRepository->getById(1);
59-
$this->eventManager->dispatch('catalog_controller_product_view', ['product' => $product]);
6068

6169
$collection = $viewedProductsTabBlock->getPreparedCollection();
6270

0 commit comments

Comments
 (0)