- Published: 2023-11-16
- Author: Nickolas Burr
Table of Contents
This is the implementation class for SelectQueryFetchStrategyInterface
.
<?php
declare(strict_types=1);
namespace Vendor\Package\Model\ResourceModel\SomeEntity;
use Magento\Framework\Data\Collection\EntityFactoryInterface;
use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use Psr\Log\LoggerInterface;
use Throwable;
use UnexpectedValueException;
use Vendor\Package\Api\SelectQueryFetchStrategyInterface;
class Collection extends AbstractCollection
{
/**
* @param EntityFactoryInterface $entityFactory
* @param LoggerInterface $logger
* @param SelectQueryFetchStrategyInterface $fetchStrategy
* @param ManagerInterface $eventManager
* @param AdapterInterface|null $connection
* @param AbstractDb|null $resource
* @param mixed[] $data
* @return void
*/
public function __construct(
EntityFactoryInterface $entityFactory,
LoggerInterface $logger,
SelectQueryFetchStrategyInterface $fetchStrategy,
ManagerInterface $eventManager,
?AdapterInterface $connection = null,
?AbstractDb $resource = null,
private array $data = []
) {
parent::__construct(
$entityFactory,
$logger,
$fetchStrategy,
$eventManager,
$connection,
$resource
);
}
/**
* @return string|null
*/
public function getSpecificColumnValue(): ?string
{
return $this->_fetchStrategy->fetchOne($this->getSelect());
}
}
<?php
declare(strict_types=1);
namespace Vendor\Package\Model\Query;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\DB\Select;
use Magento\Framework\Serialize\SerializerInterface;
use Psr\Log\LoggerInterface;
use Vendor\Package\Api\SelectQueryFetchStrategyInterface;
use function hash;
use function implode;
use function json_encode;
use function json_last_error;
use function json_last_error_msg;
use function ksort;
use function sprintf;
use const JSON_ERROR_NONE;
use const JSON_FORCE_OBJECT;
use const SORT_STRING;
class SelectQueryFetchStrategy implements SelectQueryFetchStrategyInterface
{
private const JSON_MAX_DEPTH = 4;
/**
* @param LoggerInterface $logger
* @param SerializerInterface $serializer
* @param CacheInterface|null $cache
* @param string[] $cacheTags
* @param int $cacheTtl
* @param string $algo
* @return void
*/
public function __construct(
private readonly LoggerInterface $logger,
private readonly SerializerInterface $serializer,
private ?CacheInterface $cache = null,
private readonly array $cacheTags = [],
private readonly int $cacheTtl = 3600,
private readonly string $algo = 'crc32b'
) {}
/**
* {@inheritdoc}
*/
public function fetchAll(Select $select, array $bind = []): array
{
/** @var string|null $val */
/** @var string|null $key */
[$val, $key] = $this->getCacheValue(
$select,
$bind,
__METHOD__
);
if (!empty($val)) {
return (array) $this->serializer->unserialize($val);
}
try {
/** @var mixed[]|false $data */
$data = $select->getConnection()->fetchAll($select, $bind);
if ($data !== false) {
$this->cache?->save(
$this->serializer->serialize($data),
$key,
$this->cacheTags,
$this->cacheTtl
);
}
return (array) $data;
} catch (Throwable $e) {
$this->logger->error($e->getMessage());
return [];
}
}
/**
* {@inheritdoc}
*/
public function fetchAssoc(Select $select, array $bind = []): array
{
/** @var string|null $val */
/** @var string|null $key */
[$val, $key] = $this->getCacheValue(
$select,
$bind,
__METHOD__
);
if (!empty($val)) {
return (array) $this->serializer->unserialize($val);
}
try {
/** @var mixed[]|false $data */
$data = $select->getConnection()->fetchAssoc($select, $bind);
if ($data !== false) {
$this->cache?->save(
$this->serializer->serialize($data),
$key,
$this->cacheTags,
$this->cacheTtl
);
}
return (array) $data;
} catch (Throwable $e) {
$this->logger->error($e->getMessage());
return [];
}
}
/**
* {@inheritdoc}
*/
public function fetchCol(Select $select, array $bind = []): array
{
/** @var string|null $val */
/** @var string|null $key */
[$val, $key] = $this->getCacheValue(
$select,
$bind,
__METHOD__
);
if (!empty($val)) {
return (array) $this->serializer->unserialize($val);
}
try {
/** @var mixed[]|false $data */
$data = $select->getConnection()->fetchCol($select, $bind);
if ($data !== false) {
$this->cache?->save(
$this->serializer->serialize($data),
$key,
$this->cacheTags,
$this->cacheTtl
);
}
return (array) $data;
} catch (Throwable $e) {
$this->logger->error($e->getMessage());
return [];
}
}
/**
* {@inheritdoc}
*/
public function fetchOne(Select $select, array $bind = []): ?string
{
/** @var string|null $val */
/** @var string|null $key */
[$val, $key] = $this->getCacheValue(
$select,
$bind,
__METHOD__
);
if (!empty($val)) {
return $val;
}
try {
/** @var string|false $data */
$data = $select->getConnection()->fetchOne($select, $bind);
if ($data !== false) {
$this->cache?->save(
$this->serializer->serialize($data),
$key,
$this->cacheTags,
$this->cacheTtl
);
}
return (string) $data ?: null;
} catch (Throwable $e) {
$this->logger->error($e->getMessage());
return [];
}
}
/**
* {@inheritdoc}
*/
public function fetchPairs(Select $select, array $bind = []): array
{
/** @var string|null $val */
/** @var string|null $key */
[$val, $key] = $this->getCacheValue(
$select,
$bind,
__METHOD__
);
if (!empty($val)) {
return (array) $this->serializer->unserialize($val);
}
try {
/** @var mixed[]|false $data */
$data = $select->getConnection()->fetchPairs($select, $bind);
if ($data !== false) {
$this->cache?->save(
$this->serializer->serialize($data),
$key,
$this->cacheTags,
$this->cacheTtl
);
}
return (array) $data;
} catch (Throwable $e) {
$this->logger->error($e->getMessage());
return [];
}
}
/**
* {@inheritdoc}
*/
public function fetchRow(Select $select, array $bind = []): array
{
/** @var string|null $val */
/** @var string|null $key */
[$val, $key] = $this->getCacheValue(
$select,
$bind,
__METHOD__
);
if (!empty($val)) {
return (array) $this->serializer->unserialize($val);
}
try {
/** @var mixed[]|false $data */
$data = $select->getConnection()->fetchRow($select, $bind);
if ($data !== false) {
$this->cache?->save(
$this->serializer->serialize($data),
$key,
$this->cacheTags,
$this->cacheTtl
);
}
return (array) $data;
} catch (Throwable $e) {
$this->logger->error($e->getMessage());
return [];
}
}
/**
* @param Select $select
* @param mixed[] $bind
* @param string $caller
* @return mixed[]|null
*/
private function getCacheValue(
Select $select,
array $bind,
string $caller
): ?array {
if ($this->cache === null) {
return null;
}
if (!empty($bind)) {
ksort($bind, SORT_STRING);
}
/** @var string $params */
$params = json_encode(
$bind,
JSON_FORCE_OBJECT,
self::JSON_MAX_DEPTH
);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new UnexpectedValueException(
sprintf(
'Unable to serialize bind parameters: "%s"',
json_last_error_msg()
)
);
}
/** @var string $cacheKey */
$cacheKey = sprintf(
'sqfs-%s-%s',
$caller,
hash(
$this->algo,
implode('', [$select, $params])
)
);
return [
$this->cache?->load($cacheKey) ?: null,
$cacheKey,
];
}
}
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Vendor\Package\Api\SelectQueryFetchStrategyInterface" type="Vendor\Package\Model\Query\SelectQueryFetchStrategy"/>
</config>