mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-07-27 11:41:36 +00:00
Reworked info provider system to merge all provider metadata into a unified DTO
This commit is contained in:
parent
661cc5a052
commit
071ffe322d
39 changed files with 412 additions and 533 deletions
|
|
@ -73,7 +73,7 @@ class BrowserPluginController extends AbstractController
|
||||||
if (isset($activeProviders[$key])) {
|
if (isset($activeProviders[$key])) {
|
||||||
$urlProviders[] = [
|
$urlProviders[] = [
|
||||||
'id' => $key,
|
'id' => $key,
|
||||||
'label' => $activeProviders[$key]->getProviderInfo()['name'],
|
'label' => $activeProviders[$key]->getProviderInfo()->name,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ class InfoProviderController extends AbstractController
|
||||||
$this->denyAccessUnlessGranted('@info_providers.create_parts');
|
$this->denyAccessUnlessGranted('@info_providers.create_parts');
|
||||||
|
|
||||||
$providerInstance = $this->providerRegistry->getProviderByKey($provider);
|
$providerInstance = $this->providerRegistry->getProviderByKey($provider);
|
||||||
$settingsClass = $providerInstance->getProviderInfo()['settings_class'] ?? throw new \LogicException('Provider ' . $provider . ' does not have a settings class defined');
|
$settingsClass = $providerInstance->getProviderInfo()->settingsClass ?? throw new \LogicException('Provider ' . $provider . ' does not have a settings class defined');
|
||||||
|
|
||||||
//Create a clone of the settings object
|
//Create a clone of the settings object
|
||||||
$settings = $this->settingsManager->createTemporaryCopy($settingsClass);
|
$settings = $this->settingsManager->createTemporaryCopy($settingsClass);
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ class InfoProviderNotActiveException extends \RuntimeException
|
||||||
*/
|
*/
|
||||||
public static function fromProvider(InfoProviderInterface $provider): self
|
public static function fromProvider(InfoProviderInterface $provider): self
|
||||||
{
|
{
|
||||||
return new self($provider->getProviderKey(), $provider->getProviderInfo()['name'] ?? '???');
|
$info = $provider->getProviderInfo();
|
||||||
|
return new self($info->key, $info->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@ class ProviderSelectType extends AbstractType
|
||||||
|
|
||||||
$tmp = [];
|
$tmp = [];
|
||||||
foreach ($providers as $provider) {
|
foreach ($providers as $provider) {
|
||||||
$name = $provider->getProviderInfo()['name'];
|
$info = $provider->getProviderInfo();
|
||||||
$tmp[$name] = $provider->getProviderKey();
|
$tmp[$info->name] = $info->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $tmp;
|
return $tmp;
|
||||||
|
|
@ -77,7 +77,7 @@ class ProviderSelectType extends AbstractType
|
||||||
$resolver->setDefault('choice_label', function (Options $options) {
|
$resolver->setDefault('choice_label', function (Options $options) {
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return ChoiceList::label($this, static fn(?InfoProviderInterface $choice
|
return ChoiceList::label($this, static fn(?InfoProviderInterface $choice
|
||||||
) => new StaticMessage($choice?->getProviderInfo()['name']));
|
) => new StaticMessage($choice?->getProviderInfo()->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return static fn($choice, $key, $value) => new StaticMessage($key);
|
return static fn($choice, $key, $value) => new StaticMessage($key);
|
||||||
|
|
@ -85,7 +85,7 @@ class ProviderSelectType extends AbstractType
|
||||||
$resolver->setDefault('choice_value', function (Options $options) {
|
$resolver->setDefault('choice_value', function (Options $options) {
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return ChoiceList::value($this,
|
return ChoiceList::value($this,
|
||||||
static fn(?InfoProviderInterface $choice) => $choice?->getProviderKey());
|
static fn(?InfoProviderInterface $choice) => $choice?->getProviderInfo()->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ final readonly class CreateFromUrlHelper
|
||||||
|
|
||||||
$provider = $this->providerRegistry->getProviderHandlingDomain($host);
|
$provider = $this->providerRegistry->getProviderHandlingDomain($host);
|
||||||
|
|
||||||
if ($provider !== null && $provider->isActive() && $provider->getProviderKey() !== $callingInfoProvider->getProviderKey()) {
|
if ($provider !== null && $provider->isActive() && $provider->getProviderInfo()->key !== $callingInfoProvider->getProviderInfo()->key) {
|
||||||
try {
|
try {
|
||||||
$id = $provider->getIDFromURL($url);
|
$id = $provider->getIDFromURL($url);
|
||||||
if ($id !== null) {
|
if ($id !== null) {
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ readonly class BulkSearchFieldMappingDTO
|
||||||
//Ensure that providers are provided as keys
|
//Ensure that providers are provided as keys
|
||||||
foreach ($providers as &$provider) {
|
foreach ($providers as &$provider) {
|
||||||
if ($provider instanceof InfoProviderInterface) {
|
if ($provider instanceof InfoProviderInterface) {
|
||||||
$provider = $provider->getProviderKey();
|
$provider = $provider->getProviderInfo()->key;
|
||||||
}
|
}
|
||||||
if (!is_string($provider)) {
|
if (!is_string($provider)) {
|
||||||
throw new \InvalidArgumentException('Providers must be provided as strings or InfoProviderInterface instances');
|
throw new \InvalidArgumentException('Providers must be provided as strings or InfoProviderInterface instances');
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,17 @@ use ApiPlatform\Metadata\GetCollection;
|
||||||
use ApiPlatform\Metadata\McpToolCollection;
|
use ApiPlatform\Metadata\McpToolCollection;
|
||||||
use ApiPlatform\OpenApi\Model\Operation;
|
use ApiPlatform\OpenApi\Model\Operation;
|
||||||
use App\Mcp\DTO\ListInfoProvidersInput;
|
use App\Mcp\DTO\ListInfoProvidersInput;
|
||||||
|
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
||||||
use App\State\Mcp\ListInfoProvidersProcessor;
|
use App\State\Mcp\ListInfoProvidersProcessor;
|
||||||
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This DTO represents an available info provider (a distributor or manufacturer catalog which can be
|
* Immutable, structured description of an info provider, returned by InfoProviderInterface::getProviderInfo()
|
||||||
* searched via search_info_providers / get_info_provider_part_details).
|
* and (via the 'info_provider:read' group) exposed as the REST GET /api/info_providers collection and the
|
||||||
|
* list_info_providers MCP tool.
|
||||||
|
*
|
||||||
|
* disabledHelp, oauthAppName and settingsClass are internal-only (used by the settings UI) and deliberately
|
||||||
|
* not tagged with the 'info_provider:read' group, so they never appear in the API/MCP output.
|
||||||
*/
|
*/
|
||||||
#[ApiResource(
|
#[ApiResource(
|
||||||
uriTemplate: '/info_providers',
|
uriTemplate: '/info_providers',
|
||||||
|
|
@ -44,6 +50,7 @@ use App\State\Mcp\ListInfoProvidersProcessor;
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
paginationEnabled: false,
|
paginationEnabled: false,
|
||||||
|
normalizationContext: ['groups' => ['info_provider:read']],
|
||||||
mcp: [
|
mcp: [
|
||||||
'list_info_providers' => new McpToolCollection(
|
'list_info_providers' => new McpToolCollection(
|
||||||
title: 'List available info providers',
|
title: 'List available info providers',
|
||||||
|
|
@ -52,21 +59,38 @@ use App\State\Mcp\ListInfoProvidersProcessor;
|
||||||
input: ListInfoProvidersInput::class,
|
input: ListInfoProvidersInput::class,
|
||||||
security: 'is_granted("@info_providers.create_parts")',
|
security: 'is_granted("@info_providers.create_parts")',
|
||||||
processor: ListInfoProvidersProcessor::class,
|
processor: ListInfoProvidersProcessor::class,
|
||||||
|
normalizationContext: ['groups' => ['info_provider:read']],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)]
|
)]
|
||||||
readonly class InfoProviderDTO
|
readonly class ProviderInfoDTO
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
/** @var string The unique key of the provider, to be used as provider_key in the other info provider tools */
|
/** @var string A unique key for this provider (e.g. "digikey"), which is saved into the database and used to identify the provider */
|
||||||
|
#[Groups(['info_provider:read'])]
|
||||||
public string $key,
|
public string $key,
|
||||||
/** @var string The (user friendly) name of the provider (e.g. "Digikey") */
|
/** @var string The (user friendly) name of the provider (e.g. "Digikey"), will be translated */
|
||||||
|
#[Groups(['info_provider:read'])]
|
||||||
public string $name,
|
public string $name,
|
||||||
/** @var string|null A short description of the provider */
|
/** @var string|null A short description of the provider (e.g. "Digikey is a ..."), will be translated */
|
||||||
|
#[Groups(['info_provider:read'])]
|
||||||
public ?string $description = null,
|
public ?string $description = null,
|
||||||
/** @var string|null The url of the provider (e.g. "https://www.digikey.com") */
|
/** @var string|null The url of the provider (e.g. "https://www.digikey.com") */
|
||||||
|
#[Groups(['info_provider:read'])]
|
||||||
public ?string $url = null,
|
public ?string $url = null,
|
||||||
/** @var string[] The kinds of data this provider can supply (e.g. "PRICE", "DATASHEET", "PICTURE") */
|
/** @var string|null A help text which is shown when the provider is disabled, explaining how to enable it */
|
||||||
|
public ?string $disabledHelp = null,
|
||||||
|
/** @var string|null The name of the OAuth app which is used for authentication (e.g. "ip_digikey_oauth"). If this is set a connect button will be shown */
|
||||||
|
public ?string $oauthAppName = null,
|
||||||
|
/** @var class-string|null The class name of the settings class which contains the settings for this provider (e.g. "App\Settings\InfoProviderSettings\DigikeySettings"). If this is set a link to the settings will be shown */
|
||||||
|
public ?string $settingsClass = null,
|
||||||
|
/**
|
||||||
|
* A list of capabilities this provider supports (which kind of data it can provide).
|
||||||
|
* Not every part have to contain all of these data, but the provider should be able to provide them in general.
|
||||||
|
* Currently, this list is purely informational and not used in functional checks.
|
||||||
|
* @var ProviderCapabilities[]
|
||||||
|
*/
|
||||||
|
#[Groups(['info_provider:read'])]
|
||||||
public array $capabilities = [],
|
public array $capabilities = [],
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +103,7 @@ final class PartInfoRetriever
|
||||||
//Generate a hash for the options, to ensure that different options result in different cache entries
|
//Generate a hash for the options, to ensure that different options result in different cache entries
|
||||||
$options_hash = hash('xxh3', json_encode($options_without_cache, JSON_THROW_ON_ERROR));
|
$options_hash = hash('xxh3', json_encode($options_without_cache, JSON_THROW_ON_ERROR));
|
||||||
|
|
||||||
$cache_key = "search_{$provider->getProviderKey()}_{$escaped_keyword}_{$options_hash}";
|
$cache_key = "search_{$provider->getProviderInfo()->key}_{$escaped_keyword}_{$options_hash}";
|
||||||
|
|
||||||
//If no_cache is set, bypass the cache and get fresh results from the provider
|
//If no_cache is set, bypass the cache and get fresh results from the provider
|
||||||
if ($no_cache) {
|
if ($no_cache) {
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ final class ProviderRegistry
|
||||||
private function initStructures(): void
|
private function initStructures(): void
|
||||||
{
|
{
|
||||||
foreach ($this->providers as $provider) {
|
foreach ($this->providers as $provider) {
|
||||||
$key = $provider->getProviderKey();
|
$key = $provider->getProviderInfo()->key;
|
||||||
|
|
||||||
if (isset($this->providers_by_name[$key])) {
|
if (isset($this->providers_by_name[$key])) {
|
||||||
throw new \LogicException("Provider with key $key already registered");
|
throw new \LogicException("Provider with key $key already registered");
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ use App\Services\InfoProviderSystem\SubmittedPageStorage;
|
||||||
use App\Services\InfoProviderSystem\CreateFromUrlHelper;
|
use App\Services\InfoProviderSystem\CreateFromUrlHelper;
|
||||||
use App\Services\InfoProviderSystem\DTOJsonSchemaConverter;
|
use App\Services\InfoProviderSystem\DTOJsonSchemaConverter;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Settings\InfoProviderSystem\AIExtractorSettings;
|
use App\Settings\InfoProviderSystem\AIExtractorSettings;
|
||||||
use Jkphl\Micrometa;
|
use Jkphl\Micrometa;
|
||||||
use League\HTMLToMarkdown\HtmlConverter;
|
use League\HTMLToMarkdown\HtmlConverter;
|
||||||
|
|
@ -50,6 +51,8 @@ final class AIWebProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
use FixAndValidateUrlTrait;
|
use FixAndValidateUrlTrait;
|
||||||
|
|
||||||
|
public const PROVIDER_KEY = 'ai_web';
|
||||||
|
|
||||||
private const DISTRIBUTOR_NAME = 'Website';
|
private const DISTRIBUTOR_NAME = 'Website';
|
||||||
|
|
||||||
private readonly HttpClientInterface $httpClient;
|
private readonly HttpClientInterface $httpClient;
|
||||||
|
|
@ -71,20 +74,22 @@ final class AIWebProvider implements InfoProviderInterface
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'AI Web Extractor',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'Extract part info from any URL using LLM',
|
name: 'AI Web Extractor',
|
||||||
//'url' => 'https://openrouter.ai',
|
description: 'Extract part info from any URL using LLM',
|
||||||
'disabled_help' => 'Configure AI settings',
|
disabledHelp: 'Configure AI settings',
|
||||||
'settings_class' => AIExtractorSettings::class,
|
settingsClass: AIExtractorSettings::class,
|
||||||
];
|
capabilities: [
|
||||||
}
|
ProviderCapabilities::BASIC,
|
||||||
|
ProviderCapabilities::PICTURE,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::DATASHEET,
|
||||||
{
|
ProviderCapabilities::PRICE,
|
||||||
return 'ai_web';
|
ProviderCapabilities::PARAMETERS,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -166,7 +171,7 @@ final class AIWebProvider implements InfoProviderInterface
|
||||||
$llmResponse = $this->callLLM($markdown, $url, $structuredData);
|
$llmResponse = $this->callLLM($markdown, $url, $structuredData);
|
||||||
|
|
||||||
// Build and return PartDetailDTO
|
// Build and return PartDetailDTO
|
||||||
$result = $this->jsonSchemaConverter->jsonToDTO($llmResponse, $this->getProviderKey(), $url, $url, self::DISTRIBUTOR_NAME);
|
$result = $this->jsonSchemaConverter->jsonToDTO($llmResponse, self::PROVIDER_KEY, $url, $url, self::DISTRIBUTOR_NAME);
|
||||||
|
|
||||||
// Cache the result for future use, to improve performance and reduce costs.
|
// Cache the result for future use, to improve performance and reduce costs.
|
||||||
$cacheItem->set($result);
|
$cacheItem->set($result);
|
||||||
|
|
@ -256,17 +261,6 @@ final class AIWebProvider implements InfoProviderInterface
|
||||||
return $converter->convert($htmlToConvert);
|
return $converter->convert($htmlToConvert);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
ProviderCapabilities::PARAMETERS,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function callLLM(string $htmlContent, string $url, ?string $structuredData = null): array
|
private function callLLM(string $htmlContent, string $url, ?string $structuredData = null): array
|
||||||
{
|
{
|
||||||
$input = new MessageBag(
|
$input = new MessageBag(
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Settings\InfoProviderSystem\BuerklinSettings;
|
use App\Settings\InfoProviderSystem\BuerklinSettings;
|
||||||
|
|
@ -40,6 +41,7 @@ class BuerklinProvider implements BatchInfoProviderInterface, URLHandlerInfoProv
|
||||||
private const ENDPOINT_URL = 'https://www.buerklin.com/buerklinws/v2/buerklin';
|
private const ENDPOINT_URL = 'https://www.buerklin.com/buerklinws/v2/buerklin';
|
||||||
|
|
||||||
public const DISTRIBUTOR_NAME = 'Buerklin';
|
public const DISTRIBUTOR_NAME = 'Buerklin';
|
||||||
|
public const PROVIDER_KEY = 'buerklin';
|
||||||
|
|
||||||
private const CACHE_TTL = 600;
|
private const CACHE_TTL = 600;
|
||||||
/**
|
/**
|
||||||
|
|
@ -175,20 +177,23 @@ class BuerklinProvider implements BatchInfoProviderInterface, URLHandlerInfoProv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Buerklin',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the Buerklin API to search for parts.',
|
name: 'Buerklin',
|
||||||
'url' => 'https://www.buerklin.com/',
|
description: 'This provider uses the Buerklin API to search for parts.',
|
||||||
'disabled_help' => 'Configure the API Client ID, Secret, Username and Password provided by Buerklin in the provider settings to enable.',
|
url: 'https://www.buerklin.com/',
|
||||||
'settings_class' => BuerklinSettings::class
|
disabledHelp: 'Configure the API Client ID, Secret, Username and Password provided by Buerklin in the provider settings to enable.',
|
||||||
];
|
settingsClass: BuerklinSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
//ProviderCapabilities::DATASHEET, // currently not implemented
|
||||||
return 'buerklin';
|
ProviderCapabilities::PRICE,
|
||||||
|
ProviderCapabilities::FOOTPRINT,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This provider is considered active if settings are present
|
// This provider is considered active if settings are present
|
||||||
|
|
@ -283,7 +288,7 @@ class BuerklinProvider implements BatchInfoProviderInterface, URLHandlerInfoProv
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: (string) ($product['code'] ?? $code),
|
provider_id: (string) ($product['code'] ?? $code),
|
||||||
|
|
||||||
name: (string) ($product['manufacturerProductId'] ?? $code),
|
name: (string) ($product['manufacturerProductId'] ?? $code),
|
||||||
|
|
@ -509,17 +514,6 @@ class BuerklinProvider implements BatchInfoProviderInterface, URLHandlerInfoProv
|
||||||
return $this->getPartDetail($response);
|
return $this->getPartDetail($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
//ProviderCapabilities::DATASHEET, // currently not implemented
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
ProviderCapabilities::FOOTPRINT,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function complianceToParameters(array $product, ?string $group = 'Compliance'): array
|
private function complianceToParameters(array $product, ?string $group = 'Compliance'): array
|
||||||
{
|
{
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ namespace App\Services\InfoProviderSystem\Providers;
|
||||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Settings\InfoProviderSystem\BuerklinSettings;
|
use App\Settings\InfoProviderSystem\BuerklinSettings;
|
||||||
|
|
@ -39,6 +40,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
*/
|
*/
|
||||||
class CanopyProvider implements InfoProviderInterface
|
class CanopyProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'canopy';
|
||||||
|
|
||||||
public const BASE_URL = "https://rest.canopyapi.co/api";
|
public const BASE_URL = "https://rest.canopyapi.co/api";
|
||||||
public const SEARCH_API_URL = self::BASE_URL . "/amazon/search";
|
public const SEARCH_API_URL = self::BASE_URL . "/amazon/search";
|
||||||
|
|
@ -52,20 +54,21 @@ class CanopyProvider implements InfoProviderInterface
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Amazon (Canopy)',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'Retrieves part infos from Amazon using the Canopy API',
|
name: 'Amazon (Canopy)',
|
||||||
'url' => 'https://canopyapi.co',
|
description: 'Retrieves part infos from Amazon using the Canopy API',
|
||||||
'disabled_help' => 'Set Canopy API key in the provider configuration to enable this provider',
|
url: 'https://canopyapi.co',
|
||||||
'settings_class' => CanopySettings::class
|
disabledHelp: 'Set Canopy API key in the provider configuration to enable this provider',
|
||||||
];
|
settingsClass: CanopySettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
ProviderCapabilities::PRICE,
|
||||||
return 'canopy';
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -131,7 +134,7 @@ class CanopyProvider implements InfoProviderInterface
|
||||||
|
|
||||||
|
|
||||||
$dto = new PartDetailDTO(
|
$dto = new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $result['asin'],
|
provider_id: $result['asin'],
|
||||||
name: $result["title"],
|
name: $result["title"],
|
||||||
description: "",
|
description: "",
|
||||||
|
|
@ -209,7 +212,7 @@ class CanopyProvider implements InfoProviderInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $product['asin'],
|
provider_id: $product['asin'],
|
||||||
name: $product['title'],
|
name: $product['title'],
|
||||||
description: '',
|
description: '',
|
||||||
|
|
@ -222,12 +225,4 @@ class CanopyProvider implements InfoProviderInterface
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Settings\InfoProviderSystem\ConradSettings;
|
use App\Settings\InfoProviderSystem\ConradSettings;
|
||||||
|
|
@ -38,6 +39,7 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
|
||||||
|
|
||||||
private const SEARCH_ENDPOINT = '/search/1/v3/facetSearch';
|
private const SEARCH_ENDPOINT = '/search/1/v3/facetSearch';
|
||||||
public const DISTRIBUTOR_NAME = 'Conrad';
|
public const DISTRIBUTOR_NAME = 'Conrad';
|
||||||
|
public const PROVIDER_KEY = 'conrad';
|
||||||
|
|
||||||
private HttpClientInterface $httpClient;
|
private HttpClientInterface $httpClient;
|
||||||
|
|
||||||
|
|
@ -51,20 +53,24 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Conrad',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'Retrieves part information from conrad.de',
|
name: 'Conrad',
|
||||||
'url' => 'https://www.conrad.de/',
|
description: 'Retrieves part information from conrad.de',
|
||||||
'disabled_help' => 'Set API key in settings',
|
url: 'https://www.conrad.de/',
|
||||||
'settings_class' => ConradSettings::class,
|
disabledHelp: 'Set API key in settings',
|
||||||
];
|
settingsClass: ConradSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
ProviderCapabilities::DATASHEET,
|
||||||
return 'conrad';
|
ProviderCapabilities::PRICE,
|
||||||
|
ProviderCapabilities::FOOTPRINT,
|
||||||
|
ProviderCapabilities::GTIN,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -111,7 +117,7 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
|
||||||
foreach($results['hits'] as $result) {
|
foreach($results['hits'] as $result) {
|
||||||
|
|
||||||
$out[] = new SearchResultDTO(
|
$out[] = new SearchResultDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $result['productId'],
|
provider_id: $result['productId'],
|
||||||
name: $result['manufacturerId'] ?? $result['productId'],
|
name: $result['manufacturerId'] ?? $result['productId'],
|
||||||
description: $result['title'] ?? '',
|
description: $result['title'] ?? '',
|
||||||
|
|
@ -293,7 +299,7 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
|
||||||
$data = $response->toArray();
|
$data = $response->toArray();
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $data['shortProductNumber'],
|
provider_id: $data['shortProductNumber'],
|
||||||
name: $data['productFullInformation']['manufacturer']['name'] ?? $data['productFullInformation']['manufacturer']['id'] ?? $data['shortProductNumber'],
|
name: $data['productFullInformation']['manufacturer']['name'] ?? $data['productFullInformation']['manufacturer']['id'] ?? $data['shortProductNumber'],
|
||||||
description: $data['productShortInformation']['title'] ?? '',
|
description: $data['productShortInformation']['title'] ?? '',
|
||||||
|
|
@ -311,18 +317,6 @@ readonly class ConradProvider implements InfoProviderInterface, URLHandlerInfoPr
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
ProviderCapabilities::FOOTPRINT,
|
|
||||||
ProviderCapabilities::GTIN,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHandledDomains(): array
|
public function getHandledDomains(): array
|
||||||
{
|
{
|
||||||
$domains = [];
|
$domains = [];
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Services\OAuth\OAuthTokenManager;
|
use App\Services\OAuth\OAuthTokenManager;
|
||||||
|
|
@ -37,6 +38,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
class DigikeyProvider implements InfoProviderInterface
|
class DigikeyProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'digikey';
|
||||||
|
|
||||||
private const OAUTH_APP_NAME = 'ip_digikey_oauth';
|
private const OAUTH_APP_NAME = 'ip_digikey_oauth';
|
||||||
|
|
||||||
|
|
@ -72,32 +74,24 @@ class DigikeyProvider implements InfoProviderInterface
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'DigiKey',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the DigiKey API to search for parts.',
|
name: 'DigiKey',
|
||||||
'url' => 'https://www.digikey.com/',
|
description: 'This provider uses the DigiKey API to search for parts.',
|
||||||
'oauth_app_name' => self::OAUTH_APP_NAME,
|
url: 'https://www.digikey.com/',
|
||||||
'disabled_help' => 'Set the Client ID and Secret in provider settings and connect OAuth to enable.',
|
disabledHelp: 'Set the Client ID and Secret in provider settings and connect OAuth to enable.',
|
||||||
'settings_class' => DigikeySettings::class,
|
oauthAppName: self::OAUTH_APP_NAME,
|
||||||
];
|
settingsClass: DigikeySettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
ProviderCapabilities::BASIC,
|
||||||
ProviderCapabilities::FOOTPRINT,
|
ProviderCapabilities::FOOTPRINT,
|
||||||
ProviderCapabilities::PICTURE,
|
ProviderCapabilities::PICTURE,
|
||||||
ProviderCapabilities::DATASHEET,
|
ProviderCapabilities::DATASHEET,
|
||||||
ProviderCapabilities::PRICE,
|
ProviderCapabilities::PRICE,
|
||||||
];
|
],
|
||||||
}
|
);
|
||||||
|
|
||||||
public function getProviderKey(): string
|
|
||||||
{
|
|
||||||
return 'digikey';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -128,7 +122,7 @@ class DigikeyProvider implements InfoProviderInterface
|
||||||
} catch (\InvalidArgumentException $exception) {
|
} catch (\InvalidArgumentException $exception) {
|
||||||
//Check if the exception was caused by an invalid or expired token
|
//Check if the exception was caused by an invalid or expired token
|
||||||
if (str_contains($exception->getMessage(), 'access_token')) {
|
if (str_contains($exception->getMessage(), 'access_token')) {
|
||||||
throw OAuthReconnectRequiredException::forProvider($this->getProviderKey());
|
throw OAuthReconnectRequiredException::forProvider(self::PROVIDER_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw $exception;
|
throw $exception;
|
||||||
|
|
@ -141,7 +135,7 @@ class DigikeyProvider implements InfoProviderInterface
|
||||||
foreach ($products as $product) {
|
foreach ($products as $product) {
|
||||||
foreach ($product['ProductVariations'] as $variation) {
|
foreach ($product['ProductVariations'] as $variation) {
|
||||||
$result[] = new SearchResultDTO(
|
$result[] = new SearchResultDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $variation['DigiKeyProductNumber'],
|
provider_id: $variation['DigiKeyProductNumber'],
|
||||||
name: $product['ManufacturerProductNumber'],
|
name: $product['ManufacturerProductNumber'],
|
||||||
description: $product['Description']['DetailedDescription'] ?? $product['Description']['ProductDescription'],
|
description: $product['Description']['DetailedDescription'] ?? $product['Description']['ProductDescription'],
|
||||||
|
|
@ -168,7 +162,7 @@ class DigikeyProvider implements InfoProviderInterface
|
||||||
} catch (\InvalidArgumentException $exception) {
|
} catch (\InvalidArgumentException $exception) {
|
||||||
//Check if the exception was caused by an invalid or expired token
|
//Check if the exception was caused by an invalid or expired token
|
||||||
if (str_contains($exception->getMessage(), 'access_token')) {
|
if (str_contains($exception->getMessage(), 'access_token')) {
|
||||||
throw OAuthReconnectRequiredException::forProvider($this->getProviderKey());
|
throw OAuthReconnectRequiredException::forProvider(self::PROVIDER_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw $exception;
|
throw $exception;
|
||||||
|
|
@ -191,7 +185,7 @@ class DigikeyProvider implements InfoProviderInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $id,
|
provider_id: $id,
|
||||||
name: $product['ManufacturerProductNumber'],
|
name: $product['ManufacturerProductNumber'],
|
||||||
description: $product['Description']['DetailedDescription'] ?? $product['Description']['ProductDescription'],
|
description: $product['Description']['DetailedDescription'] ?? $product['Description']['ProductDescription'],
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Settings\InfoProviderSystem\Element14Settings;
|
use App\Settings\InfoProviderSystem\Element14Settings;
|
||||||
use Composer\CaBundle\CaBundle;
|
use Composer\CaBundle\CaBundle;
|
||||||
|
|
@ -35,6 +36,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
class Element14Provider implements InfoProviderInterface, URLHandlerInfoProviderInterface
|
class Element14Provider implements InfoProviderInterface, URLHandlerInfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'element14';
|
||||||
|
|
||||||
private const ENDPOINT_URL = 'https://api.element14.com/catalog/products';
|
private const ENDPOINT_URL = 'https://api.element14.com/catalog/products';
|
||||||
private const API_VERSION_NUMBER = '1.4';
|
private const API_VERSION_NUMBER = '1.4';
|
||||||
|
|
@ -60,20 +62,21 @@ class Element14Provider implements InfoProviderInterface, URLHandlerInfoProvider
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Farnell element14',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the Farnell element14 API to search for parts.',
|
name: 'Farnell element14',
|
||||||
'url' => 'https://www.element14.com/',
|
description: 'This provider uses the Farnell element14 API to search for parts.',
|
||||||
'disabled_help' => 'Configure the API key in the provider settings to enable.',
|
url: 'https://www.element14.com/',
|
||||||
'settings_class' => Element14Settings::class,
|
disabledHelp: 'Configure the API key in the provider settings to enable.',
|
||||||
];
|
settingsClass: Element14Settings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
ProviderCapabilities::DATASHEET,
|
||||||
return 'element14';
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -113,7 +116,7 @@ class Element14Provider implements InfoProviderInterface, URLHandlerInfoProvider
|
||||||
|
|
||||||
foreach ($products as $product) {
|
foreach ($products as $product) {
|
||||||
$result[] = new PartDetailDTO(
|
$result[] = new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(), provider_id: $product['sku'],
|
provider_key: self::PROVIDER_KEY, provider_id: $product['sku'],
|
||||||
name: $product['translatedManufacturerPartNumber'],
|
name: $product['translatedManufacturerPartNumber'],
|
||||||
description: $this->displayNameToDescription($product['displayName'], $product['translatedManufacturerPartNumber']),
|
description: $this->displayNameToDescription($product['displayName'], $product['translatedManufacturerPartNumber']),
|
||||||
manufacturer: $product['vendorName'] ?? $product['brandName'] ?? null,
|
manufacturer: $product['vendorName'] ?? $product['brandName'] ?? null,
|
||||||
|
|
@ -301,15 +304,6 @@ class Element14Provider implements InfoProviderInterface, URLHandlerInfoProvider
|
||||||
return $tmp[0];
|
return $tmp[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHandledDomains(): array
|
public function getHandledDomains(): array
|
||||||
{
|
{
|
||||||
return ['element14.com', 'farnell.com', 'newark.com'];
|
return ['element14.com', 'farnell.com', 'newark.com'];
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ namespace App\Services\InfoProviderSystem\Providers;
|
||||||
|
|
||||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use Symfony\Component\DependencyInjection\Attribute\When;
|
use Symfony\Component\DependencyInjection\Attribute\When;
|
||||||
|
|
||||||
|
|
@ -34,19 +35,20 @@ use Symfony\Component\DependencyInjection\Attribute\When;
|
||||||
#[When(env: 'test')]
|
#[When(env: 'test')]
|
||||||
class EmptyProvider implements InfoProviderInterface
|
class EmptyProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
public function getProviderInfo(): array
|
public const PROVIDER_KEY = 'empty';
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'Empty Provider',
|
|
||||||
'description' => 'This is a test provider',
|
|
||||||
//'url' => 'https://example.com',
|
|
||||||
'disabled_help' => 'This provider is disabled for testing purposes'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getProviderKey(): string
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return 'empty';
|
return new ProviderInfoDTO(
|
||||||
|
key: self::PROVIDER_KEY,
|
||||||
|
name: 'Empty Provider',
|
||||||
|
description: 'This is a test provider',
|
||||||
|
disabledHelp: 'This provider is disabled for testing purposes',
|
||||||
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
|
ProviderCapabilities::FOOTPRINT,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -61,14 +63,6 @@ class EmptyProvider implements InfoProviderInterface
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::FOOTPRINT,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDetails(string $id, array $options = []): PartDetailDTO
|
public function getDetails(string $id, array $options = []): PartDetailDTO
|
||||||
{
|
{
|
||||||
throw new \RuntimeException('No part details available');
|
throw new \RuntimeException('No part details available');
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ use App\Services\InfoProviderSystem\CreateFromUrlHelper;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
||||||
|
|
@ -53,6 +54,7 @@ class GenericWebProvider implements InfoProviderInterface
|
||||||
use FixAndValidateUrlTrait;
|
use FixAndValidateUrlTrait;
|
||||||
|
|
||||||
public const DISTRIBUTOR_NAME = 'Website';
|
public const DISTRIBUTOR_NAME = 'Website';
|
||||||
|
public const PROVIDER_KEY = 'generic_web';
|
||||||
|
|
||||||
private readonly HttpClientInterface $httpClient;
|
private readonly HttpClientInterface $httpClient;
|
||||||
|
|
||||||
|
|
@ -69,20 +71,21 @@ class GenericWebProvider implements InfoProviderInterface
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Generic Web URL',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'Tries to extract a part from a given product webpage URL using common metadata standards like JSON-LD and OpenGraph.',
|
name: 'Generic Web URL',
|
||||||
//'url' => 'https://example.com',
|
description: 'Tries to extract a part from a given product webpage URL using common metadata standards like JSON-LD and OpenGraph.',
|
||||||
'disabled_help' => 'Enable in settings to use this provider',
|
disabledHelp: 'Enable in settings to use this provider',
|
||||||
'settings_class' => GenericWebProviderSettings::class,
|
settingsClass: GenericWebProviderSettings::class,
|
||||||
];
|
capabilities: [
|
||||||
}
|
ProviderCapabilities::BASIC,
|
||||||
|
ProviderCapabilities::PICTURE,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PRICE,
|
||||||
{
|
ProviderCapabilities::GTIN,
|
||||||
return 'generic_web';
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -227,7 +230,7 @@ class GenericWebProvider implements InfoProviderInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $url,
|
provider_id: $url,
|
||||||
name: $product->name?->toString() ?? $product->alternateName?->toString() ?? $product->mpn?->toString() ?? 'Unknown Name',
|
name: $product->name?->toString() ?? $product->alternateName?->toString() ?? $product->mpn?->toString() ?? 'Unknown Name',
|
||||||
description: $this->getMetaContent($dom, 'og:description') ?? $this->getMetaContent($dom, 'description') ?? '',
|
description: $this->getMetaContent($dom, 'og:description') ?? $this->getMetaContent($dom, 'description') ?? '',
|
||||||
|
|
@ -376,7 +379,7 @@ class GenericWebProvider implements InfoProviderInterface
|
||||||
)];
|
)];
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $canonicalURL,
|
provider_id: $canonicalURL,
|
||||||
name: $this->getMetaContent($dom, 'og:title') ?? $pageTitle,
|
name: $this->getMetaContent($dom, 'og:title') ?? $pageTitle,
|
||||||
description: $this->getMetaContent($dom, 'og:description') ?? $this->getMetaContent($dom, 'description') ?? '',
|
description: $this->getMetaContent($dom, 'og:description') ?? $this->getMetaContent($dom, 'description') ?? '',
|
||||||
|
|
@ -387,13 +390,4 @@ class GenericWebProvider implements InfoProviderInterface
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
ProviderCapabilities::GTIN,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||||
namespace App\Services\InfoProviderSystem\Providers;
|
namespace App\Services\InfoProviderSystem\Providers;
|
||||||
|
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
|
|
||||||
interface InfoProviderInterface
|
interface InfoProviderInterface
|
||||||
|
|
@ -34,26 +35,8 @@ interface InfoProviderInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get information about this provider
|
* Get information about this provider
|
||||||
*
|
|
||||||
* @return array An associative array with the following keys (? means optional):
|
|
||||||
* - name: The (user friendly) name of the provider (e.g. "Digikey"), will be translated
|
|
||||||
* - description?: A short description of the provider (e.g. "Digikey is a ..."), will be translated
|
|
||||||
* - logo?: The logo of the provider (e.g. "digikey.png")
|
|
||||||
* - url?: The url of the provider (e.g. "https://www.digikey.com")
|
|
||||||
* - disabled_help?: A help text which is shown when the provider is disabled, explaining how to enable it
|
|
||||||
* - oauth_app_name?: The name of the OAuth app which is used for authentication (e.g. "ip_digikey_oauth"). If this is set a connect button will be shown
|
|
||||||
* - settings_class?: The class name of the settings class which contains the settings for this provider (e.g. "App\Settings\InfoProviderSettings\DigikeySettings"). If this is set a link to the settings will be shown
|
|
||||||
*
|
|
||||||
* @phpstan-return array{ name: string, description?: string, logo?: string, url?: string, disabled_help?: string, oauth_app_name?: string, settings_class?: class-string }
|
|
||||||
*/
|
*/
|
||||||
public function getProviderInfo(): array;
|
public function getProviderInfo(): ProviderInfoDTO;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a unique key for this provider, which will be saved into the database
|
|
||||||
* and used to identify the provider
|
|
||||||
* @return string A unique key for this provider (e.g. "digikey")
|
|
||||||
*/
|
|
||||||
public function getProviderKey(): string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this provider is enabled or not (meaning that it can be used for searching)
|
* Checks if this provider is enabled or not (meaning that it can be used for searching)
|
||||||
|
|
@ -76,12 +59,4 @@ interface InfoProviderInterface
|
||||||
* @return PartDetailDTO
|
* @return PartDetailDTO
|
||||||
*/
|
*/
|
||||||
public function getDetails(string $id, array $options = []): PartDetailDTO;
|
public function getDetails(string $id, array $options = []): PartDetailDTO;
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of capabilities this provider supports (which kind of data it can provide).
|
|
||||||
* Not every part have to contain all of these data, but the provider should be able to provide them in general.
|
|
||||||
* Currently, this list is purely informational and not used in functional checks.
|
|
||||||
* @return ProviderCapabilities[]
|
|
||||||
*/
|
|
||||||
public function getCapabilities(): array;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Settings\InfoProviderSystem\LCSCSettings;
|
use App\Settings\InfoProviderSystem\LCSCSettings;
|
||||||
use Symfony\Component\HttpFoundation\Cookie;
|
use Symfony\Component\HttpFoundation\Cookie;
|
||||||
|
|
@ -39,26 +40,30 @@ class LCSCProvider implements BatchInfoProviderInterface, URLHandlerInfoProvider
|
||||||
private const ENDPOINT_URL = 'https://wmsc.lcsc.com/ftps/wm';
|
private const ENDPOINT_URL = 'https://wmsc.lcsc.com/ftps/wm';
|
||||||
|
|
||||||
public const DISTRIBUTOR_NAME = 'LCSC';
|
public const DISTRIBUTOR_NAME = 'LCSC';
|
||||||
|
public const PROVIDER_KEY = 'lcsc';
|
||||||
|
|
||||||
public function __construct(private readonly HttpClientInterface $lcscClient, private readonly LCSCSettings $settings)
|
public function __construct(private readonly HttpClientInterface $lcscClient, private readonly LCSCSettings $settings)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'LCSC',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the (unofficial) LCSC API to search for parts.',
|
name: 'LCSC',
|
||||||
'url' => 'https://www.lcsc.com/',
|
description: 'This provider uses the (unofficial) LCSC API to search for parts.',
|
||||||
'disabled_help' => 'Enable this provider in the provider settings.',
|
url: 'https://www.lcsc.com/',
|
||||||
'settings_class' => LCSCSettings::class,
|
disabledHelp: 'Enable this provider in the provider settings.',
|
||||||
];
|
settingsClass: LCSCSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
ProviderCapabilities::DATASHEET,
|
||||||
return 'lcsc';
|
ProviderCapabilities::PRICE,
|
||||||
|
ProviderCapabilities::FOOTPRINT,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This provider is always active
|
// This provider is always active
|
||||||
|
|
@ -227,7 +232,7 @@ class LCSCProvider implements BatchInfoProviderInterface, URLHandlerInfoProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $product['productCode'],
|
provider_id: $product['productCode'],
|
||||||
name: $product['productModel'],
|
name: $product['productModel'],
|
||||||
description: $this->sanitizeField($product['productIntroEn']) ?? '',
|
description: $this->sanitizeField($product['productIntroEn']) ?? '',
|
||||||
|
|
@ -455,17 +460,6 @@ class LCSCProvider implements BatchInfoProviderInterface, URLHandlerInfoProvider
|
||||||
return $tmp[0];
|
return $tmp[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
ProviderCapabilities::FOOTPRINT,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHandledDomains(): array
|
public function getHandledDomains(): array
|
||||||
{
|
{
|
||||||
return ['lcsc.com'];
|
return ['lcsc.com'];
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ use App\Entity\Parts\ManufacturingStatus;
|
||||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Settings\InfoProviderSystem\MouserSettings;
|
use App\Settings\InfoProviderSystem\MouserSettings;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
@ -48,6 +49,7 @@ class MouserProvider implements InfoProviderInterface
|
||||||
private const ENDPOINT_URL = 'https://api.mouser.com/api/v2/search';
|
private const ENDPOINT_URL = 'https://api.mouser.com/api/v2/search';
|
||||||
|
|
||||||
public const DISTRIBUTOR_NAME = 'Mouser';
|
public const DISTRIBUTOR_NAME = 'Mouser';
|
||||||
|
public const PROVIDER_KEY = 'mouser';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly HttpClientInterface $mouserClient,
|
private readonly HttpClientInterface $mouserClient,
|
||||||
|
|
@ -55,20 +57,22 @@ class MouserProvider implements InfoProviderInterface
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Mouser',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the Mouser API to search for parts.',
|
name: 'Mouser',
|
||||||
'url' => 'https://www.mouser.com/',
|
description: 'This provider uses the Mouser API to search for parts.',
|
||||||
'disabled_help' => 'Configure the API key in the provider settings to enable.',
|
url: 'https://www.mouser.com/',
|
||||||
'settings_class' => MouserSettings::class
|
disabledHelp: 'Configure the API key in the provider settings to enable.',
|
||||||
];
|
settingsClass: MouserSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
ProviderCapabilities::DATASHEET,
|
||||||
return 'mouser';
|
ProviderCapabilities::PRICE,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -207,17 +211,6 @@ class MouserProvider implements InfoProviderInterface
|
||||||
return reset($tmp);
|
return reset($tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ResponseInterface $response
|
* @param ResponseInterface $response
|
||||||
* @return PartDetailDTO[]
|
* @return PartDetailDTO[]
|
||||||
|
|
@ -251,7 +244,7 @@ class MouserProvider implements InfoProviderInterface
|
||||||
|
|
||||||
|
|
||||||
$result[] = new PartDetailDTO(
|
$result[] = new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $product['MouserPartNumber'],
|
provider_id: $product['MouserPartNumber'],
|
||||||
name: $product['ManufacturerPartNumber'],
|
name: $product['ManufacturerPartNumber'],
|
||||||
description: $product['Description'],
|
description: $product['Description'],
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Settings\InfoProviderSystem\OEMSecretsSettings;
|
use App\Settings\InfoProviderSystem\OEMSecretsSettings;
|
||||||
use App\Settings\InfoProviderSystem\OEMSecretsSortMode;
|
use App\Settings\InfoProviderSystem\OEMSecretsSortMode;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
@ -96,6 +97,7 @@ use Psr\Cache\CacheItemPoolInterface;
|
||||||
|
|
||||||
class OEMSecretsProvider implements InfoProviderInterface
|
class OEMSecretsProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'oemsecrets';
|
||||||
|
|
||||||
private const ENDPOINT_URL = 'https://oemsecretsapi.com/partsearch';
|
private const ENDPOINT_URL = 'https://oemsecretsapi.com/partsearch';
|
||||||
|
|
||||||
|
|
@ -227,37 +229,22 @@ class OEMSecretsProvider implements InfoProviderInterface
|
||||||
private array $distributorCountryCodes = [];
|
private array $distributorCountryCodes = [];
|
||||||
private array $countryCodeToRegionMap = [];
|
private array $countryCodeToRegionMap = [];
|
||||||
|
|
||||||
/**
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
* Get information about this provider
|
|
||||||
*
|
|
||||||
* @return array An associative array with the following keys (? means optional):
|
|
||||||
* - name: The (user friendly) name of the provider (e.g. "Digikey"), will be translated
|
|
||||||
* - description?: A short description of the provider (e.g. "Digikey is a ..."), will be translated
|
|
||||||
* - logo?: The logo of the provider (e.g. "digikey.png")
|
|
||||||
* - url?: The url of the provider (e.g. "https://www.digikey.com")
|
|
||||||
* - disabled_help?: A help text which is shown when the provider is disabled, explaining how to enable it
|
|
||||||
* - oauth_app_name?: The name of the OAuth app which is used for authentication (e.g. "ip_digikey_oauth"). If this is set a connect button will be shown
|
|
||||||
*
|
|
||||||
* @phpstan-return array{ name: string, description?: string, logo?: string, url?: string, disabled_help?: string, oauth_app_name?: string }
|
|
||||||
*/
|
|
||||||
public function getProviderInfo(): array
|
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'OEMSecrets',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the OEMSecrets API to search for parts.',
|
name: 'OEMSecrets',
|
||||||
'url' => 'https://www.oemsecrets.com/',
|
description: 'This provider uses the OEMSecrets API to search for parts.',
|
||||||
'disabled_help' => 'Configure the API key in the provider settings to enable.',
|
url: 'https://www.oemsecrets.com/',
|
||||||
'settings_class' => OEMSecretsSettings::class
|
disabledHelp: 'Configure the API key in the provider settings to enable.',
|
||||||
];
|
settingsClass: OEMSecretsSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
/**
|
ProviderCapabilities::BASIC,
|
||||||
* Returns a unique key for this provider, which will be saved into the database
|
ProviderCapabilities::PICTURE,
|
||||||
* and used to identify the provider
|
ProviderCapabilities::DATASHEET,
|
||||||
* @return string A unique key for this provider (e.g. "digikey")
|
ProviderCapabilities::PRICE,
|
||||||
*/
|
],
|
||||||
public function getProviderKey(): string
|
);
|
||||||
{
|
|
||||||
return 'oemsecrets';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -456,17 +443,6 @@ class OEMSecretsProvider implements InfoProviderInterface
|
||||||
* Currently, this list is purely informational and not used in functional checks.
|
* Currently, this list is purely informational and not used in functional checks.
|
||||||
* @return ProviderCapabilities[]
|
* @return ProviderCapabilities[]
|
||||||
*/
|
*/
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a single product and updates arrays for basic information, datasheets, images, parameters,
|
* Processes a single product and updates arrays for basic information, datasheets, images, parameters,
|
||||||
* and purchase information. Aggregates and organizes data received for a specific `part_number` and `manufacturer_id`.
|
* and purchase information. Aggregates and organizes data received for a specific `part_number` and `manufacturer_id`.
|
||||||
|
|
@ -896,7 +872,7 @@ class OEMSecretsProvider implements InfoProviderInterface
|
||||||
// If there is no existing basic info array, we create a new one
|
// If there is no existing basic info array, we create a new one
|
||||||
if (is_null($existingBasicInfo)) {
|
if (is_null($existingBasicInfo)) {
|
||||||
return [
|
return [
|
||||||
'provider_key' => $this->getProviderKey(),
|
'provider_key' => self::PROVIDER_KEY,
|
||||||
'provider_id' => $provider_id,
|
'provider_id' => $provider_id,
|
||||||
'name' => $product['part_number'],
|
'name' => $product['part_number'],
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
|
|
@ -916,7 +892,7 @@ class OEMSecretsProvider implements InfoProviderInterface
|
||||||
|
|
||||||
// Update fields only if empty or undefined, with additional check for preview_image_url
|
// Update fields only if empty or undefined, with additional check for preview_image_url
|
||||||
return [
|
return [
|
||||||
'provider_key' => $existingBasicInfo['provider_key'] ?? $this->getProviderKey(),
|
'provider_key' => $existingBasicInfo['provider_key'] ?? self::PROVIDER_KEY,
|
||||||
'provider_id' => $existingBasicInfo['provider_id'] ?? $provider_id,
|
'provider_id' => $existingBasicInfo['provider_id'] ?? $provider_id,
|
||||||
'name' => $existingBasicInfo['name'] ?? $product['part_number'],
|
'name' => $existingBasicInfo['name'] ?? $product['part_number'],
|
||||||
// Update description if it's null/empty
|
// Update description if it's null/empty
|
||||||
|
|
@ -1270,7 +1246,7 @@ class OEMSecretsProvider implements InfoProviderInterface
|
||||||
*/
|
*/
|
||||||
private function generateInquiryUrl(string $partNumber, string $oemInquiry = 'compare/'): string
|
private function generateInquiryUrl(string $partNumber, string $oemInquiry = 'compare/'): string
|
||||||
{
|
{
|
||||||
$baseUrl = rtrim($this->getProviderInfo()['url'], '/') . '/';
|
$baseUrl = rtrim($this->getProviderInfo()->url, '/') . '/';
|
||||||
$inquiryPath = trim($oemInquiry, '/') . '/';
|
$inquiryPath = trim($oemInquiry, '/') . '/';
|
||||||
$encodedPartNumber = urlencode(trim($partNumber));
|
$encodedPartNumber = urlencode(trim($partNumber));
|
||||||
return $baseUrl . $inquiryPath . $encodedPartNumber;
|
return $baseUrl . $inquiryPath . $encodedPartNumber;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\OAuth\OAuthTokenManager;
|
use App\Services\OAuth\OAuthTokenManager;
|
||||||
use App\Settings\InfoProviderSystem\OctopartSettings;
|
use App\Settings\InfoProviderSystem\OctopartSettings;
|
||||||
|
|
@ -43,6 +44,8 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
*/
|
*/
|
||||||
class OctopartProvider implements InfoProviderInterface
|
class OctopartProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'octopart';
|
||||||
|
|
||||||
private const OAUTH_APP_NAME = 'ip_octopart_oauth';
|
private const OAUTH_APP_NAME = 'ip_octopart_oauth';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -164,20 +167,23 @@ class OctopartProvider implements InfoProviderInterface
|
||||||
return $response->toArray(true);
|
return $response->toArray(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Octopart',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the Nexar/Octopart API to search for parts on Octopart.',
|
name: 'Octopart',
|
||||||
'url' => 'https://www.octopart.com/',
|
description: 'This provider uses the Nexar/Octopart API to search for parts on Octopart.',
|
||||||
'disabled_help' => 'Set the Client ID and Secret in provider settings.',
|
url: 'https://www.octopart.com/',
|
||||||
'settings_class' => OctopartSettings::class
|
disabledHelp: 'Set the Client ID and Secret in provider settings.',
|
||||||
];
|
settingsClass: OctopartSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::FOOTPRINT,
|
||||||
{
|
ProviderCapabilities::PICTURE,
|
||||||
return 'octopart';
|
ProviderCapabilities::DATASHEET,
|
||||||
|
ProviderCapabilities::PRICE,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -307,7 +313,7 @@ class OctopartProvider implements InfoProviderInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $part['id'],
|
provider_id: $part['id'],
|
||||||
name: $part['mpn'],
|
name: $part['mpn'],
|
||||||
description: $part['shortDescription'] ?? null,
|
description: $part['shortDescription'] ?? null,
|
||||||
|
|
@ -397,14 +403,4 @@ class OctopartProvider implements InfoProviderInterface
|
||||||
return $tmp;
|
return $tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::FOOTPRINT,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Settings\InfoProviderSystem\PollinSettings;
|
use App\Settings\InfoProviderSystem\PollinSettings;
|
||||||
|
|
@ -38,6 +39,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
class PollinProvider implements InfoProviderInterface, URLHandlerInfoProviderInterface
|
class PollinProvider implements InfoProviderInterface, URLHandlerInfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'pollin';
|
||||||
|
|
||||||
public function __construct(private readonly HttpClientInterface $client,
|
public function __construct(private readonly HttpClientInterface $client,
|
||||||
private readonly PollinSettings $settings,
|
private readonly PollinSettings $settings,
|
||||||
|
|
@ -45,20 +47,22 @@ class PollinProvider implements InfoProviderInterface, URLHandlerInfoProviderInt
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Pollin',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'Webscraping from pollin.de to get part information',
|
name: 'Pollin',
|
||||||
'url' => 'https://www.pollin.de/',
|
description: 'Webscraping from pollin.de to get part information',
|
||||||
'disabled_help' => 'Enable the provider in provider settings',
|
url: 'https://www.pollin.de/',
|
||||||
'settings_class' => PollinSettings::class,
|
disabledHelp: 'Enable the provider in provider settings',
|
||||||
];
|
settingsClass: PollinSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
ProviderCapabilities::PRICE,
|
||||||
return 'pollin';
|
ProviderCapabilities::DATASHEET,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -88,7 +92,7 @@ class PollinProvider implements InfoProviderInterface, URLHandlerInfoProviderInt
|
||||||
//Iterate over each div.product-box
|
//Iterate over each div.product-box
|
||||||
$dom->filter('div.product-box')->each(function (Crawler $node) use (&$results) {
|
$dom->filter('div.product-box')->each(function (Crawler $node) use (&$results) {
|
||||||
$results[] = new SearchResultDTO(
|
$results[] = new SearchResultDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $node->filter('meta[itemprop="productID"]')->attr('content'),
|
provider_id: $node->filter('meta[itemprop="productID"]')->attr('content'),
|
||||||
name: $node->filter('a.product-name')->text(),
|
name: $node->filter('a.product-name')->text(),
|
||||||
description: '',
|
description: '',
|
||||||
|
|
@ -156,7 +160,7 @@ class PollinProvider implements InfoProviderInterface, URLHandlerInfoProviderInt
|
||||||
$purchaseInfo = new PurchaseInfoDTO('Pollin', $orderId, $this->parsePrices($dom), $productPageUrl);
|
$purchaseInfo = new PurchaseInfoDTO('Pollin', $orderId, $this->parsePrices($dom), $productPageUrl);
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $orderId,
|
provider_id: $orderId,
|
||||||
name: trim($dom->filter('meta[property="og:title"]')->attr('content')),
|
name: trim($dom->filter('meta[property="og:title"]')->attr('content')),
|
||||||
description: $dom->filter('meta[property="og:description"]')->attr('content'),
|
description: $dom->filter('meta[property="og:description"]')->attr('content'),
|
||||||
|
|
@ -244,16 +248,6 @@ class PollinProvider implements InfoProviderInterface, URLHandlerInfoProviderInt
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
ProviderCapabilities::DATASHEET
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHandledDomains(): array
|
public function getHandledDomains(): array
|
||||||
{
|
{
|
||||||
return ['pollin.de'];
|
return ['pollin.de'];
|
||||||
|
|
|
||||||
|
|
@ -26,28 +26,28 @@ namespace App\Services\InfoProviderSystem\Providers;
|
||||||
/**
|
/**
|
||||||
* This enum contains all capabilities (which data it can provide) a provider can have.
|
* This enum contains all capabilities (which data it can provide) a provider can have.
|
||||||
*/
|
*/
|
||||||
enum ProviderCapabilities
|
enum ProviderCapabilities: string
|
||||||
{
|
{
|
||||||
/** Basic information about a part, like the name, description, part number, manufacturer etc */
|
/** Basic information about a part, like the name, description, part number, manufacturer etc */
|
||||||
case BASIC;
|
case BASIC = 'BASIC';
|
||||||
|
|
||||||
/** Provider can provide a picture for a part */
|
/** Provider can provide a picture for a part */
|
||||||
case PICTURE;
|
case PICTURE = 'PICTURE';
|
||||||
|
|
||||||
/** Provider can provide datasheets for a part */
|
/** Provider can provide datasheets for a part */
|
||||||
case DATASHEET;
|
case DATASHEET = 'DATASHEET';
|
||||||
|
|
||||||
/** Provider can provide prices for a part */
|
/** Provider can provide prices for a part */
|
||||||
case PRICE;
|
case PRICE = 'PRICE';
|
||||||
|
|
||||||
/** Information about the footprint of a part */
|
/** Information about the footprint of a part */
|
||||||
case FOOTPRINT;
|
case FOOTPRINT = 'FOOTPRINT';
|
||||||
|
|
||||||
/** Provider can provide GTIN for a part */
|
/** Provider can provide GTIN for a part */
|
||||||
case GTIN;
|
case GTIN = 'GTIN';
|
||||||
|
|
||||||
/** Provider can provide parameters/specifications for a part */
|
/** Provider can provide parameters/specifications for a part */
|
||||||
case PARAMETERS;
|
case PARAMETERS = 'PARAMETERS';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the order index for displaying capabilities in a stable order.
|
* Get the order index for displaying capabilities in a stable order.
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Settings\InfoProviderSystem\ReicheltSettings;
|
use App\Settings\InfoProviderSystem\ReicheltSettings;
|
||||||
|
|
@ -38,6 +39,7 @@ class ReicheltProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
public const DISTRIBUTOR_NAME = "Reichelt";
|
public const DISTRIBUTOR_NAME = "Reichelt";
|
||||||
|
public const PROVIDER_KEY = 'reichelt';
|
||||||
|
|
||||||
private readonly HttpClientInterface $client;
|
private readonly HttpClientInterface $client;
|
||||||
|
|
||||||
|
|
@ -48,20 +50,23 @@ class ReicheltProvider implements InfoProviderInterface
|
||||||
$this->client = new RandomizeUseragentHttpClient($client);
|
$this->client = new RandomizeUseragentHttpClient($client);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Reichelt',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'Webscraping from reichelt.com to get part information',
|
name: 'Reichelt',
|
||||||
'url' => 'https://www.reichelt.com/',
|
description: 'Webscraping from reichelt.com to get part information',
|
||||||
'disabled_help' => 'Enable provider in provider settings.',
|
url: 'https://www.reichelt.com/',
|
||||||
'settings_class' => ReicheltSettings::class,
|
disabledHelp: 'Enable provider in provider settings.',
|
||||||
];
|
settingsClass: ReicheltSettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::PICTURE,
|
||||||
{
|
ProviderCapabilities::DATASHEET,
|
||||||
return 'reichelt';
|
ProviderCapabilities::PRICE,
|
||||||
|
ProviderCapabilities::GTIN,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -93,7 +98,7 @@ class ReicheltProvider implements InfoProviderInterface
|
||||||
$pictureURL = $element->filter("div.al_artlogo img")->attr('src');
|
$pictureURL = $element->filter("div.al_artlogo img")->attr('src');
|
||||||
|
|
||||||
$results[] = new SearchResultDTO(
|
$results[] = new SearchResultDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $artId,
|
provider_id: $artId,
|
||||||
name: $productID,
|
name: $productID,
|
||||||
description: $name,
|
description: $name,
|
||||||
|
|
@ -173,7 +178,7 @@ class ReicheltProvider implements InfoProviderInterface
|
||||||
|
|
||||||
//Create part object
|
//Create part object
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $id,
|
provider_id: $id,
|
||||||
name: $json[0]['article_artnr'],
|
name: $json[0]['article_artnr'],
|
||||||
description: $json[0]['article_besch'],
|
description: $json[0]['article_besch'],
|
||||||
|
|
@ -282,14 +287,4 @@ class ReicheltProvider implements InfoProviderInterface
|
||||||
return 'https://www.reichelt.com/' . strtolower($this->settings->country) . '/' . strtolower($this->settings->language);
|
return 'https://www.reichelt.com/' . strtolower($this->settings->country) . '/' . strtolower($this->settings->language);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
ProviderCapabilities::GTIN,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,14 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Settings\InfoProviderSystem\TMESettings;
|
use App\Settings\InfoProviderSystem\TMESettings;
|
||||||
|
|
||||||
class TMEProvider implements InfoProviderInterface, URLHandlerInfoProviderInterface
|
class TMEProvider implements InfoProviderInterface, URLHandlerInfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'tme';
|
||||||
|
|
||||||
private const VENDOR_NAME = 'TME';
|
private const VENDOR_NAME = 'TME';
|
||||||
|
|
||||||
|
|
@ -48,20 +50,23 @@ class TMEProvider implements InfoProviderInterface, URLHandlerInfoProviderInterf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'TME',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This provider uses the API of TME (Transfer Multipart).',
|
name: 'TME',
|
||||||
'url' => 'https://tme.eu/',
|
description: 'This provider uses the API of TME (Transfer Multipart).',
|
||||||
'disabled_help' => 'Configure the API Token and secret in provider settings to use this provider.',
|
url: 'https://tme.eu/',
|
||||||
'settings_class' => TMESettings::class
|
disabledHelp: 'Configure the API Token and secret in provider settings to use this provider.',
|
||||||
];
|
settingsClass: TMESettings::class,
|
||||||
}
|
capabilities: [
|
||||||
|
ProviderCapabilities::BASIC,
|
||||||
public function getProviderKey(): string
|
ProviderCapabilities::FOOTPRINT,
|
||||||
{
|
ProviderCapabilities::PICTURE,
|
||||||
return 'tme';
|
ProviderCapabilities::DATASHEET,
|
||||||
|
ProviderCapabilities::PRICE,
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -83,7 +88,7 @@ class TMEProvider implements InfoProviderInterface, URLHandlerInfoProviderInterf
|
||||||
|
|
||||||
foreach($data['ProductList'] as $product) {
|
foreach($data['ProductList'] as $product) {
|
||||||
$result[] = new SearchResultDTO(
|
$result[] = new SearchResultDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $product['Symbol'],
|
provider_id: $product['Symbol'],
|
||||||
name: empty($product['OriginalSymbol']) ? $product['Symbol'] : $product['OriginalSymbol'],
|
name: empty($product['OriginalSymbol']) ? $product['Symbol'] : $product['OriginalSymbol'],
|
||||||
description: $product['Description'],
|
description: $product['Description'],
|
||||||
|
|
@ -119,7 +124,7 @@ class TMEProvider implements InfoProviderInterface, URLHandlerInfoProviderInterf
|
||||||
$parameters = $this->getParameters($id, $footprint);
|
$parameters = $this->getParameters($id, $footprint);
|
||||||
|
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $product['Symbol'],
|
provider_id: $product['Symbol'],
|
||||||
name: empty($product['OriginalSymbol']) ? $product['Symbol'] : $product['OriginalSymbol'],
|
name: empty($product['OriginalSymbol']) ? $product['Symbol'] : $product['OriginalSymbol'],
|
||||||
description: $product['Description'],
|
description: $product['Description'],
|
||||||
|
|
@ -290,17 +295,6 @@ class TMEProvider implements InfoProviderInterface, URLHandlerInfoProviderInterf
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::FOOTPRINT,
|
|
||||||
ProviderCapabilities::PICTURE,
|
|
||||||
ProviderCapabilities::DATASHEET,
|
|
||||||
ProviderCapabilities::PRICE,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHandledDomains(): array
|
public function getHandledDomains(): array
|
||||||
{
|
{
|
||||||
return ['tme.eu'];
|
return ['tme.eu'];
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ namespace App\Services\InfoProviderSystem\Providers;
|
||||||
|
|
||||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use Symfony\Component\DependencyInjection\Attribute\When;
|
use Symfony\Component\DependencyInjection\Attribute\When;
|
||||||
|
|
||||||
|
|
@ -34,20 +35,20 @@ use Symfony\Component\DependencyInjection\Attribute\When;
|
||||||
#[When(env: 'test')]
|
#[When(env: 'test')]
|
||||||
class TestProvider implements InfoProviderInterface
|
class TestProvider implements InfoProviderInterface
|
||||||
{
|
{
|
||||||
|
public const PROVIDER_KEY = 'test';
|
||||||
|
|
||||||
public function getProviderInfo(): array
|
public function getProviderInfo(): ProviderInfoDTO
|
||||||
{
|
{
|
||||||
return [
|
return new ProviderInfoDTO(
|
||||||
'name' => 'Test Provider',
|
key: self::PROVIDER_KEY,
|
||||||
'description' => 'This is a test provider',
|
name: 'Test Provider',
|
||||||
//'url' => 'https://example.com',
|
description: 'This is a test provider',
|
||||||
'disabled_help' => 'This provider is disabled for testing purposes'
|
disabledHelp: 'This provider is disabled for testing purposes',
|
||||||
];
|
capabilities: [
|
||||||
}
|
ProviderCapabilities::BASIC,
|
||||||
|
ProviderCapabilities::FOOTPRINT,
|
||||||
public function getProviderKey(): string
|
],
|
||||||
{
|
);
|
||||||
return 'test';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool
|
public function isActive(): bool
|
||||||
|
|
@ -58,24 +59,16 @@ class TestProvider implements InfoProviderInterface
|
||||||
public function searchByKeyword(string $keyword, array $options = []): array
|
public function searchByKeyword(string $keyword, array $options = []): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
new SearchResultDTO(provider_key: $this->getProviderKey(), provider_id: 'element1', name: 'Element 1', description: 'fd'),
|
new SearchResultDTO(provider_key: self::PROVIDER_KEY, provider_id: 'element1', name: 'Element 1', description: 'fd'),
|
||||||
new SearchResultDTO(provider_key: $this->getProviderKey(), provider_id: 'element2', name: 'Element 2', description: 'fd'),
|
new SearchResultDTO(provider_key: self::PROVIDER_KEY, provider_id: 'element2', name: 'Element 2', description: 'fd'),
|
||||||
new SearchResultDTO(provider_key: $this->getProviderKey(), provider_id: 'element3', name: 'Element 3', description: 'fd'),
|
new SearchResultDTO(provider_key: self::PROVIDER_KEY, provider_id: 'element3', name: 'Element 3', description: 'fd'),
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCapabilities(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ProviderCapabilities::BASIC,
|
|
||||||
ProviderCapabilities::FOOTPRINT,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDetails(string $id, array $options = []): PartDetailDTO
|
public function getDetails(string $id, array $options = []): PartDetailDTO
|
||||||
{
|
{
|
||||||
return new PartDetailDTO(
|
return new PartDetailDTO(
|
||||||
provider_key: $this->getProviderKey(),
|
provider_key: self::PROVIDER_KEY,
|
||||||
provider_id: $id,
|
provider_id: $id,
|
||||||
name: 'Test Element',
|
name: 'Test Element',
|
||||||
description: 'fd',
|
description: 'fd',
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace App\State\Mcp;
|
||||||
use ApiPlatform\Metadata\Operation;
|
use ApiPlatform\Metadata\Operation;
|
||||||
use ApiPlatform\State\ProcessorInterface;
|
use ApiPlatform\State\ProcessorInterface;
|
||||||
use ApiPlatform\State\ProviderInterface;
|
use ApiPlatform\State\ProviderInterface;
|
||||||
use App\Services\InfoProviderSystem\DTOs\InfoProviderDTO;
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\ProviderRegistry;
|
use App\Services\InfoProviderSystem\ProviderRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -40,7 +40,7 @@ class ListInfoProvidersProcessor implements ProcessorInterface, ProviderInterfac
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return InfoProviderDTO[]
|
* @return ProviderInfoDTO[]
|
||||||
*/
|
*/
|
||||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array
|
||||||
{
|
{
|
||||||
|
|
@ -48,7 +48,7 @@ class ListInfoProvidersProcessor implements ProcessorInterface, ProviderInterfac
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return InfoProviderDTO[]
|
* @return ProviderInfoDTO[]
|
||||||
*/
|
*/
|
||||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): array
|
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): array
|
||||||
{
|
{
|
||||||
|
|
@ -56,22 +56,14 @@ class ListInfoProvidersProcessor implements ProcessorInterface, ProviderInterfac
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return InfoProviderDTO[]
|
* @return ProviderInfoDTO[]
|
||||||
*/
|
*/
|
||||||
private function listActiveProviders(): array
|
private function listActiveProviders(): array
|
||||||
{
|
{
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
foreach ($this->providerRegistry->getActiveProviders() as $provider) {
|
foreach ($this->providerRegistry->getActiveProviders() as $provider) {
|
||||||
$info = $provider->getProviderInfo();
|
$result[] = $provider->getProviderInfo();
|
||||||
|
|
||||||
$result[] = new InfoProviderDTO(
|
|
||||||
key: $provider->getProviderKey(),
|
|
||||||
name: $info['name'],
|
|
||||||
description: $info['description'] ?? null,
|
|
||||||
url: $info['url'] ?? null,
|
|
||||||
capabilities: array_map(static fn ($capability) => $capability->name, $provider->getCapabilities()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ final readonly class InfoProviderExtension
|
||||||
public function getInfoProviderName(string $key): ?string
|
public function getInfoProviderName(string $key): ?string
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $this->providerRegistry->getProviderByKey($key)->getProviderInfo()['name'];
|
return $this->providerRegistry->getProviderByKey($key)->getProviderInfo()->name;
|
||||||
} catch (\InvalidArgumentException) {
|
} catch (\InvalidArgumentException) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,35 +8,35 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<h5>
|
<h5>
|
||||||
{% if provider.providerInfo.url is defined and provider.providerInfo.url is not empty %}
|
{% if provider.providerInfo.url is not empty %}
|
||||||
<a href="{{ provider.providerInfo.url }}" target="_blank">{{ provider.providerInfo.name }}</a>
|
<a href="{{ provider.providerInfo.url }}" target="_blank">{{ provider.providerInfo.name }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ provider.providerInfo.name | trans }}
|
{{ provider.providerInfo.name | trans }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h5>
|
</h5>
|
||||||
<div>
|
<div>
|
||||||
{% if provider.providerInfo.description is defined and provider.providerInfo.description is not null %}
|
{% if provider.providerInfo.description is not null %}
|
||||||
{{ provider.providerInfo.description | trans }}
|
{{ provider.providerInfo.description | trans }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
{% if provider.providerInfo.settings_class is defined %}
|
{% if provider.providerInfo.settingsClass is not null %}
|
||||||
<a href="{{ path('info_providers_provider_settings', {'provider': provider.providerKey}) }}" class="btn btn-primary btn-sm {% if not is_granted('@config.change_system_settings') %}disabled{% endif %}"
|
<a href="{{ path('info_providers_provider_settings', {'provider': provider.providerInfo.key}) }}" class="btn btn-primary btn-sm {% if not is_granted('@config.change_system_settings') %}disabled{% endif %}"
|
||||||
title="{% trans %}info_providers.settings.title{% endtrans %}"
|
title="{% trans %}info_providers.settings.title{% endtrans %}"
|
||||||
><i class="fa-solid fa-cog"></i></a>
|
><i class="fa-solid fa-cog"></i></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for capability in provider.capabilities|sort((a, b) => a.orderIndex <=> b.orderIndex) %}
|
{% for capability in provider.providerInfo.capabilities|sort((a, b) => a.orderIndex <=> b.orderIndex) %}
|
||||||
{# @var capability \App\Services\InfoProviderSystem\Providers\ProviderCapabilities #}
|
{# @var capability \App\Services\InfoProviderSystem\Providers\ProviderCapabilities #}
|
||||||
<span class="badge text-bg-secondary">
|
<span class="badge text-bg-secondary">
|
||||||
<i class="{{ capability.fAIconClass }} fa-fw"></i>
|
<i class="{{ capability.fAIconClass }} fa-fw"></i>
|
||||||
{{ capability.translationKey|trans }}
|
{{ capability.translationKey|trans }}
|
||||||
</span>
|
</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if provider.providerInfo.oauth_app_name is defined and provider.providerInfo.oauth_app_name is not empty %}
|
{% if provider.providerInfo.oauthAppName is not empty %}
|
||||||
<br>
|
<br>
|
||||||
<a href="{{ path('oauth_client_connect', {'name': provider.providerInfo.oauth_app_name}) }}" target="_blank" class="btn btn-outline-secondary btn-sm mt-2">{% trans %}oauth_client.connect.btn{% endtrans %}</a>
|
<a href="{{ path('oauth_client_connect', {'name': provider.providerInfo.oauthAppName}) }}" target="_blank" class="btn btn-outline-secondary btn-sm mt-2">{% trans %}oauth_client.connect.btn{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -44,9 +44,9 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-danger">
|
<div class="col text-danger">
|
||||||
<i class="fa-solid fa-circle-exclamation"></i> <b>{% trans %}info_providers.providers_list.disabled{% endtrans %}</b>
|
<i class="fa-solid fa-circle-exclamation"></i> <b>{% trans %}info_providers.providers_list.disabled{% endtrans %}</b>
|
||||||
{% if provider.providerInfo.disabled_help is defined and provider.providerInfo.disabled_help is not empty %}
|
{% if provider.providerInfo.disabledHelp is not empty %}
|
||||||
<br>
|
<br>
|
||||||
<span class="text-muted">{{ provider.providerInfo.disabled_help|trans }}</span>
|
<span class="text-muted">{{ provider.providerInfo.disabledHelp|trans }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
{% block card_content %}
|
{% block card_content %}
|
||||||
<div class="{{ offset_label }}">
|
<div class="{{ offset_label }}">
|
||||||
<h3>
|
<h3>
|
||||||
{% if info_provider_info.url is defined %}
|
{% if info_provider_info.url is not empty %}
|
||||||
<a href="{{ info_provider_info.url }}" class="link-external" target="_blank" rel="nofollow">{{ info_provider_info.name }}</a>
|
<a href="{{ info_provider_info.url }}" class="link-external" target="_blank" rel="nofollow">{{ info_provider_info.name }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ info_provider_info.name }}
|
{{ info_provider_info.name }}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,16 @@ class InfoProviderEndpointTest extends AuthenticatedApiTestCase
|
||||||
|
|
||||||
$keys = array_column($json['hydra:member'], 'key');
|
$keys = array_column($json['hydra:member'], 'key');
|
||||||
self::assertContains('test', $keys);
|
self::assertContains('test', $keys);
|
||||||
|
|
||||||
|
//The 'test' provider has a disabledHelp set internally, but it must not leak into the API response
|
||||||
|
$testProvider = $json['hydra:member'][array_search('test', $keys, true)];
|
||||||
|
self::assertArrayHasKey('capabilities', $testProvider);
|
||||||
|
self::assertArrayNotHasKey('disabledHelp', $testProvider);
|
||||||
|
self::assertArrayNotHasKey('oauthAppName', $testProvider);
|
||||||
|
self::assertArrayNotHasKey('settingsClass', $testProvider);
|
||||||
|
|
||||||
|
//Capabilities must serialize as plain enum-name strings, not objects
|
||||||
|
self::assertSame(['BASIC', 'FOOTPRINT'], $testProvider['capabilities']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListInfoProvidersRequiresAuthentication(): void
|
public function testListInfoProvidersRequiresAuthentication(): void
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ namespace App\Tests\Services\InfoProviderSystem\DTOs;
|
||||||
|
|
||||||
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
||||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO;
|
use App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
final class BulkSearchFieldMappingDTOTest extends TestCase
|
final class BulkSearchFieldMappingDTOTest extends TestCase
|
||||||
|
|
@ -32,7 +33,7 @@ final class BulkSearchFieldMappingDTOTest extends TestCase
|
||||||
public function testProviderInstanceNormalization(): void
|
public function testProviderInstanceNormalization(): void
|
||||||
{
|
{
|
||||||
$mockProvider = $this->createMock(InfoProviderInterface::class);
|
$mockProvider = $this->createMock(InfoProviderInterface::class);
|
||||||
$mockProvider->method('getProviderKey')->willReturn('mock_provider');
|
$mockProvider->method('getProviderInfo')->willReturn(new ProviderInfoDTO(key: 'mock_provider', name: 'mock_provider'));
|
||||||
|
|
||||||
$fieldMapping = new BulkSearchFieldMappingDTO(field: 'mpn', providers: ['provider1', $mockProvider], priority: 5);
|
$fieldMapping = new BulkSearchFieldMappingDTO(field: 'mpn', providers: ['provider1', $mockProvider], priority: 5);
|
||||||
$this->assertSame(['provider1', 'mock_provider'], $fieldMapping->providers);
|
$this->assertSame(['provider1', 'mock_provider'], $fieldMapping->providers);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||||
*/
|
*/
|
||||||
namespace App\Tests\Services\InfoProviderSystem;
|
namespace App\Tests\Services\InfoProviderSystem;
|
||||||
|
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\ProviderRegistry;
|
use App\Services\InfoProviderSystem\ProviderRegistry;
|
||||||
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
||||||
use App\Services\InfoProviderSystem\Providers\URLHandlerInfoProviderInterface;
|
use App\Services\InfoProviderSystem\Providers\URLHandlerInfoProviderInterface;
|
||||||
|
|
@ -46,7 +47,7 @@ final class ProviderRegistryTest extends TestCase
|
||||||
public function getMockProvider(string $key, bool $active = true): InfoProviderInterface
|
public function getMockProvider(string $key, bool $active = true): InfoProviderInterface
|
||||||
{
|
{
|
||||||
$mock = $this->createMockForIntersectionOfInterfaces([InfoProviderInterface::class, URLHandlerInfoProviderInterface::class]);
|
$mock = $this->createMockForIntersectionOfInterfaces([InfoProviderInterface::class, URLHandlerInfoProviderInterface::class]);
|
||||||
$mock->method('getProviderKey')->willReturn($key);
|
$mock->method('getProviderInfo')->willReturn(new ProviderInfoDTO(key: $key, name: $key));
|
||||||
$mock->method('isActive')->willReturn($active);
|
$mock->method('isActive')->willReturn($active);
|
||||||
$mock->method('getHandledDomains')->willReturn(["$key.com", "test.$key.de"]);
|
$mock->method('getHandledDomains')->willReturn(["$key.com", "test.$key.de"]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\Providers\LCSCProvider;
|
use App\Services\InfoProviderSystem\Providers\LCSCProvider;
|
||||||
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
||||||
|
|
@ -56,18 +57,10 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$info = $this->provider->getProviderInfo();
|
$info = $this->provider->getProviderInfo();
|
||||||
|
|
||||||
$this->assertIsArray($info);
|
$this->assertInstanceOf(ProviderInfoDTO::class, $info);
|
||||||
$this->assertArrayHasKey('name', $info);
|
$this->assertSame('lcsc', $info->key);
|
||||||
$this->assertArrayHasKey('description', $info);
|
$this->assertEquals('LCSC', $info->name);
|
||||||
$this->assertArrayHasKey('url', $info);
|
$this->assertEquals('https://www.lcsc.com/', $info->url);
|
||||||
$this->assertArrayHasKey('disabled_help', $info);
|
|
||||||
$this->assertEquals('LCSC', $info['name']);
|
|
||||||
$this->assertEquals('https://www.lcsc.com/', $info['url']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetProviderKey(): void
|
|
||||||
{
|
|
||||||
$this->assertSame('lcsc', $this->provider->getProviderKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsActiveWhenEnabled(): void
|
public function testIsActiveWhenEnabled(): void
|
||||||
|
|
@ -86,7 +79,7 @@ final class LCSCProviderTest extends TestCase
|
||||||
|
|
||||||
public function testGetCapabilities(): void
|
public function testGetCapabilities(): void
|
||||||
{
|
{
|
||||||
$capabilities = $this->provider->getCapabilities();
|
$capabilities = $this->provider->getProviderInfo()->capabilities;
|
||||||
|
|
||||||
$this->assertIsArray($capabilities);
|
$this->assertIsArray($capabilities);
|
||||||
$this->assertContains(ProviderCapabilities::BASIC, $capabilities);
|
$this->assertContains(ProviderCapabilities::BASIC, $capabilities);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ namespace App\Tests\Services\InfoProviderSystem\Providers;
|
||||||
|
|
||||||
use App\Entity\Parts\ManufacturingStatus;
|
use App\Entity\Parts\ManufacturingStatus;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
||||||
|
|
@ -212,17 +213,10 @@ final class TMEProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$info = $this->provider->getProviderInfo();
|
$info = $this->provider->getProviderInfo();
|
||||||
|
|
||||||
$this->assertIsArray($info);
|
$this->assertInstanceOf(ProviderInfoDTO::class, $info);
|
||||||
$this->assertArrayHasKey('name', $info);
|
$this->assertSame('tme', $info->key);
|
||||||
$this->assertArrayHasKey('description', $info);
|
$this->assertEquals('TME', $info->name);
|
||||||
$this->assertArrayHasKey('url', $info);
|
$this->assertEquals('https://tme.eu/', $info->url);
|
||||||
$this->assertEquals('TME', $info['name']);
|
|
||||||
$this->assertEquals('https://tme.eu/', $info['url']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetProviderKey(): void
|
|
||||||
{
|
|
||||||
$this->assertSame('tme', $this->provider->getProviderKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsActiveWithCredentials(): void
|
public function testIsActiveWithCredentials(): void
|
||||||
|
|
@ -239,7 +233,7 @@ final class TMEProviderTest extends TestCase
|
||||||
|
|
||||||
public function testGetCapabilities(): void
|
public function testGetCapabilities(): void
|
||||||
{
|
{
|
||||||
$capabilities = $this->provider->getCapabilities();
|
$capabilities = $this->provider->getProviderInfo()->capabilities;
|
||||||
|
|
||||||
$this->assertIsArray($capabilities);
|
$this->assertIsArray($capabilities);
|
||||||
$this->assertContains(ProviderCapabilities::BASIC, $capabilities);
|
$this->assertContains(ProviderCapabilities::BASIC, $capabilities);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ namespace App\Tests\State\Mcp;
|
||||||
use ApiPlatform\Metadata\Get;
|
use ApiPlatform\Metadata\Get;
|
||||||
use App\Mcp\DTO\InfoProviderPartDetailsInput;
|
use App\Mcp\DTO\InfoProviderPartDetailsInput;
|
||||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOtoEntityConverter;
|
use App\Services\InfoProviderSystem\DTOtoEntityConverter;
|
||||||
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
||||||
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
||||||
|
|
@ -45,14 +46,14 @@ final class GetInfoProviderPartDetailsProcessorTest extends TestCase
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
$activeProvider = $this->createMock(InfoProviderInterface::class);
|
$activeProvider = $this->createMock(InfoProviderInterface::class);
|
||||||
$activeProvider->method('getProviderKey')->willReturn('test1');
|
$activeProvider->method('getProviderInfo')->willReturn(new ProviderInfoDTO(key: 'test1', name: 'test1'));
|
||||||
$activeProvider->method('isActive')->willReturn(true);
|
$activeProvider->method('isActive')->willReturn(true);
|
||||||
$activeProvider->method('getDetails')->willReturn(
|
$activeProvider->method('getDetails')->willReturn(
|
||||||
new PartDetailDTO(provider_key: 'test1', provider_id: '42', name: 'Element 42', description: 'desc')
|
new PartDetailDTO(provider_key: 'test1', provider_id: '42', name: 'Element 42', description: 'desc')
|
||||||
);
|
);
|
||||||
|
|
||||||
$inactiveProvider = $this->createMock(InfoProviderInterface::class);
|
$inactiveProvider = $this->createMock(InfoProviderInterface::class);
|
||||||
$inactiveProvider->method('getProviderKey')->willReturn('test2');
|
$inactiveProvider->method('getProviderInfo')->willReturn(new ProviderInfoDTO(key: 'test2', name: 'test2'));
|
||||||
$inactiveProvider->method('isActive')->willReturn(false);
|
$inactiveProvider->method('isActive')->willReturn(false);
|
||||||
|
|
||||||
$providerRegistry = new ProviderRegistry([$activeProvider, $inactiveProvider]);
|
$providerRegistry = new ProviderRegistry([$activeProvider, $inactiveProvider]);
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace App\Tests\State\Mcp;
|
||||||
|
|
||||||
use ApiPlatform\Metadata\Get;
|
use ApiPlatform\Metadata\Get;
|
||||||
use App\Mcp\DTO\ListInfoProvidersInput;
|
use App\Mcp\DTO\ListInfoProvidersInput;
|
||||||
use App\Services\InfoProviderSystem\DTOs\InfoProviderDTO;
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
use App\Services\InfoProviderSystem\Providers\InfoProviderInterface;
|
||||||
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
||||||
use App\Services\InfoProviderSystem\ProviderRegistry;
|
use App\Services\InfoProviderSystem\ProviderRegistry;
|
||||||
|
|
@ -37,20 +37,18 @@ final class ListInfoProvidersProcessorTest extends TestCase
|
||||||
public function testOnlyActiveProvidersAreListed(): void
|
public function testOnlyActiveProvidersAreListed(): void
|
||||||
{
|
{
|
||||||
$active = $this->createMock(InfoProviderInterface::class);
|
$active = $this->createMock(InfoProviderInterface::class);
|
||||||
$active->method('getProviderKey')->willReturn('active_provider');
|
|
||||||
$active->method('isActive')->willReturn(true);
|
$active->method('isActive')->willReturn(true);
|
||||||
$active->method('getProviderInfo')->willReturn([
|
$active->method('getProviderInfo')->willReturn(new ProviderInfoDTO(
|
||||||
'name' => 'Active Provider',
|
key: 'active_provider',
|
||||||
'description' => 'A provider that is active',
|
name: 'Active Provider',
|
||||||
'url' => 'https://example.com',
|
description: 'A provider that is active',
|
||||||
]);
|
url: 'https://example.com',
|
||||||
$active->method('getCapabilities')->willReturn([ProviderCapabilities::BASIC, ProviderCapabilities::PRICE]);
|
capabilities: [ProviderCapabilities::BASIC, ProviderCapabilities::PRICE],
|
||||||
|
));
|
||||||
|
|
||||||
$disabled = $this->createMock(InfoProviderInterface::class);
|
$disabled = $this->createMock(InfoProviderInterface::class);
|
||||||
$disabled->method('getProviderKey')->willReturn('disabled_provider');
|
|
||||||
$disabled->method('isActive')->willReturn(false);
|
$disabled->method('isActive')->willReturn(false);
|
||||||
$disabled->method('getProviderInfo')->willReturn(['name' => 'Disabled Provider']);
|
$disabled->method('getProviderInfo')->willReturn(new ProviderInfoDTO(key: 'disabled_provider', name: 'Disabled Provider'));
|
||||||
$disabled->method('getCapabilities')->willReturn([]);
|
|
||||||
|
|
||||||
$registry = new ProviderRegistry([$active, $disabled]);
|
$registry = new ProviderRegistry([$active, $disabled]);
|
||||||
$processor = new ListInfoProvidersProcessor($registry);
|
$processor = new ListInfoProvidersProcessor($registry);
|
||||||
|
|
@ -58,11 +56,11 @@ final class ListInfoProvidersProcessorTest extends TestCase
|
||||||
$result = $processor->process(new ListInfoProvidersInput(), new Get());
|
$result = $processor->process(new ListInfoProvidersInput(), new Get());
|
||||||
|
|
||||||
$this->assertCount(1, $result);
|
$this->assertCount(1, $result);
|
||||||
$this->assertInstanceOf(InfoProviderDTO::class, $result[0]);
|
$this->assertInstanceOf(ProviderInfoDTO::class, $result[0]);
|
||||||
$this->assertSame('active_provider', $result[0]->key);
|
$this->assertSame('active_provider', $result[0]->key);
|
||||||
$this->assertSame('Active Provider', $result[0]->name);
|
$this->assertSame('Active Provider', $result[0]->name);
|
||||||
$this->assertSame('A provider that is active', $result[0]->description);
|
$this->assertSame('A provider that is active', $result[0]->description);
|
||||||
$this->assertSame('https://example.com', $result[0]->url);
|
$this->assertSame('https://example.com', $result[0]->url);
|
||||||
$this->assertSame(['BASIC', 'PRICE'], $result[0]->capabilities);
|
$this->assertSame([ProviderCapabilities::BASIC, ProviderCapabilities::PRICE], $result[0]->capabilities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ namespace App\Tests\State\Mcp;
|
||||||
|
|
||||||
use ApiPlatform\Metadata\Get;
|
use ApiPlatform\Metadata\Get;
|
||||||
use App\Mcp\DTO\InfoProviderSearchInput;
|
use App\Mcp\DTO\InfoProviderSearchInput;
|
||||||
|
use App\Services\InfoProviderSystem\DTOs\ProviderInfoDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||||
use App\Services\InfoProviderSystem\DTOtoEntityConverter;
|
use App\Services\InfoProviderSystem\DTOtoEntityConverter;
|
||||||
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
use App\Services\InfoProviderSystem\PartInfoRetriever;
|
||||||
|
|
@ -69,8 +70,8 @@ final class SearchInfoProvidersProcessorTest extends TestCase
|
||||||
private function getMockProvider(string $key, bool $active = true): InfoProviderInterface
|
private function getMockProvider(string $key, bool $active = true): InfoProviderInterface
|
||||||
{
|
{
|
||||||
$mock = $this->createMock(InfoProviderInterface::class);
|
$mock = $this->createMock(InfoProviderInterface::class);
|
||||||
$mock->method('getProviderKey')->willReturn($key);
|
|
||||||
$mock->method('isActive')->willReturn($active);
|
$mock->method('isActive')->willReturn($active);
|
||||||
|
$mock->method('getProviderInfo')->willReturn(new ProviderInfoDTO(key: $key, name: $key));
|
||||||
$mock->method('searchByKeyword')->willReturn([
|
$mock->method('searchByKeyword')->willReturn([
|
||||||
new SearchResultDTO(provider_key: $key, provider_id: '1', name: 'Element 1', description: 'desc'),
|
new SearchResultDTO(provider_key: $key, provider_id: '1', name: 'Element 1', description: 'desc'),
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue