![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/cartforge.co/vendor/magento/framework/Mview/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\Framework\Mview; use InvalidArgumentException; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; use Magento\Framework\Mview\View\ChangeLogBatchWalkerFactory; use Magento\Framework\Mview\View\ChangeLogBatchWalkerInterface; use Magento\Framework\Mview\View\ChangelogTableNotExistsException; use Magento\Framework\Mview\View\SubscriptionFactory; use Exception; use Magento\Framework\Mview\View\SubscriptionInterface; /** * Mview * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class View extends DataObject implements ViewInterface, ViewSubscriptionInterface { /** * Default batch size for partial reindex */ public const DEFAULT_BATCH_SIZE = 1000; /** * @var string */ protected $_idFieldName = 'view_id'; /** * @var ConfigInterface */ protected $config; /** * @var ActionFactory */ protected $actionFactory; /** * @var View\ChangelogInterface */ protected $changelog; /** * @var View\SubscriptionFactory */ protected $subscriptionFactory; /** * @var View\StateInterface */ protected $state; /** * @var array */ private $changelogBatchSize; /** * @var ChangeLogBatchWalkerFactory */ private $changeLogBatchWalkerFactory; /** * @param ConfigInterface $config * @param ActionFactory $actionFactory * @param View\StateInterface $state * @param View\ChangelogInterface $changelog * @param SubscriptionFactory $subscriptionFactory * @param array $data * @param array $changelogBatchSize * @param ChangeLogBatchWalkerFactory $changeLogBatchWalkerFactory */ public function __construct( ConfigInterface $config, ActionFactory $actionFactory, View\StateInterface $state, View\ChangelogInterface $changelog, SubscriptionFactory $subscriptionFactory, array $data = [], array $changelogBatchSize = [], ChangeLogBatchWalkerFactory $changeLogBatchWalkerFactory = null ) { $this->config = $config; $this->actionFactory = $actionFactory; $this->state = $state; $this->changelog = $changelog; $this->subscriptionFactory = $subscriptionFactory; $this->changelogBatchSize = $changelogBatchSize; parent::__construct($data); $this->changeLogBatchWalkerFactory = $changeLogBatchWalkerFactory ?: ObjectManager::getInstance()->get(ChangeLogBatchWalkerFactory::class); } /** * Return ID * * @return string */ public function getId() { return $this->getData($this->_idFieldName); } /** * Set ID * * @param string $id * @return $this */ public function setId($id) { $this->setData($this->_idFieldName, $id); return $this; } /** * Id field name setter * * @param string $name * @return $this */ public function setIdFieldName($name) { $this->_idFieldName = $name; return $this; } /** * Id field name getter * * @return string */ public function getIdFieldName() { return $this->_idFieldName; } /** * Return view action class * * @return string */ public function getActionClass() { return $this->getData('action_class'); } /** * Return view group * * @return string */ public function getGroup() { return $this->getData('group'); } /** * Return view subscriptions * * @return array */ public function getSubscriptions() { return $this->getData('subscriptions'); } /** * Fill view data from config * * @param string $viewId * @return ViewInterface * @throws InvalidArgumentException */ public function load($viewId) { $view = $this->config->getView($viewId); if (empty($view) || empty($view['view_id']) || $view['view_id'] !== $viewId) { throw new InvalidArgumentException("{$viewId} view does not exist."); } $this->setId($viewId); $this->setData($view); return $this; } /** * Create subscriptions * * @return ViewInterface * @throws Exception */ public function subscribe() { if ($this->getState()->getMode() !== View\StateInterface::MODE_ENABLED) { // Create changelog table $this->getChangelog()->create(); foreach ($this->getSubscriptions() as $subscriptionConfig) { $this->initSubscriptionInstance($subscriptionConfig)->create(); } // Update view state $this->getState()->setMode(View\StateInterface::MODE_ENABLED)->save(); } return $this; } /** * Remove subscriptions * * @return ViewInterface * @throws Exception */ public function unsubscribe() { if ($this->getState()->getMode() != View\StateInterface::MODE_DISABLED) { // Remove subscriptions foreach ($this->getSubscriptions() as $subscriptionConfig) { $this->initSubscriptionInstance($subscriptionConfig)->remove(); } // Update view state $this->getState()->setMode(View\StateInterface::MODE_DISABLED)->save(); } return $this; } /** * Materialize view by IDs in changelog * * @return void * @throws Exception */ public function update() { if (!$this->isIdle() || !$this->isEnabled()) { return; } try { $currentVersionId = $this->getChangelog()->getVersion(); } catch (ChangelogTableNotExistsException $e) { return; } $lastVersionId = (int)$this->getState()->getVersionId(); $action = $this->actionFactory->get($this->getActionClass()); try { $this->getState()->setStatus(View\StateInterface::STATUS_WORKING)->save(); $this->executeAction($action, $lastVersionId, $currentVersionId); $this->getState()->loadByView($this->getId()); $statusToRestore = $this->getState()->getStatus() === View\StateInterface::STATUS_SUSPENDED ? View\StateInterface::STATUS_SUSPENDED : View\StateInterface::STATUS_IDLE; $this->getState()->setVersionId($currentVersionId)->setStatus($statusToRestore)->save(); } catch (\Throwable $exception) { $this->getState()->loadByView($this->getId()); $statusToRestore = $this->getState()->getStatus() === View\StateInterface::STATUS_SUSPENDED ? View\StateInterface::STATUS_SUSPENDED : View\StateInterface::STATUS_IDLE; $this->getState()->setStatus($statusToRestore)->save(); if (!$exception instanceof \Exception) { $exception = new \RuntimeException( 'Error when updating an mview', 0, $exception ); } throw $exception; } } /** * Execute action from last version to current version, by batches * * @param ActionInterface $action * @param int $lastVersionId * @param int $currentVersionId * @return void * @throws \Exception */ private function executeAction(ActionInterface $action, int $lastVersionId, int $currentVersionId) { $batchSize = isset($this->changelogBatchSize[$this->getChangelog()->getViewId()]) ? (int) $this->changelogBatchSize[$this->getChangelog()->getViewId()] : self::DEFAULT_BATCH_SIZE; $vsFrom = $lastVersionId; while ($vsFrom < $currentVersionId) { $walker = $this->getWalker(); $ids = $walker->walk($this->getChangelog(), $vsFrom, $currentVersionId, $batchSize); if (empty($ids)) { break; } $vsFrom += $batchSize; $action->execute($ids); } } /** * Create and validate walker class for changelog * * @return ChangeLogBatchWalkerInterface|mixed * @throws Exception */ private function getWalker(): ChangeLogBatchWalkerInterface { $config = $this->config->getView($this->changelog->getViewId()); $walkerClass = $config['walker']; return $this->changeLogBatchWalkerFactory->create($walkerClass); } /** * Suspend view updates and set version ID to changelog's end * * @return void * @throws Exception */ public function suspend() { if ($this->getState()->getMode() === View\StateInterface::MODE_ENABLED) { $state = $this->getState(); $state->setVersionId($this->getChangelog()->getVersion()); $state->setStatus(View\StateInterface::STATUS_SUSPENDED); $state->save(); } } /** * Resume view updates * * @return void * @throws Exception */ public function resume() { $state = $this->getState(); if ($state->getStatus() === View\StateInterface::STATUS_SUSPENDED) { $state->setStatus(View\StateInterface::STATUS_IDLE); $state->save(); } } /** * Clear precessed changelog entries * * @return void */ public function clearChangelog() { if ($this->getState()->getMode() === View\StateInterface::MODE_ENABLED) { $this->getChangelog()->clear($this->getState()->getVersionId()); } } /** * Return related state object * * @return View\StateInterface */ public function getState() { if (!$this->state->getViewId()) { $this->state->loadByView($this->getId()); } return $this->state; } /** * Set view state object * * @param View\StateInterface $state * @return ViewInterface */ public function setState(View\StateInterface $state) { $this->state = $state; return $this; } /** * Check whether view is enabled * * @return bool */ public function isEnabled() { return $this->getState()->getMode() === View\StateInterface::MODE_ENABLED; } /** * Check whether view is idle * * @return bool */ public function isIdle() { return $this->getState()->getStatus() === View\StateInterface::STATUS_IDLE; } /** * Check whether view is working * * @return bool */ public function isWorking() { return $this->getState()->getStatus() === View\StateInterface::STATUS_WORKING; } /** * Check whether view is suspended * * @return bool */ public function isSuspended() { return $this->getState()->getStatus() === View\StateInterface::STATUS_SUSPENDED; } /** * Return view updated datetime * * @return string */ public function getUpdated() { return $this->getState()->getUpdated(); } /** * Retrieve linked changelog * * @return View\ChangelogInterface */ public function getChangelog() { if (!$this->changelog->getViewId()) { $this->changelog->setViewId($this->getId()); } return $this->changelog; } /** * Initializes Subscription instance * * @param array $subscriptionConfig * @return SubscriptionInterface */ public function initSubscriptionInstance(array $subscriptionConfig): SubscriptionInterface { return $this->subscriptionFactory->create( [ 'view' => $this, 'tableName' => $subscriptionConfig['name'], 'columnName' => $subscriptionConfig['column'], 'subscriptionModel' => !empty($subscriptionConfig['subscription_model']) ? $subscriptionConfig['subscription_model'] : SubscriptionFactory::INSTANCE_NAME, ] ); } }