src/Controller/Content/DownloadController.php line 24

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Content;
  3. use App\Controller\BaseController;
  4. use App\Helpers\Odbc\OdbcProdukte;
  5. use App\Search\EntitySearchService;
  6. use App\Service\IceCatService;
  7. use App\Service\SearchResultsFormatter;
  8. use Doctrine\Persistence\ManagerRegistry;
  9. use Symfony\Component\HttpFoundation\JsonResponse;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\Response;
  12. use Symfony\Component\Routing\Annotation\Route;
  13. /**
  14.  * Controller handling downloads and entity search functionality.
  15.  */
  16. class DownloadController extends BaseController
  17. {
  18.     /**
  19.      * @Route("/download", name="download")
  20.      */
  21.     public function download(): Response
  22.     {
  23.         return $this->baseRender('content/downloads.html.twig');
  24.     }
  25.     /**
  26.      * @Route("/entity-search", name="entity_search")
  27.      */
  28.     public function entitySearch(): Response
  29.     {
  30.         return $this->baseRender('content/entity_search.html.twig');
  31.     }
  32.     /**
  33.      * @Route("/search-entity-fast", name="search_entity_fast")
  34.      *
  35.      * Main search endpoint using the refactored EntitySearchService.
  36.      */
  37.     public function searchEntityFast(
  38.         Request $request,
  39.         EntitySearchService $searchService,
  40.         SearchResultsFormatter $formatter
  41.     ): JsonResponse {
  42.         $search $request->query->get('search''');
  43.         $category $request->query->get('category');
  44.         $manufacturer $request->query->get('manufacturer');
  45.         // Execute search
  46.         $response $searchService->search($search$category$manufacturer);
  47.         $responseArray $response->toArray();
  48.         // Handle device-related scenarios (no HTML formatting needed)
  49.         if ($response->getScenario()->isDeviceRelated()) {
  50.             return new JsonResponse($responseArray);
  51.         }
  52.         // Format results into HTML for other scenarios
  53.         $checkIceCat $request->query->get('check_icecat''false') === 'true';
  54.         $formattedResults $formatter->formatSearchResults($responseArray$checkIceCat);
  55.         return new JsonResponse([
  56.             'html' => $formattedResults['html'],
  57.             'count' => $formattedResults['count'],
  58.             'scenario' => $responseArray['scenario'],
  59.             'metadata' => $responseArray['metadata'],
  60.             'icecat_status' => $formattedResults['icecat_status'] ?? [],
  61.             'results' => $responseArray['results'],
  62.             'alternatives' => $responseArray['alternatives'],
  63.         ]);
  64.     }
  65.     /**
  66.      * @Route("/entity-search/categories", name="entity_search_categories")
  67.      */
  68.     public function getCategories(EntitySearchService $searchService): JsonResponse
  69.     {
  70.         return new JsonResponse($searchService->getCategories());
  71.     }
  72.     /**
  73.      * @Route("/entity-search/manufacturers", name="entity_search_manufacturers")
  74.      */
  75.     public function getManufacturers(EntitySearchService $searchService): JsonResponse
  76.     {
  77.         return new JsonResponse($searchService->getManufacturers());
  78.     }
  79.     /**
  80.      * @Route("/entity-search/supplies", name="entity_search_supplies")
  81.      *
  82.      * Get supplies/components for a device model with optional type filter.
  83.      */
  84.     public function getSuppliesForModel(
  85.         Request $request,
  86.         EntitySearchService $searchService
  87.     ): JsonResponse {
  88.         $modelId $request->query->get('model_id');
  89.         $supplyType $request->query->get('supply_type');
  90.         if (empty($modelId)) {
  91.             return new JsonResponse(['error' => 'model_id is required'], 400);
  92.         }
  93.         $response $searchService->getSuppliesForModel(
  94.             (int)$modelId,
  95.             $supplyType !== null && $supplyType !== '' ? (int)$supplyType null
  96.         );
  97.         if ($response->isError()) {
  98.             return new JsonResponse(['error' => $response->getErrorMessage()], 404);
  99.         }
  100.         $responseArray $response->toArray();
  101.         // Build image URLs for supplies
  102.         $supplies $responseArray['supplies'] ?? [];
  103.         foreach ($supplies as &$supply) {
  104.             $supply['image_url'] = $this->buildSupplyImageUrl($supply);
  105.         }
  106.         return new JsonResponse([
  107.             'model' => $responseArray['device'] ?? null,
  108.             'supply_types' => $responseArray['supply_types'] ?? [],
  109.             'supplies' => $supplies,
  110.             'count' => count($supplies),
  111.             'current_filter' => $supplyType !== null ? (int)$supplyType null,
  112.         ]);
  113.     }
  114.     /**
  115.      * @Route("/opcache-reset-temp", name="opcache_reset_temp")
  116.      */
  117.     public function opcacheReset(): JsonResponse
  118.     {
  119.         if (function_exists('opcache_reset')) {
  120.             opcache_reset();
  121.             return new JsonResponse(['status' => 'OPcache reset successfully']);
  122.         }
  123.         return new JsonResponse(['status' => 'OPcache not available'], 500);
  124.     }
  125.     /**
  126.      * @Route("/product-details", name="product_details")
  127.      *
  128.      * Get detailed product information for modal display (includes IceCat data).
  129.      */
  130.     public function getProductDetails(
  131.         Request $request,
  132.         ManagerRegistry $doctrine,
  133.         IceCatService $iceCatService,
  134.         EntitySearchService $searchService
  135.     ): JsonResponse {
  136.         $articleNr $request->query->get('article_nr''');
  137.         $manufacturer $request->query->get('manufacturer''');
  138.         if (empty($articleNr)) {
  139.             return new JsonResponse(['error' => 'Article number is required'], 400);
  140.         }
  141.         try {
  142.             $productData $this->fetchProductData($doctrine$articleNr$manufacturer);
  143.             if (!$productData) {
  144.                 return new JsonResponse(['error' => 'Product not found'], 404);
  145.             }
  146.             // Add compatible devices
  147.             $this->addCompatibleDevices($productData$articleNr$searchService);
  148.             // Add IceCat data
  149.             $this->addIceCatData($productData$iceCatService$articleNr$manufacturer);
  150.             return new JsonResponse($productData);
  151.         } catch (\Exception $e) {
  152.             error_log('Error fetching product details: ' $e->getMessage());
  153.             return new JsonResponse(['error' => 'Failed to load product details'], 500);
  154.         }
  155.     }
  156.     // =========================================================================
  157.     // Private Helper Methods
  158.     // =========================================================================
  159.     private function buildSupplyImageUrl(array $supply): string
  160.     {
  161.         $imageFile $supply['image_file'] ?? '';
  162.         $manufacturer $supply['manufacturer'] ?? '';
  163.         if (empty($imageFile) || $imageFile === 'nopic.gif') {
  164.             return '/img/nopic.gif';
  165.         }
  166.         return '/image/' strtoupper($manufacturer) . '/' $imageFile;
  167.     }
  168.     private function fetchProductData(
  169.         ManagerRegistry $doctrine,
  170.         string $articleNr,
  171.         string $manufacturer
  172.     ): ?array {
  173.         // Try ODBC first
  174.         try {
  175.             $odbc = new OdbcProdukte();
  176.             $products $odbc->searchByArtnr($articleNr1);
  177.             if (!empty($products)) {
  178.                 $product $products[0];
  179.                 return [
  180.                     'article_nr' => $product->getArtnr(),
  181.                     'manufacturer' => $product->getHersteller(),
  182.                     'description' => $product->getDescription(),
  183.                     'ean' => $product->getEan(),
  184.                     'category' => $product->getArtGr(),
  185.                     'image_file' => $product->getBildDatei(),
  186.                     'price' => $product->getVk(),
  187.                     'availability' => $product->getAvailability(),
  188.                     'delivery' => $product->getDeliveryTime(),
  189.                     'source' => 'odbc',
  190.                     'image_url' => $this->buildProductImageUrl($product->getBildDatei(), $product->getHersteller()),
  191.                 ];
  192.             }
  193.         } catch (\Exception $e) {
  194.             error_log('ODBC not available: ' $e->getMessage());
  195.         }
  196.         // Fallback to MySQL entity table
  197.         $connection $doctrine->getConnection();
  198.         $sql "
  199.             SELECT
  200.                 entity_id,
  201.                 name1 AS article_nr,
  202.                 hersteller AS manufacturer,
  203.                 name2 AS description,
  204.                 ean,
  205.                 artgr AS category,
  206.                 picfile AS image_file,
  207.                 description AS long_description
  208.             FROM entity
  209.             WHERE name1 = :article_nr
  210.         ";
  211.         $params = ['article_nr' => $articleNr];
  212.         if ($manufacturer) {
  213.             $sql .= " AND hersteller = :manufacturer";
  214.             $params['manufacturer'] = $manufacturer;
  215.         }
  216.         $sql .= " LIMIT 1";
  217.         $stmt $connection->prepare($sql);
  218.         $result $stmt->executeQuery($params);
  219.         $row $result->fetchAssociative();
  220.         if ($row) {
  221.             $row['source'] = 'mysql';
  222.             $row['image_url'] = $this->buildProductImageUrl($row['image_file'] ?? ''$row['manufacturer'] ?? '');
  223.             return $row;
  224.         }
  225.         // Fallback to supplies_models
  226.         $sql "
  227.             SELECT
  228.                 sm.model_id,
  229.                 sm.artnr AS article_nr,
  230.                 sb.brand_name AS manufacturer,
  231.                 sm.model_name AS description,
  232.                 sm.bild AS image_file
  233.             FROM supplies_models sm
  234.             LEFT JOIN supplies_brand sb ON sm.brand_id = sb.brand_id
  235.             WHERE sm.artnr = :article_nr
  236.             LIMIT 1
  237.         ";
  238.         $stmt $connection->prepare($sql);
  239.         $result $stmt->executeQuery(['article_nr' => $articleNr]);
  240.         $row $result->fetchAssociative();
  241.         if ($row) {
  242.             $row['source'] = 'supplies_models';
  243.             $row['category'] = 'Gerät/Drucker';
  244.             $row['image_url'] = !empty($row['image_file'])
  245.                 ? '/img/drucker/' $row['image_file']
  246.                 : '/img/nopic.gif';
  247.             return $row;
  248.         }
  249.         return null;
  250.     }
  251.     private function buildProductImageUrl(?string $imageFilestring $manufacturer): string
  252.     {
  253.         if (empty($imageFile) || $imageFile === 'nopic.gif') {
  254.             return '/img/nopic.gif';
  255.         }
  256.         return '/image/' strtolower($manufacturer) . '/' $imageFile;
  257.     }
  258.     private function addCompatibleDevices(
  259.         array &$productData,
  260.         string $articleNr,
  261.         EntitySearchService $searchService
  262.     ): void {
  263.         // Use the supplies repository through the search service
  264.         // For now, we'll use direct query (TODO: expose through service)
  265.         $productData['compatible_with'] = '';
  266.         $productData['compatible_count'] = 0;
  267.     }
  268.     private function addIceCatData(
  269.         array &$productData,
  270.         IceCatService $iceCatService,
  271.         string $articleNr,
  272.         string $manufacturer
  273.     ): void {
  274.         try {
  275.             $ean $productData['ean'] ?? '';
  276.             $productManufacturer $productData['manufacturer'] ?? $manufacturer;
  277.             // Handle HP special case
  278.             if (substr($productManufacturer02) === 'HP') {
  279.                 $productManufacturer 'HP';
  280.             }
  281.             $iceCatResponse $iceCatService->getProductSpecs($ean$articleNr$productManufacturertrue);
  282.             if ($iceCatResponse && $iceCatResponse['success']) {
  283.                 $productData['icecat_available'] = true;
  284.                 $productData['icecat_specs'] = $iceCatResponse['specs'];
  285.                 $productData['icecat_image_url'] = $iceCatResponse['image_url'] ?? null;
  286.                 $productData['icecat_details'] = [
  287.                     'http_status_code' => $iceCatResponse['http_status'],
  288.                     'request_url' => $iceCatResponse['request_url'],
  289.                     'response_time_ms' => $iceCatResponse['response_time_ms'],
  290.                 ];
  291.             } else {
  292.                 $productData['icecat_available'] = false;
  293.                 $productData['icecat_details'] = [
  294.                     'error' => $iceCatResponse['error'] ?? 'Product not found in IceCat',
  295.                 ];
  296.             }
  297.         } catch (\Exception $e) {
  298.             $productData['icecat_available'] = false;
  299.             $productData['icecat_details'] = ['error' => $e->getMessage()];
  300.         }
  301.     }
  302. }