Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BEG-151: Add custom StagedProductAttributeSubscription for catalog_product_link table #13 #14

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 221 additions & 0 deletions Model/Mview/View/Attribute/CatalogProductLinkSubscription.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
<?php
/*
* Copyright (c) Aligent Consulting. All rights reserved.
*/
namespace Aligent\Prerender\Model\Mview\View\Attribute;

use Magento\Catalog\Api\Data\CategoryInterface;
use Magento\Framework\DB\Ddl\Trigger;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Ddl\TriggerFactory;
use Magento\Framework\EntityManager\EntityMetadata;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Mview\View\ChangelogInterface;
use Magento\Framework\Mview\View\CollectionInterface;
use Magento\Framework\Mview\ViewInterface;
use Magento\Framework\Mview\Config;
use Magento\Framework\Mview\View\Changelog;

/**
* Subscription model class for "catalog_product_link" table
*/
class CatalogProductLinkSubscription extends \Magento\Framework\Mview\View\Subscription
{
private const CATALOG_PRODUCT_LINK_PRODUCT_ID = 'product_id';

/**
* @var EntityMetadata
*/
protected $entityMetadata;

/**
* Save state of Subscription for build statement for retrieving entity id value
*
* @var array
*/
private $statementState = [];

/**
* List of columns that can be updated in a subscribed table
* without creating a new change log entry
*
* @var array
*/
private $ignoredUpdateColumns;

/**
* @param ResourceConnection $resource
* @param TriggerFactory $triggerFactory
* @param CollectionInterface $viewCollection
* @param ViewInterface $view
* @param string $tableName
* @param string $columnName
* @param MetadataPool $metadataPool
* @param string|null $entityInterface
* @param array $ignoredUpdateColumns
* @param array $ignoredUpdateColumnsBySubscription
* @param Config|null $mviewConfig
* @throws \Exception
*/
public function __construct(
ResourceConnection $resource,
TriggerFactory $triggerFactory,
CollectionInterface $viewCollection,
ViewInterface $view,
$tableName,
$columnName,
MetadataPool $metadataPool,
$entityInterface = null,
$ignoredUpdateColumns = [],
$ignoredUpdateColumnsBySubscription = [],
Config $mviewConfig = null
) {
parent::__construct(
$resource,
$triggerFactory,
$viewCollection,
$view,
$tableName,
$columnName,
$ignoredUpdateColumns,
$ignoredUpdateColumnsBySubscription,
$mviewConfig
);
$this->ignoredUpdateColumns = $ignoredUpdateColumns;
$this->entityMetadata = $metadataPool->getMetadata($entityInterface);
}

/**
* Build trigger statement for INSERT, UPDATE, DELETE events
*
* @param string $event
* @param ViewInterface $view
* @return string
*/
protected function buildStatement(string $event, ViewInterface $view): string
{
$triggerBody = '';

switch ($event) {
case Trigger::EVENT_INSERT:
case Trigger::EVENT_UPDATE:
$eventType = 'NEW';
break;
case Trigger::EVENT_DELETE:
$eventType = 'OLD';
break;
default:
return $triggerBody;
}
$entityIdHash = $this->entityMetadata->getIdentifierField()
. $this->entityMetadata->getEntityTable()
. $this->entityMetadata->getLinkField()
. $event;
if (!isset($this->statementState[$entityIdHash])) {
$triggerBody = $this->buildEntityIdStatementByEventType($eventType);
$this->statementState[$entityIdHash] = true;
}

$trigger = $this->buildStatementByEventType($view, $event);
if ($event == Trigger::EVENT_UPDATE) {
$trigger = $this->addConditionsToTrigger($trigger);
}
$triggerBody .= $trigger;

return $triggerBody;
}

/**
* Adds quoted conditions to the trigger
*
* @param string $trigger
* @return string
*/
private function addConditionsToTrigger(string $trigger): string
{
$tableName = $this->resource->getTableName($this->getTableName());
if ($this->connection->isTableExists($tableName)
&& $describe = $this->connection->describeTable($tableName)
) {
$columnNames = array_column($describe, 'COLUMN_NAME');
$columnNames = array_diff($columnNames, $this->ignoredUpdateColumns);
if ($columnNames) {
$columns = [];
foreach ($columnNames as $columnName) {
$columns[] = sprintf(
'NOT(NEW.%1$s <=> OLD.%1$s)',
$this->connection->quoteIdentifier($columnName)
);
}
$trigger = sprintf(
"IF (%s) THEN %s END IF;",
implode(' OR ', $columns),
$trigger
);
}
}

return $trigger;
}

/**
* Build trigger body
*
* @param string $eventType
* @return string
*/
private function buildEntityIdStatementByEventType(string $eventType): string
{
return vsprintf(
'SET @entity_id = (SELECT %1$s FROM %2$s WHERE %3$s = %4$s.%5$s);',
[
$this->connection->quoteIdentifier(
$this->entityMetadata->getIdentifierField()
),
$this->connection->quoteIdentifier(
$this->resource->getTableName($this->entityMetadata->getEntityTable())
),
$this->connection->quoteIdentifier(
$this->entityMetadata->getLinkField()
),
$eventType,
self::CATALOG_PRODUCT_LINK_PRODUCT_ID
]
) . PHP_EOL;
}

/**
* Override column name as we need to use entity_id instead of link field
*
* @param string $prefix
* @param ViewInterface $view
* @return string
*/
public function getEntityColumn(string $prefix, ViewInterface $view): string
{
return '@entity_id';
}

/**
* Build sql statement for trigger
*
* @param ViewInterface $view
* @param string $event
* @return string
* @throws \Exception
*/
private function buildStatementByEventType(ViewInterface $view, string $event): string
{
$columns = $this->prepareColumns($view, $event);
return vsprintf(
'INSERT IGNORE INTO %s (%s) values(%s);',
[
$this->connection->quoteIdentifier(
$this->resource->getTableName($view->getChangelog()->getName())
),
implode(', ', $columns['column_names']),
implode(', ', $columns['column_values'])
]
);
}
}
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
"description": "Prerender service integration for Magento 2, providing recaching for product URLs",
"require": {
"php": ">=7.4",
"magento/framework": "*"
"magento/framework": "*",
"magento/module-store": "*",
"magento/module-catalog": "*",
"magento/module-configurable-product": "*",
"magento/module-url-rewrite": "*"
},
"require-dev": {
"magento/magento-coding-standard": ">=23"
Expand Down
5 changes: 5 additions & 0 deletions etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,9 @@
</argument>
</arguments>
</type>
<type name="Aligent\Prerender\Model\Mview\View\Attribute\CatalogProductLinkSubscription">
<arguments>
<argument name="entityInterface" xsi:type="string">Magento\Catalog\Api\Data\ProductInterface</argument>
</arguments>
</type>
</config>
9 changes: 8 additions & 1 deletion etc/module.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,12 @@

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Aligent_Prerender"/>
<module name="Aligent_Prerender">
<sequence>
<module name="Magento_Store"/>
<module name="Magento_Catalog"/>
<module name="Magento_ConfigurableProduct"/>
<module name="Magento_UrlRewrite"/>
</sequence>
</module>
</config>
4 changes: 2 additions & 2 deletions etc/mview.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<table name="catalog_product_entity_text" entity_column="entity_id" />
<table name="catalog_product_entity_tier_price" entity_column="entity_id" />
<table name="catalog_product_entity_varchar" entity_column="entity_id" />
<table name="catalog_product_link" entity_column="product_id" />
<table name="catalog_product_link" entity_column="product_id" subscription_model="Aligent\Prerender\Model\Mview\View\Attribute\CatalogProductLinkSubscription"/>
<table name="catalogrule_product_price" entity_column="product_id" />
<table name="cataloginventory_stock_item" entity_column="product_id" />
</subscriptions>
Expand All @@ -41,7 +41,7 @@
<table name="catalog_product_entity_text" entity_column="entity_id" />
<table name="catalog_product_entity_tier_price" entity_column="entity_id" />
<table name="catalog_product_entity_varchar" entity_column="entity_id" />
<table name="catalog_product_link" entity_column="product_id" />
<table name="catalog_product_link" entity_column="product_id" subscription_model="Aligent\PrerenderIo\Model\Mview\View\Attribute\CatalogProductLinkSubscription"/>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mausham-shrestha-aligent Please rename the module namespace PrerenderIo to Prerender otherwise we're getting error.

Warning: class_implements(): Class Aligent\PrerenderIo\Model\Mview\View\Attribute\CatalogProductLinkSubscription does not exist and could not be loaded in /app/vendor/magento/framework/Mview/Config/Converter.php on line 108

<table name="catalogrule_product_price" entity_column="product_id" />
<table name="cataloginventory_stock_item" entity_column="product_id" />
<table name="catalog_category_product" entity_column="product_id" />
Expand Down
Loading