Added basic reichelt search capabilities

This commit is contained in:
Jan Böhmer 2025-02-19 00:44:49 +01:00
parent f592ab6395
commit 80527e35c3
4 changed files with 180 additions and 70 deletions

View file

@ -54,6 +54,8 @@
"symfony/apache-pack": "^1.0",
"symfony/asset": "6.4.*",
"symfony/console": "6.4.*",
"symfony/css-selector": "6.4.*",
"symfony/dom-crawler": "6.4.*",
"symfony/dotenv": "6.4.*",
"symfony/expression-language": "6.4.*",
"symfony/flex": "^v2.3.1",
@ -104,7 +106,6 @@
"rector/rector": "^2.0.4",
"roave/security-advisories": "dev-latest",
"symfony/browser-kit": "6.4.*",
"symfony/css-selector": "6.4.*",
"symfony/debug-bundle": "6.4.*",
"symfony/maker-bundle": "^1.13",
"symfony/phpunit-bridge": "6.4.*",

136
composer.lock generated
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": "ca8701d95e24bae5d28ccdcfe242e8e4",
"content-hash": "75643d42e05fce4684644d375bff2d0a",
"packages": [
{
"name": "amphp/amp",
@ -8984,6 +8984,73 @@
],
"time": "2025-01-25T08:04:58+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v6.4.18",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "fd07959d3e8992795029bdab3605c2e8e895034e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/fd07959d3e8992795029bdab3605c2e8e895034e",
"reference": "fd07959d3e8992795029bdab3605c2e8e895034e",
"shasum": ""
},
"require": {
"masterminds/html5": "^2.6",
"php": ">=8.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"symfony/css-selector": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\DomCrawler\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dom-crawler/tree/v6.4.18"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-01-09T15:35:00+00:00"
},
{
"name": "symfony/dotenv",
"version": "v6.4.16",
@ -18497,73 +18564,6 @@
],
"time": "2024-09-25T14:18:03+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v6.4.18",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "fd07959d3e8992795029bdab3605c2e8e895034e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/fd07959d3e8992795029bdab3605c2e8e895034e",
"reference": "fd07959d3e8992795029bdab3605c2e8e895034e",
"shasum": ""
},
"require": {
"masterminds/html5": "^2.6",
"php": ">=8.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"symfony/css-selector": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\DomCrawler\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Eases DOM navigation for HTML and XML documents",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dom-crawler/tree/v6.4.18"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-01-09T15:35:00+00:00"
},
{
"name": "symfony/maker-bundle",
"version": "v1.62.1",

View file

@ -76,7 +76,7 @@ class LCSCProvider implements InfoProviderInterface
'Cookie' => new Cookie('currencyCode', $this->currency)
],
'query' => [
'productCode' => $id,
'prductCode' => $id,
],
]);

View file

@ -0,0 +1,109 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\InfoProviderSystem\Providers;
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class ReicheltProvider implements InfoProviderInterface
{
private const SEARCH_ENDPOINT = "https://www.reichelt.com/index.html?ACTION=446&LA=0&nbc=1&q=%s";
public function __construct(private readonly HttpClientInterface $client)
{
}
public function getProviderInfo(): array
{
return [
'name' => 'Reichelt',
'description' => 'TODO',
'url' => 'https://www.reichelt.de/',
'disabled_help' => 'TODO'
];
}
public function getProviderKey(): string
{
return 'reichelt';
}
public function isActive(): bool
{
return true;
}
public function searchByKeyword(string $keyword): array
{
//Lowercase the keyword and urlencode it
$keyword = urlencode($keyword);
$response = $this->client->request('GET', sprintf(self::SEARCH_ENDPOINT, $keyword));
$html = $response->getContent();
//Parse the HTML and return the results
$dom = new Crawler($html);
//Iterate over all div.al_gallery_article elements
$results = [];
$dom->filter('div.al_gallery_article')->each(function (Crawler $element) use (&$results) {
$productID = $element->filter('meta[itemprop="productID"]')->attr('content');
$name = $element->filter('meta[itemprop="name"]')->attr('content');
$sku = $element->filter('meta[itemprop="sku"]')->attr('content');
//Try to extract a picture URL:
$pictureURL = $element->filter("div.al_artlogo img")->attr('src');
$results[] = new SearchResultDTO(
provider_key: $this->getProviderKey(),
provider_id: $productID,
name: $productID,
description: $name,
category: null,
manufacturer: $sku,
preview_image_url: $pictureURL,
provider_url: $element->filter('a.al_artinfo_link')->attr('href')
);
});
return $results;
}
public function getDetails(string $id): PartDetailDTO
{
// TODO: Implement getDetails() method.
}
public function getCapabilities(): array
{
return [
ProviderCapabilities::BASIC,
ProviderCapabilities::PICTURE,
ProviderCapabilities::DATASHEET,
ProviderCapabilities::PRICE,
];
}
}