feat: remove cache, refactor

This commit is contained in:
2025-08-08 22:25:00 +03:00
parent 4114c3366e
commit 7404ecb33e
7 changed files with 474 additions and 395 deletions

View File

@@ -29,4 +29,7 @@ link:
dev:
$(MAKE) link && \
cd spa && npm run dev
cd spa && npm run dev
lint:
docker compose exec -w /module/oc_telegram_shop/upload/oc_telegram_shop web bash -c "./vendor/bin/phpstan analyse src framework"

View File

@@ -12,7 +12,7 @@ services:
deploy:
resources:
limits:
memory: 256M
memory: 512M
environment:
- WEB_DOCUMENT_ROOT=/web/upload
- PHP_DISPLAY_ERRORS=1

View File

@@ -27,6 +27,7 @@
"symfony/cache": "^5.4"
},
"require-dev": {
"roave/security-advisories": "dev-latest"
"roave/security-advisories": "dev-latest",
"phpstan/phpstan": "^2.1"
}
}

View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "329d7196ee1db3f0f4e8b3552e28f83a",
"content-hash": "119f24aafb5ae0828f70c3c57fa07234",
"packages": [
{
"name": "graham-campbell/result-type",
@@ -1733,6 +1733,64 @@
}
],
"packages-dev": [
{
"name": "phpstan/phpstan",
"version": "2.1.22",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4",
"reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4",
"shasum": ""
},
"require": {
"php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
},
"bin": [
"phpstan",
"phpstan.phar"
],
"type": "library",
"autoload": {
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"keywords": [
"dev",
"static analysis"
],
"support": {
"docs": "https://phpstan.org/user-guide/getting-started",
"forum": "https://github.com/phpstan/phpstan/discussions",
"issues": "https://github.com/phpstan/phpstan/issues",
"security": "https://github.com/phpstan/phpstan/security/policy",
"source": "https://github.com/phpstan/phpstan-src"
},
"funding": [
{
"url": "https://github.com/ondrejmirtes",
"type": "github"
},
{
"url": "https://github.com/phpstan",
"type": "github"
}
],
"time": "2025-08-04T19:17:37+00:00"
},
{
"name": "roave/security-advisories",
"version": "dev-latest",

View File

@@ -1,15 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Handlers;
use Openguru\OpenCartFramework\Config\Settings;
use Openguru\OpenCartFramework\Http\JsonResponse;
use Openguru\OpenCartFramework\Http\Request;
use Openguru\OpenCartFramework\ImageTool\ImageToolInterface;
use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Contracts\Cache\ItemInterface;
class CategoriesHandler
{
@@ -18,45 +16,41 @@ class CategoriesHandler
private Builder $queryBuilder;
private ImageToolInterface $ocImageTool;
public function __construct(Builder $queryBuilder, ImageToolInterface $ocImageTool, Settings $settings)
public function __construct(Builder $queryBuilder, ImageToolInterface $ocImageTool)
{
$this->queryBuilder = $queryBuilder;
$this->ocImageTool = $ocImageTool;
$this->settings = $settings;
}
public function index(): JsonResponse
{
$cache = new FilesystemAdapter();
$languageId = 1;
$categories = $cache->get('main-page-categories', function (ItemInterface $item) {
$item->expiresAfter($this->settings->get('cache_categories_main', 60 * 5));
$languageId = 1;
$categoriesFlat = $this->queryBuilder->newQuery()
->select([
'categories.category_id' => 'id',
'categories.parent_id' => 'parent_id',
'categories.image' => 'image',
'descriptions.name' => 'name',
'descriptions.description' => 'description',
])
->from(db_table('category'), 'categories')
->join(
db_table('category_description') . ' AS descriptions',
function (JoinClause $join) use ($languageId) {
$join->on('categories.category_id', '=', 'descriptions.category_id')
->where('descriptions.language_id', '=', $languageId);
}
)
->where('categories.status', '=', 1)
->orderBy('parent_id')
->orderBy('sort_order')
->get();
$categoriesFlat = $this->queryBuilder->newQuery()
->select([
'categories.category_id' => 'id',
'categories.parent_id' => 'parent_id',
'categories.image' => 'image',
'descriptions.name' => 'name',
'descriptions.description' => 'description',
])
->from(db_table('category'), 'categories')
->join(
db_table('category_description') . ' AS descriptions',
function (JoinClause $join) use ($languageId) {
$join->on('categories.category_id', '=', 'descriptions.category_id')
->where('descriptions.language_id', '=', $languageId);
}
)
->where('categories.status', '=', 1)
->orderBy('parent_id')
->orderBy('sort_order')
->get();
$categories = $this->buildCategoryTree($categoriesFlat);
$categories = $this->buildCategoryTree($categoriesFlat);
return array_map(static function ($category) {
return new JsonResponse([
'data' => array_map(static function ($category) {
return [
'id' => (int)$category['id'],
'image' => $category['image'],
@@ -64,11 +58,7 @@ class CategoriesHandler
'description' => $category['description'],
'children' => $category['children'],
];
}, $categories);
});
return new JsonResponse([
'data' => $categories,
}, $categories),
]);
}

View File

@@ -1,191 +1,32 @@
<?php
declare(strict_types=1);
namespace App\Handlers;
use App\Adapters\OcModelCatalogProductAdapter;
use App\Decorators\OcRegistryDecorator;
use Cart\Currency;
use Cart\Tax;
use App\Services\ProductsService;
use Exception;
use Openguru\OpenCartFramework\Config\Settings;
use Openguru\OpenCartFramework\Http\JsonResponse;
use Openguru\OpenCartFramework\Http\Request;
use Openguru\OpenCartFramework\Http\Response;
use Openguru\OpenCartFramework\ImageTool\ImageToolInterface;
use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Support\PaginationHelper;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Contracts\Cache\ItemInterface;
use Openguru\OpenCartFramework\Logger\Logger;
use RuntimeException;
class ProductsHandler
{
private Builder $queryBuilder;
private Currency $currency;
private Tax $tax;
private Settings $settings;
private OcModelCatalogProductAdapter $ocModelCatalogProduct;
private ImageToolInterface $ocImageTool;
private OcRegistryDecorator $oc;
private ProductsService $productsService;
private Logger $logger;
public function __construct(
Builder $queryBuilder,
Currency $currency,
Tax $tax,
Settings $settings,
OcModelCatalogProductAdapter $ocModelCatalogProduct,
ImageToolInterface $ocImageTool,
OcRegistryDecorator $registry
) {
$this->queryBuilder = $queryBuilder;
$this->currency = $currency;
$this->tax = $tax;
$this->settings = $settings;
$this->ocModelCatalogProduct = $ocModelCatalogProduct;
$this->ocImageTool = $ocImageTool;
$this->oc = $registry;
}
private function getProductsResponse(array $params): array
public function __construct(Settings $settings, ProductsService $productsService, Logger $logger)
{
$page = $params['page'];
$perPage = $params['perPage'];
$categoryId = $params['categoryId'];
$search = $params['search'];
$forMainPage = $params['forMainPage'];
$featuredProducts = $params['featuredProducts'];
$mainpageProducts = $params['mainpageProducts'];
$languageId = 1;
$categoryName = '';
$imageWidth = 300;
$imageHeight = 300;
if ($categoryId) {
$categoryName = $this->queryBuilder->newQuery()
->select(['name'])
->from(db_table('category_description'), 'category')
->where('language_id', '=', $languageId)
->where('category_id', '=', $categoryId)
->value('name');
}
$productsQuery = $this->queryBuilder->newQuery()
->select([
'products.product_id' => 'product_id',
'products.quantity' => 'product_quantity',
'product_description.name' => 'product_name',
'products.price' => 'price',
'products.image' => 'product_image',
'products.tax_class_id' => 'tax_class_id',
])
->from(db_table('product'), 'products')
->join(
db_table('product_description') . ' AS product_description',
function (JoinClause $join) use ($languageId) {
$join->on('products.product_id', '=', 'product_description.product_id')
->where('product_description.language_id', '=', $languageId);
}
)
->when($categoryId !== 0, function (Builder $query) use ($categoryId) {
$query->join(
db_table('product_to_category') . ' AS product_to_category',
function (JoinClause $join) use ($categoryId) {
$join->on('product_to_category.product_id', '=', 'products.product_id')
->where('product_to_category.category_id', '=', $categoryId);
}
);
})
->when(
$forMainPage && $mainpageProducts === 'featured' && $featuredProducts,
function (Builder $query) use ($featuredProducts) {
$query->whereIn('products.product_id', $featuredProducts);
}
)
->when($search, function (Builder $query) use ($search) {
$query->where('product_description.name', 'LIKE', '%' . $search . '%');
});
$total = $productsQuery->count();
$lastPage = PaginationHelper::calculateLastPage($total, $perPage);
$hasMore = $page + 1 <= $lastPage;
$products = $productsQuery
->forPage($page, $perPage)
->orderBy($mainpageProducts === 'latest' ? 'date_modified' : 'viewed', 'DESC')
->get();
$productIds = Arr::pluck($products, 'product_id');
$productsImages = [];
if ($productIds) {
$productsImages = $this->queryBuilder->newQuery()
->select([
'products_images.product_id' => 'product_id',
'products_images.image' => 'image',
])
->from(db_table('product_image'), 'products_images')
->orderBy('products_images.sort_order', 'ASC')
->whereIn('product_id', $productIds)
->get();
}
$productsImagesMap = [];
foreach ($productsImages as $item) {
$productsImagesMap[$item['product_id']][] = [
'url' => $this->ocImageTool->resize($item['image'], $imageWidth, $imageHeight, 'placeholder.png'),
'alt' => 'Product Image',
];
}
return [
'data' => array_map(function ($product) use ($productsImagesMap, $imageWidth, $imageHeight) {
$allImages = [];
$image = $this->ocImageTool->resize(
$product['product_image'],
$imageWidth,
$imageHeight,
'placeholder.png'
);
$allImages[] = [
'url' => $image,
'alt' => $product['product_name'],
];
$price = $this->currency->format(
$this->tax->calculate(
$product['price'],
$product['tax_class_id'],
$this->settings->get('oc_config_tax'),
),
$this->settings->get('oc_default_currency'),
);
if (! empty($productsImagesMap[$product['product_id']])) {
$allImages = array_merge($allImages, $productsImagesMap[$product['product_id']]);
}
return [
'id' => (int) $product['product_id'],
'product_quantity' => (int) $product['product_quantity'],
'name' => $product['product_name'],
'price' => $price,
'images' => $allImages,
];
}, $products),
'meta' => [
'currentCategoryName' => $categoryName,
'hasMore' => $hasMore,
]
];
$this->settings = $settings;
$this->productsService = $productsService;
$this->logger = $logger;
}
public function handle(Request $request): JsonResponse
{
$cache = new FilesystemAdapter();
$page = (int) $request->get('page', 1);
$perPage = min((int) $request->get('perPage', 6), 15);
$categoryId = (int) $request->get('categoryId', 0);
@@ -194,45 +35,17 @@ class ProductsHandler
$featuredProducts = $this->settings->get('featured_products');
$mainpageProducts = $this->settings->get('mainpage_products');
if ($forMainPage && $page === 1) {
$response = $cache->get(
'main-page-products',
function (ItemInterface $cacheitem) use (
$page,
$perPage,
$categoryId,
$search,
$forMainPage,
$featuredProducts,
$mainpageProducts
): array {
$cacheitem->expiresAfter($this->settings->get('cache_products_main', 60 * 10));
return $this->getProductsResponse(
compact(
'page',
'perPage',
'categoryId',
'search',
'forMainPage',
'featuredProducts',
'mainpageProducts'
)
);
}
);
} else {
$response = $this->getProductsResponse(
compact(
'page',
'perPage',
'categoryId',
'search',
'forMainPage',
'featuredProducts',
'mainpageProducts'
)
);
}
$response = $this->productsService->getProductsResponse(
compact(
'page',
'perPage',
'categoryId',
'search',
'forMainPage',
'featuredProducts',
'mainpageProducts'
)
);
return new JsonResponse($response);
}
@@ -246,152 +59,22 @@ class ProductsHandler
$imageFullWidth = 1000;
$imageFullHeight = 1000;
$product = $this->queryBuilder->newQuery()
->select([
'products.product_id' => 'product_id',
'product_description.name' => 'product_name',
'product_description.description' => 'product_description',
'products.price' => 'price',
'products.minimum' => 'minimum',
'products.quantity' => 'quantity',
'products.image' => 'product_image',
'products.tax_class_id' => 'tax_class_id',
'manufacturer.name' => 'product_manufacturer',
])
->from(db_table('product'), 'products')
->join(
db_table('product_description') . ' AS product_description',
function (JoinClause $join) use ($languageId) {
$join->on('products.product_id', '=', 'product_description.product_id')
->where('product_description.language_id', '=', $languageId);
}
)
->leftJoin(
db_table('manufacturer') . ' AS manufacturer',
function (JoinClause $join) use ($languageId) {
$join->on('products.manufacturer_id', '=', 'manufacturer.manufacturer_id');
}
)
->where('products.product_id', '=', $productId)
->limit(1)
->firstOrNull();
if (! $product) {
return new JsonResponse([], Response::HTTP_NOT_FOUND);
try {
$product = $this->productsService->getProduct(
$productId,
$languageId,
$imageWidth,
$imageHeight,
$imageFullWidth,
$imageFullHeight
);
} catch (Exception $exception) {
$this->logger->logException($exception);
throw new RuntimeException('Error get product with id ' . $productId);
}
$productsImages = $this->queryBuilder->newQuery()
->select([
'products_images.product_id' => 'product_id',
'products_images.image' => 'image',
])
->from(db_table('product_image'), 'products_images')
->orderBy('products_images.sort_order', 'ASC')
->where('products_images.product_id', '=', $productId)
->get();
$imagePaths = [];
$imagePaths[] = $product['product_image'];
foreach ($productsImages as $item) {
$imagePaths[] = $item['image'];
}
$images = [];
foreach ($imagePaths as $imagePath) {
[$width, $height] = $this->ocImageTool->getRealSize($imagePath);
$images[] = [
'thumbnailURL' => $this->ocImageTool->resize($imagePath, $imageWidth, $imageHeight, 'placeholder.png'),
'largeURL' => $this->ocImageTool->resize($imagePath, $imageFullWidth, $imageFullHeight, 'placeholder.png'),
'width' => $width,
'height' => $height,
'alt' => $product['product_name'],
];
}
$price = $this->currency->format(
$this->tax->calculate(
$product['price'],
$product['tax_class_id'],
$this->settings->get('oc_config_tax'),
),
$this->settings->get('oc_default_currency'),
);
$data = [
'id' => $product['product_id'],
'name' => $product['product_name'],
'description' => html_entity_decode($product['product_description']),
'manufacturer' => $product['product_manufacturer'],
'price' => $price,
'minimum' => $product['minimum'],
'quantity' => $product['quantity'],
'images' => $images,
'options' => $this->loadProductOptions($product),
'attributes' => $this->loadProductAttributes($product['product_id']),
];
return new JsonResponse([
'data' => $data,
'data' => $product,
]);
}
private function loadProductOptions($product): array
{
$result = [];
$productId = $product['product_id'];
$taxClassId = $product['tax_class_id'];
$options = $this->ocModelCatalogProduct->getProductOptions($productId);
$ocConfigTax = $this->settings->get('oc_config_tax');
$ocDefaultCurrency = $this->settings->get('oc_default_currency');
foreach ($options as $option) {
$product_option_value_data = [];
foreach ($option['product_option_value'] as $option_value) {
if (! $option_value['subtract'] || ($option_value['quantity'] > 0)) {
if ((float) $option_value['price']) {
$priceWithTax = $this->tax->calculate(
$option_value['price'],
$taxClassId,
$ocConfigTax ? 'Р' : false,
);
$price = $this->currency->format($priceWithTax, $ocDefaultCurrency);
} else {
$price = false;
}
$product_option_value_data[] = [
'product_option_value_id' => (int) $option_value['product_option_value_id'],
'option_value_id' => (int) $option_value['option_value_id'],
'name' => $option_value['name'],
'image' => $this->ocImageTool->resize($option_value['image'], 50, 50),
'price' => $price,
'price_prefix' => $option_value['price_prefix'],
'selected' => false,
];
}
}
$result[] = [
'product_option_id' => (int) $option['product_option_id'],
'values' => $product_option_value_data,
'option_id' => (int) $option['option_id'],
'name' => $option['name'],
'type' => $option['type'],
'value' => $option['value'],
'required' => filter_var($option['required'], FILTER_VALIDATE_BOOLEAN),
];
}
return $result;
}
private function loadProductAttributes(int $productId): array
{
$this->oc->load->model('catalog/product');
return $this->oc->model_catalog_product->getProductAttributes($productId);
}
}

View File

@@ -0,0 +1,344 @@
<?php
namespace App\Services;
use App\Adapters\OcModelCatalogProductAdapter;
use App\Decorators\OcRegistryDecorator;
use Cart\Currency;
use Cart\Tax;
use Exception;
use Openguru\OpenCartFramework\Config\Settings;
use Openguru\OpenCartFramework\ImageTool\ImageToolInterface;
use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Support\PaginationHelper;
class ProductsService
{
private Builder $queryBuilder;
private Currency $currency;
private Tax $tax;
private Settings $settings;
private OcModelCatalogProductAdapter $ocModelCatalogProduct;
private ImageToolInterface $ocImageTool;
private OcRegistryDecorator $oc;
public function __construct(
Builder $queryBuilder,
Currency $currency,
Tax $tax,
Settings $settings,
OcModelCatalogProductAdapter $ocModelCatalogProduct,
ImageToolInterface $ocImageTool,
OcRegistryDecorator $registry
) {
$this->queryBuilder = $queryBuilder;
$this->currency = $currency;
$this->tax = $tax;
$this->settings = $settings;
$this->ocModelCatalogProduct = $ocModelCatalogProduct;
$this->ocImageTool = $ocImageTool;
$this->oc = $registry;
}
public function getProductsResponse(array $params): array
{
$page = $params['page'];
$perPage = $params['perPage'];
$categoryId = $params['categoryId'];
$search = $params['search'];
$forMainPage = $params['forMainPage'];
$featuredProducts = $params['featuredProducts'];
$mainpageProducts = $params['mainpageProducts'];
$languageId = 1;
$categoryName = '';
$imageWidth = 300;
$imageHeight = 300;
if ($categoryId) {
$categoryName = $this->queryBuilder->newQuery()
->select(['name'])
->from(db_table('category_description'), 'category')
->where('language_id', '=', $languageId)
->where('category_id', '=', $categoryId)
->value('name');
}
$productsQuery = $this->queryBuilder->newQuery()
->select([
'products.product_id' => 'product_id',
'products.quantity' => 'product_quantity',
'product_description.name' => 'product_name',
'products.price' => 'price',
'products.image' => 'product_image',
'products.tax_class_id' => 'tax_class_id',
])
->from(db_table('product'), 'products')
->join(
db_table('product_description') . ' AS product_description',
function (JoinClause $join) use ($languageId) {
$join->on('products.product_id', '=', 'product_description.product_id')
->where('product_description.language_id', '=', $languageId);
}
)
->when($categoryId !== 0, function (Builder $query) use ($categoryId) {
$query->join(
db_table('product_to_category') . ' AS product_to_category',
function (JoinClause $join) use ($categoryId) {
$join->on('product_to_category.product_id', '=', 'products.product_id')
->where('product_to_category.category_id', '=', $categoryId);
}
);
})
->when(
$forMainPage && $mainpageProducts === 'featured' && $featuredProducts,
function (Builder $query) use ($featuredProducts) {
$query->whereIn('products.product_id', $featuredProducts);
}
)
->when($search, function (Builder $query) use ($search) {
$query->where('product_description.name', 'LIKE', '%' . $search . '%');
});
$total = $productsQuery->count();
$lastPage = PaginationHelper::calculateLastPage($total, $perPage);
$hasMore = $page + 1 <= $lastPage;
$products = $productsQuery
->forPage($page, $perPage)
->orderBy($mainpageProducts === 'latest' ? 'date_modified' : 'viewed', 'DESC')
->get();
$productIds = Arr::pluck($products, 'product_id');
$productsImages = [];
if ($productIds) {
$productsImages = $this->queryBuilder->newQuery()
->select([
'products_images.product_id' => 'product_id',
'products_images.image' => 'image',
])
->from(db_table('product_image'), 'products_images')
->orderBy('products_images.sort_order')
->whereIn('product_id', $productIds)
->get();
}
$productsImagesMap = [];
foreach ($productsImages as $item) {
$productsImagesMap[$item['product_id']][] = [
'url' => $this->ocImageTool->resize($item['image'], $imageWidth, $imageHeight, 'placeholder.png'),
'alt' => 'Product Image',
];
}
return [
'data' => array_map(function ($product) use ($productsImagesMap, $imageWidth, $imageHeight) {
$allImages = [];
$image = $this->ocImageTool->resize(
$product['product_image'],
$imageWidth,
$imageHeight,
'placeholder.png'
);
$allImages[] = [
'url' => $image,
'alt' => $product['product_name'],
];
$price = $this->currency->format(
$this->tax->calculate(
$product['price'],
$product['tax_class_id'],
$this->settings->get('oc_config_tax'),
),
$this->settings->get('oc_default_currency'),
);
if (! empty($productsImagesMap[$product['product_id']])) {
$allImages = array_merge($allImages, $productsImagesMap[$product['product_id']]);
}
return [
'id' => (int) $product['product_id'],
'product_quantity' => (int) $product['product_quantity'],
'name' => $product['product_name'],
'price' => $price,
'images' => $allImages,
];
}, $products),
'meta' => [
'currentCategoryName' => $categoryName,
'hasMore' => $hasMore,
]
];
}
/**
* @throws Exception
*/
public function getProduct(
int $productId,
int $languageId,
int $imageWidth,
int $imageHeight,
int $imageFullWidth,
int $imageFullHeight
): array {
$product = $this->queryBuilder->newQuery()
->select([
'products.product_id' => 'product_id',
'product_description.name' => 'product_name',
'product_description.description' => 'product_description',
'products.price' => 'price',
'products.minimum' => 'minimum',
'products.quantity' => 'quantity',
'products.image' => 'product_image',
'products.tax_class_id' => 'tax_class_id',
'manufacturer.name' => 'product_manufacturer',
])
->from(db_table('product'), 'products')
->join(
db_table('product_description') . ' AS product_description',
function (JoinClause $join) use ($languageId) {
$join->on('products.product_id', '=', 'product_description.product_id')
->where('product_description.language_id', '=', $languageId);
}
)
->leftJoin(
db_table('manufacturer') . ' AS manufacturer',
function (JoinClause $join) {
$join->on('products.manufacturer_id', '=', 'manufacturer.manufacturer_id');
}
)
->where('products.product_id', '=', $productId)
->limit(1)
->firstOrNull();
if (! $product) {
return [];
}
$productsImages = $this->queryBuilder->newQuery()
->select([
'products_images.product_id' => 'product_id',
'products_images.image' => 'image',
])
->from(db_table('product_image'), 'products_images')
->orderBy('products_images.sort_order')
->where('products_images.product_id', '=', $productId)
->get();
$imagePaths = [];
$imagePaths[] = $product['product_image'];
foreach ($productsImages as $item) {
$imagePaths[] = $item['image'];
}
$images = [];
foreach ($imagePaths as $imagePath) {
[$width, $height] = $this->ocImageTool->getRealSize($imagePath);
$images[] = [
'thumbnailURL' => $this->ocImageTool->resize($imagePath, $imageWidth, $imageHeight, 'placeholder.png'),
'largeURL' => $this->ocImageTool->resize(
$imagePath,
$imageFullWidth,
$imageFullHeight,
'placeholder.png'
),
'width' => $width,
'height' => $height,
'alt' => $product['product_name'],
];
}
$price = $this->currency->format(
$this->tax->calculate(
$product['price'],
$product['tax_class_id'],
$this->settings->get('oc_config_tax'),
),
$this->settings->get('oc_default_currency'),
);
return [
'id' => $product['product_id'],
'name' => $product['product_name'],
'description' => html_entity_decode($product['product_description']),
'manufacturer' => $product['product_manufacturer'],
'price' => $price,
'minimum' => $product['minimum'],
'quantity' => $product['quantity'],
'images' => $images,
'options' => $this->loadProductOptions($product),
'attributes' => $this->loadProductAttributes($product['product_id']),
];
}
private function loadProductOptions($product): array
{
$result = [];
$productId = $product['product_id'];
$taxClassId = $product['tax_class_id'];
$options = $this->ocModelCatalogProduct->getProductOptions($productId);
$ocConfigTax = $this->settings->get('oc_config_tax');
$ocDefaultCurrency = $this->settings->get('oc_default_currency');
foreach ($options as $option) {
$product_option_value_data = [];
foreach ($option['product_option_value'] as $option_value) {
if (! $option_value['subtract'] || ($option_value['quantity'] > 0)) {
if ((float) $option_value['price']) {
$priceWithTax = $this->tax->calculate(
$option_value['price'],
$taxClassId,
$ocConfigTax ? 'Р' : false,
);
$price = $this->currency->format($priceWithTax, $ocDefaultCurrency);
} else {
$price = false;
}
$product_option_value_data[] = [
'product_option_value_id' => (int) $option_value['product_option_value_id'],
'option_value_id' => (int) $option_value['option_value_id'],
'name' => $option_value['name'],
'image' => $this->ocImageTool->resize($option_value['image'], 50, 50),
'price' => $price,
'price_prefix' => $option_value['price_prefix'],
'selected' => false,
];
}
}
$result[] = [
'product_option_id' => (int) $option['product_option_id'],
'values' => $product_option_value_data,
'option_id' => (int) $option['option_id'],
'name' => $option['name'],
'type' => $option['type'],
'value' => $option['value'],
'required' => filter_var($option['required'], FILTER_VALIDATE_BOOLEAN),
];
}
return $result;
}
/**
* @throws Exception
*/
private function loadProductAttributes(int $productId): array
{
$this->oc->load->model('catalog/product');
return $this->oc->model_catalog_product->getProductAttributes($productId);
}
}