Files
productlinkchecker/controllers/front/product.php
2025-09-26 13:15:18 +03:00

164 lines
7.0 KiB
PHP

<?php
/**
* Product Link Checker Product Data Generate Controller
*
* This controller generates a JSON or CSV feed of all products and their attribute combinations
* with detailed information for external services.
*/
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
class ProductLinkCheckerProductModuleFrontController extends ModuleFrontController
{
/**
* @see FrontController::init()
*/
public function init()
{
parent::init();
// Security check
if (!Tools::getValue('token') || Tools::getValue('token') !== Configuration::get('PLC_SECURITY_TOKEN')) {
$response = new JsonResponse(['error' => 'Not Authorized'], 403);
$response->send();
exit;
}
}
/**
* @see FrontController::initContent()
*/
public function initContent()
{
parent::initContent();
$format = Tools::getValue('format', 'json');
$productsData = [];
$collection = new PrestaShopCollection('Product');
// This temporary array will help flatten attributes for CSV
$attributes_list = [];
foreach ((array)Tools::getValue('plc_id_shop', Shop::getShops(true, null, true)) as $id_shop) {
foreach ((array)Tools::getValue('plc_id_lang', Language::getLanguages(false, false, true)) as $id_lang) {
foreach ($collection as $p) {
$product = new Product((int)$p->id, false, $id_lang, $id_shop);
if (!Validate::isLoadedObject($product)) {
continue;
}
if (Tools::getValue('plc_only_active') && !$product->active) {
continue;
}
// Handle products with attribute combinations
if ($product->hasAttributes()) {
$combinations = $product->getAttributeCombinations($id_lang);
foreach ($combinations as $combination) {
$index = $product->id . '_' . $combination['id_product_attribute'];
if (!isset($productsData[$index])) {
$productsData[$index] = $this->getBaseProductData($product, $id_lang, $id_shop, (int)$combination['id_product_attribute']);
}
// Store attributes for later processing (both JSON and CSV)
$attributes_list[$index][] = [
'group_name' => $combination['group_name'] ?? null,
'attribute_name' => $combination['attribute_name'] ?? null,
];
}
} else { // Handle simple products (without combinations)
$index = $product->id . '_' . 0;
$productsData[$index] = $this->getBaseProductData($product, $id_lang, $id_shop, 0);
}
}
}
}
// Post-process the data based on the requested format
foreach ($productsData as $index => &$data) {
if (isset($attributes_list[$index])) {
if ($format === 'csv') {
// Flatten attributes into a single string for CSV
$flat_attributes = [];
foreach ($attributes_list[$index] as $attr) {
$flat_attributes[] = $attr['group_name'] . ':' . $attr['attribute_name'];
}
$data['attributes'] = implode(' | ', $flat_attributes);
} else {
// Keep the structured array for JSON
$data['attributes'] = $attributes_list[$index];
}
} elseif ($format === 'csv') {
// Ensure the attributes column exists for simple products in CSV
$data['attributes'] = '';
}
}
unset($data);
if ($format === 'csv') {
$this->sendCsvResponse(array_values($productsData), 'products.csv');
} else {
$response = new JsonResponse($productsData);
$response->send();
exit;
}
}
/**
* Helper to get common product data fields.
*/
private function getBaseProductData(Product $product, $id_lang, $id_shop, $id_product_attribute)
{
$combination = new Combination($id_product_attribute);
$data = [
'id_lang' => (int)$id_lang,
'id_shop' => (int)$id_shop,
'id_product' => (int)$product->id,
'id_product_attribute' => $id_product_attribute,
'active' => (bool)$product->active,
'link' => $this->context->link->getProductLink($product, null, null, null, (int)$id_lang, (int)$id_shop, $id_product_attribute, false),
];
// Conditionally add data based on URL flags
Tools::getValue('plc_name') ? $data['name'] = $product->name : null;
Tools::getValue('plc_link_rewrite') ? $data['link_rewrite'] = $product->link_rewrite : null;
Tools::getValue('plc_description') ? $data['description'] = $product->description : null;
Tools::getValue('plc_description_short') ? $data['description_short'] = $product->description_short : null;
Tools::getValue('plc_meta_title') ? $data['meta_title'] = $product->meta_title : null;
Tools::getValue('plc_meta_description') ? $data['meta_description'] = $product->meta_description : null;
// Use combination specific data if it exists, otherwise fallback to product
Tools::getValue('plc_reference') ? $data['reference'] = ($id_product_attribute && !empty($combination->reference)) ? $combination->reference : $product->reference : null;
Tools::getValue('plc_ean13') ? $data['ean13'] = ($id_product_attribute && !empty($combination->ean13)) ? $combination->ean13 : $product->ean13 : null;
Tools::getValue('plc_upc') ? $data['upc'] = ($id_product_attribute && !empty($combination->upc)) ? $combination->upc : $product->upc : null;
Tools::getValue('plc_mpn') ? $data['mpn'] = ($id_product_attribute && !empty($combination->mpn)) ? $combination->mpn : $product->mpn : null;
return $data;
}
/**
* Encodes data as CSV and sends it as a downloadable file.
*/
private function sendCsvResponse(array $data, $filename)
{
if (empty($data)) {
$response = new Response('', 204); // No Content
$response->send();
exit;
}
$csvEncoder = new CsvEncoder();
$csvContent = $csvEncoder->encode($data, 'csv', [
CsvEncoder::DELIMITER_KEY => ';', // Semicolon for better Excel compatibility
]);
$response = new Response($csvContent);
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"');
$response->send();
exit;
}
}