How to show history of products viewed by logged in customer and delete if current user wishes to?

magento.stackexchange https://magento.stackexchange.com/questions/174847

  •  08-10-2020
  •  | 
  •  

Question

What I have tried till now is

$objManager = \Magento\Framework\App\ObjectManager::getInstance();
$visitors = $objManager->get('Your\Store\Block\Customer\Login');
$currVisitorId = $visitors->getLoggedInUserId();
$currVisitorName = $visitors->getLoggedInUserName();

$prodMyViewedCol = $objManager->get('\Magento\Reports\Model\ResourceModel\Event\Collection');
$prodMyViewedCol->setOrder('logged_at','DESC');

$prodViewedThisEntirelyIdCol = array();  //used to store products viewed by currently logged in user.

foreach($prodMyViewedCol as $prod){
    //subject id is the column name in the event table
    if($prod->getSubjectId() != $currVisitorId){
        continue;
    }
    $product_id = $prod->getObjectId();
    $prodViewedThisEntirelyIdCol[] = $product_id;
}
echo "<pre>";
echo 'logged in user: ', $currVisitorName, '<br>';
var_dump(array_unique($prodViewedThisEntirelyIdCol));
die();

fetched the collection of events of product view and sort them in descending order. Then after filtered them by the customer id. I'm getting the correct history which is shown below:enter image description here

Ok, I got the history and can list the history of a customer, I could be happy if my requirements were limited to this. But I need to delete the history. I can do that as well but deleting the data in table will hamper the results of reports in backend.

So what I want is: get the products viewed by currently logged in customer and delete that history safely without hampering the core behavior of reports, or store's database.

Was it helpful?

Solution 2

First of all I created following file to track product view event.

events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_controller_product_view">
        <observer name="catalog_controller_product_view_catcher" instance="User\History\Observer\UsersProductView" />
    </event>
</config>

The observer saves each product viewed by the customer in custom made table in database:

<?php
namespace User\History\Observer;
/*
  Observer class to save product view history.
*/
class UsersProductView implements \Magento\Framework\Event\ObserverInterface
{
    protected $productViewHistory;

    public function __construct(
        \User\History\Model\CustomerProductViewHistory $productViewHistory,
    ){}
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        if($this->isUserLoggedIn())
      {
         $product = $observer->getData('product');
         $objectId = $product->getData('entity_id');

      }
    }
    public function saveData($objectId)
    {
        $subjectId = $this->getLoggedInUserId();
        $subType =  $this->getSubjectType();
        $storeId = $this->_storeManager->getStore()->getId();

        /*SET DATA*/
        $this->productViewHistory->setEventId(0);
        $this->productViewHistory->setObjectId($objectId);
        $this->productViewHistory->setSubtype($subType);
        $this->productViewHistory->setStoreId($storeId);
        $this->productViewHistory->setSubjectId($subjectId);

        /*SAVE*///$this->productViewHistory->save();
        try {
           $this->productViewHistory->save();
        }
        catch (\Exception $ex) {
            $this->logger->critical($ex);
            return false;
        }
    }
...
...
}

Using above approach I'm able to save the user's view history in my own table so that deleting it won't affect magento's reports.

To delete history I used below function:

public function deleteEventForProductId($productId)
{
   $collection = $this->historyCollectionFactory->create();
   // There can be multiple events associated with same user for same product.
   $collection->addFieldToFilter('object_id', $productId);
   foreach ($collection as $key => $value) {
        if($value->getData('subject_id') == $this->getLoggedInUserId())
           // user repository to delete by id.
           $this->historyRepo->deleteById( $value->getData('id') );
       }    
}   

OTHER TIPS

First off: don't directly use the object manager in your code, but use dependency injection.

enter image description here

Secondly: use factories to create instances of objects.

And for the question about deletion: you should use Service Contracts (repositories) when it comes to handling the persistence of data. Given that the reports-module currently doesn't have any (2.1.6), you need to handle the deletion using the resource model. Once again: use dependency injection and a factory to get this model.

Example code for a Block class:

namespace yourNameSpace;
class Example  extends \Magento\Framework\View\Element\Template
{
    /**
     * @var \Magento\Reports\Model\ResourceModel\Event\CollectionFactory
     */
    protected $collectionFactory;
/**
 * @var \Magento\Customer\Model\Session
 */
protected $customerSession;

/**
 * @var \Magento\Reports\Model\ResourceModel\EventFactory
 */
protected $resourceFactory;

/**
 * Example constructor.
 * @param \Magento\Reports\Model\ResourceModel\Event\CollectionFactory $collectionFactory
 * @param \Magento\Reports\Model\ResourceModel\EventFactory $resourceFactory
 * @param \Magento\Customer\Model\Session $customerSession
 */
public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,        
    \Magento\Reports\Model\ResourceModel\Event\CollectionFactory $collectionFactory,
    \Magento\Reports\Model\ResourceModel\EventFactory $resourceFactory,
    \Magento\Customer\Model\Session $customerSession
) {
    parent::__construct($context);
        $this->collectionFactory = $collectionFactory;
        $this->customerSession = $customerSession;
        $this->resourceFactory = $resourceFactory;
    }

    /**
     * @return bool|\Magento\Reports\Model\ResourceModel\Event\Collection
     */
    public function getViewedProductsForCurrentCustomer()
    {
        if ($this->customerSession->isLoggedIn()) {
            /** @var \Magento\Reports\Model\ResourceModel\Event\Collection $collection */
            $collection = $this->collectionFactory->create();
            $collection->addFieldToFilter('subject_id', $this->customerSession->getCustomerId());
            $collection->distinct(true);

            return $collection;
        }

        return false;
    }

    /**
     * 
     */
    public function deleteViewedProductsForCurrentCustomer()
    {
        if ($products = $this->getViewedProductsForCurrentCustomer()) {
            /** @var \Magento\Reports\Model\ResourceModel\Event $resource */
            $resource = $this->resourceFactory->create();
            foreach($products as $product) {
                $resource->delete($product);
            }
        }
    }
}

Haven't tested this code, but in theory it should work.

On a sidenote: I don't know how much knowledge you have about Magento 2, but you should really understand the following core concepts:

  • Dependency Injection
  • Repositories
  • Auto generated code (factories)

The Magento documentation has tons of examples about this. Besides that it will also help to dive in the following programming principles:

  • S.O.L.I.D programming
  • Composition over Inheritance
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top