diff --git a/config/services.yaml b/config/services.yaml index 6f939198..cec5019d 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -244,6 +244,10 @@ services: arguments: $providers: !tagged_iterator 'app.info_provider' + App\Services\InfoProviderSystem\Providers\Element14Provider: + arguments: + $api_key: '%env(PROVIDER_ELEMENT14_KEY)%' + #################################################################################################################### # Symfony overrides #################################################################################################################### diff --git a/src/Services/InfoProviderSystem/Providers/Element14Provider.php b/src/Services/InfoProviderSystem/Providers/Element14Provider.php new file mode 100644 index 00000000..0250d45e --- /dev/null +++ b/src/Services/InfoProviderSystem/Providers/Element14Provider.php @@ -0,0 +1,155 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\InfoProviderSystem\Providers; + +use App\Entity\Parts\ManufacturingStatus; +use App\Form\InfoProviderSystem\ProviderSelectType; +use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class Element14Provider implements InfoProviderInterface +{ + + private const ENDPOINT_URL = 'https://api.element14.com/catalog/products'; + private const FARNELL_STORE_ID = 'de.farnell.com'; + private const API_VERSION_NUMBER = '1.2'; + private const NUMBER_OF_RESULTS = 20; + + public function __construct(private readonly HttpClientInterface $element14Client, private readonly string $api_key) + { + + } + + public function getProviderInfo(): array + { + return [ + 'name' => 'Farnell element14', + 'description' => 'This provider uses the Farnell element14 API to search for parts.', + 'url' => 'https://www.element14.com/', + ]; + } + + public function getProviderKey(): string + { + return 'element14'; + } + + public function isActive(): bool + { + return !empty($this->api_key); + } + + private function queryByTerm(string $term, string $responseGroup = 'large'): array + { + $response = $this->element14Client->request('GET', self::ENDPOINT_URL, [ + 'query' => [ + 'term' => $term, + 'storeInfo.id' => self::FARNELL_STORE_ID, + 'resultsSettings.offset' => 0, + 'resultsSettings.numberOfResults' => self::NUMBER_OF_RESULTS, + 'resultsSettings.responseGroup' => $responseGroup, + 'callInfo.apiKey' => $this->api_key, + 'callInfo.responseDataFormat' => 'json', + 'callInfo.version' => self::API_VERSION_NUMBER, + ], + ]); + + return $response->toArray(); + + } + + private function toImageUrl(?array $image): ?string + { + if ($image === null || count($image) === 0) { + return null; + } + + //See Constructing an Image URL: https://partner.element14.com/docs/Product_Search_API_REST__Description + $locale = 'en_GB'; + if ($image['vrntPath'] === 'nio/') { + $locale = 'en_US'; + } + + return 'https://' . self::FARNELL_STORE_ID . '/productimages/standard/' . $locale . $image['baseName']; + } + + private function displayNameToDescription(string $display_name, string $mpn): string + { + //Try to find the position of the '-' after the MPN + $pos = strpos($display_name, $mpn . ' - '); + if ($pos === false) { + return $display_name; + } + + //Remove the MPN and the '-' from the display name + return substr($display_name, $pos + strlen($mpn) + 3); + } + + private function releaseStatusCodeToManufacturingStatus(?int $releaseStatusCode): ?ManufacturingStatus + { + if ($releaseStatusCode === null) { + return null; + } + + return match ($releaseStatusCode) { + 1 => ManufacturingStatus::ANNOUNCED, + 2,4 => ManufacturingStatus::ACTIVE, + 6 => ManufacturingStatus::EOL, + 7 => ManufacturingStatus::DISCONTINUED, + default => ManufacturingStatus::NOT_SET + }; + } + + public function searchByKeyword(string $keyword): array + { + $response = $this->queryByTerm('any:' . $keyword); + $products = $response['keywordSearchReturn']['products'] ?? []; + + $result = []; + + foreach ($products as $product) { + $result[] = new SearchResultDTO( + provider_key: $this->getProviderKey(), provider_id: $product['sku'], + name: $product['translatedManufacturerPartNumber'], + description: $this->displayNameToDescription($product['displayName'], $product['translatedManufacturerPartNumber']), + manufacturer: $product['vendorName'] ?? $product['brandName'] ?? null, + mpn: $product['translatedManufacturerPartNumber'], + preview_image_url: $this->toImageUrl($product['image'] ?? null), + manufacturing_status: $this->releaseStatusCodeToManufacturingStatus($product['releaseStatusCode'] ?? null), + provider_url: 'https://' . self::FARNELL_STORE_ID . '/' . $product['sku'] + ); + } + + return $result; + } + + public function getCapabilities(): array + { + return [ + ProviderCapabilities::BASIC, + ProviderCapabilities::PICTURE, + ProviderCapabilities::DATASHEET, + ]; + } +} \ No newline at end of file