Files
kupshop/bundles/KupShop/CatalogBundle/Parameters/ParameterFinder.php
2025-08-02 16:30:27 +02:00

241 lines
7.5 KiB
PHP

<?php
namespace KupShop\CatalogBundle\Parameters;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Query\Operator;
class ParameterFinder
{
use \DatabaseCommunication;
protected $listParameter;
protected $listParameterValues;
protected $parameterInstancesCache = [];
protected function loadParametersCache()
{
if (is_null($this->listParameter)) {
$this->listParameter = sqlFetchAll(sqlQuery('SELECT par.*, LOWER(name) as name FROM parameters par'), 'id');
}
}
/**
* @return \Parameter
*/
public function getParameter($id_parameter)
{
$this->loadParametersCache();
if (!($this->parameterInstancesCache[$id_parameter] ?? false)) {
$parameter = new \Parameter();
$parameter->createFromArray($this->listParameter[$id_parameter]);
$this->parameterInstancesCache[$id_parameter] = $parameter;
}
return $this->parameterInstancesCache[$id_parameter];
}
public function getParameterById(int $parameterId): ?\Parameter
{
$this->loadParametersCache();
if (!($this->listParameter[$parameterId] ?? false)) {
return null;
}
if (!($this->parameterInstancesCache[$parameterId] ?? false)) {
$parameter = new \Parameter();
$parameter->createFromArray($this->listParameter[$parameterId]);
$this->parameterInstancesCache[$parameterId] = $parameter;
}
return $this->parameterInstancesCache[$parameterId];
}
public function getParameterId(string $name): ?int
{
$this->loadParametersCache();
$nameLower = mb_strtolower($name);
foreach ($this->listParameter as $id => $parameter) {
if ($parameter['name'] == $nameLower) {
return (int) $id;
}
}
return null;
}
public function findParameter($name, $type = 'list')
{
if ($name == '') {
return null;
}
$this->loadParametersCache();
if ($parameterId = $this->getParameterId($name)) {
return $parameterId;
}
$nameLower = mb_strtolower($name);
$max_position = returnSQLResult('SELECT MAX(position) FROM parameters');
try {
$index = sqlGetConnection()->transactional(function () use ($name, $max_position, $type) {
$this->insertSQL('parameters', ['name' => $name, 'position' => $max_position + 1, 'value_type' => $type]);
return sqlInsertId();
});
} catch (UniqueConstraintViolationException $e) {
$index = $this->selectSQL('parameters', ['name' => $name])->fetch()['id'];
}
$this->listParameter[$index] = ['id' => $index, 'name' => $nameLower, 'position' => $max_position + 1, 'value_type' => $type];
return $index;
}
public function getParameterValueId(int $parameterId, string $value): ?int
{
if ($index = array_search(mb_strtolower($value), $this->getListParametersValuesCache($parameterId))) {
return $index;
}
return null;
}
public function findParameterValue($parameter_id, $value)
{
if ($value == '') {
return null;
}
$params = $this->getListParametersValuesCache($parameter_id);
if ($index = array_search(mb_strtolower($value), $params)) {
return $index;
}
try {
$index = sqlGetConnection()->transactional(function () use ($value, $parameter_id) {
$this->insertSQL('parameters_list', ['value' => $value, 'id_parameter' => $parameter_id]);
return sqlInsertId();
});
} catch (\Exception $e) {
$index = sqlFetchAssoc($this->selectSQL('parameters_list', ['value' => $value, 'id_parameter' => $parameter_id], ['id']))['id'];
}
$this->listParameterValues[$parameter_id][$index] = mb_strtolower($value);
return $index;
}
private function getListParametersValuesCache(int $parameterId): array
{
if (!isset($this->listParameterValues[$parameterId])) {
$values = sqlQuery('SELECT id, LOWER(value) as value
FROM parameters_list WHERE id_parameter=:id_parameter',
['id_parameter' => $parameterId]);
$this->listParameterValues[$parameterId] = sqlFetchAll($values, ['id' => 'value']);
}
return $this->listParameterValues[$parameterId] ?? [];
}
/**
* @param string $parameter Parameter name
* @param string $value Parameter value
* @param string $type Parameter type
*
* @return array array with keys "id_parameter" and "value"
*/
public function findParameterAndValue($parameter, $value, $type = 'list')
{
$id_parameter = $this->findParameter($parameter, $type);
if ($type == 'list') {
$value = $this->findParameterValue($id_parameter, $value);
}
return ['id_parameter' => $id_parameter, 'value' => $value];
}
/** Replace all product parameter values with new one.
*/
public function setProductParameters($id_product, $id_parameter, $values)
{
$parameter = $this->getParameter($id_parameter);
$data = ['id_parameter' => $id_parameter, 'id_product' => $id_product];
$this->deleteSQL('parameters_products', $data);
foreach ($values as $value) {
if (empty($value)) {
continue;
}
$data['value'] = $value;
$parameter->setValue($data);
}
}
/**
* Narozdil od `setProductParameters` neprovadi pokazde delete a insert, takze je mene narocna pro
* databazi a negeneruje tak velke mnozstvi dat do binlogu.
*/
public function updateProductParameters(int $productId, int $parameterId, array $values): void
{
if (!($parameter = $this->getParameterById($parameterId))) {
return;
}
$valueField = "value_{$parameter->value_type}";
// nactu si aktualni hodnoty parametru od produktu
$oldValues = sqlQueryBuilder()
->select('id', $valueField)
->from('parameters_products')
->where(Operator::equals(['id_parameter' => $parameterId, 'id_product' => $productId]))
->orderBy('id', 'ASC')
->execute()->fetchAllAssociative();
$oldValuesOnly = array_map(fn ($x) => $x[$valueField], $oldValues);
// najdu si hodnoty, ktere mam smazat
$deleteDiff = array_diff_assoc($oldValuesOnly, $values);
// najdu si hodnoty, ktere mam insertovat
$insertDiff = array_diff_assoc($values, $oldValuesOnly);
$deleteIds = [];
// chci to mazat podle ID, takze dohledam ID
foreach ($deleteDiff as $position => $value) {
$deleteIds[] = $oldValues[$position]['id'];
}
// provedu delete
if (!empty($deleteIds)) {
sqlQueryBuilder()
->delete('parameters_products')
->andWhere(Operator::inIntArray($deleteIds, 'id'))
->execute();
}
// provedu insert
foreach ($insertDiff as $value) {
sqlQueryBuilder()
->insert('parameters_products')
->directValues(
[
'id_parameter' => $parameterId,
'id_product' => $productId,
$valueField => $value,
]
)->execute();
}
}
}