Improved code formatting

This commit is contained in:
Jan Böhmer 2024-09-09 00:24:24 +02:00
parent d4fb2ba46a
commit ef22856e5c

View file

@ -20,41 +20,41 @@
/** /**
* OEMSecretsProvider Class * OEMSecretsProvider Class
* *
* This class is responsible for interfacing with the OEMSecrets API (version 3.0.1) to retrieve and manage information * This class is responsible for interfacing with the OEMSecrets API (version 3.0.1) to retrieve and manage information
* about electronic components. Since the API does not provide a unique identifier for each part, the class aggregates * about electronic components. Since the API does not provide a unique identifier for each part, the class aggregates
* results based on "part_number" and "manufacturer_id". It also transforms unstructured descriptions into structured * results based on "part_number" and "manufacturer_id". It also transforms unstructured descriptions into structured
* parameters and aggregates datasheets and images provided by multiple distributors. * parameters and aggregates datasheets and images provided by multiple distributors.
* The OEMSecrets API returns results by matching the provided part number not only with the original part number * The OEMSecrets API returns results by matching the provided part number not only with the original part number
* but also with the distributor-assigned part number and/or the part description. * but also with the distributor-assigned part number and/or the part description.
* *
* Key functionalities: * Key functionalities:
* - Aggregation of results based on part_number and manufacturer_id to ensure unique identification of parts. * - Aggregation of results based on part_number and manufacturer_id to ensure unique identification of parts.
* - Conversion of component descriptions into structured parameters (ParameterDTO) for better clarity and searchability. * - Conversion of component descriptions into structured parameters (ParameterDTO) for better clarity and searchability.
* - Aggregation of datasheets and images from multiple distributors, ensuring that all available resources are collected. * - Aggregation of datasheets and images from multiple distributors, ensuring that all available resources are collected.
* - Price handling, including filtering of distributors that offer zero prices, controlled by the `zero_price` configuration variable. * - Price handling, including filtering of distributors that offer zero prices, controlled by the `zero_price` configuration variable.
* - A sorting algorithm that first prioritizes exact matches with the keyword, followed by alphabetical sorting of items * - A sorting algorithm that first prioritizes exact matches with the keyword, followed by alphabetical sorting of items
* with the same prefix (e.g., "BC546", "BC546A", "BC546B"), and finally, sorts by either manufacturer or completeness * with the same prefix (e.g., "BC546", "BC546A", "BC546B"), and finally, sorts by either manufacturer or completeness
* based on the specified criteria. * based on the specified criteria.
* - Sorting the distributors: * - Sorting the distributors:
* 1. Environment's country_code first. * 1. Environment's country_code first.
* 2. Region matching environment's country_code, prioritizing "Global" ('XX'). * 2. Region matching environment's country_code, prioritizing "Global" ('XX').
* 3. Distributors with null country_code/region are placed last. * 3. Distributors with null country_code/region are placed last.
* 4. Final fallback is alphabetical sorting by region and country_code. * 4. Final fallback is alphabetical sorting by region and country_code.
* *
* Configuration: * Configuration:
* - The ZERO_PRICE variable must be set in the `.env.local` file. If is set to 0, the class will skip distributors * - The ZERO_PRICE variable must be set in the `.env.local` file. If is set to 0, the class will skip distributors
* that do not offer valid prices for the components. * that do not offer valid prices for the components.
* - Currency and country settings can also be specified for localized pricing and distributor filtering. * - Currency and country settings can also be specified for localized pricing and distributor filtering.
* - Generation of parameters: if SET_PARAM is set to 1 the parameters for the part are generated from the description * - Generation of parameters: if SET_PARAM is set to 1 the parameters for the part are generated from the description
* transforming unstructured descriptions into structured parameters; each parameter in description should have the form: * transforming unstructured descriptions into structured parameters; each parameter in description should have the form:
* "...;name1:value1;name2:value2" * "...;name1:value1;name2:value2"
* - Sorting is guided by SORT_CRITERIA variable. The sorting process first arranges items based on the provided keyword. * - Sorting is guided by SORT_CRITERIA variable. The sorting process first arranges items based on the provided keyword.
* Then, if set to 'C', it further sorts by completeness (prioritizing items with the most detailed information). * Then, if set to 'C', it further sorts by completeness (prioritizing items with the most detailed information).
* If set to 'M', it further sorts by manufacturer name. If unset or set to any other value, no sorting is performed. * If set to 'M', it further sorts by manufacturer name. If unset or set to any other value, no sorting is performed.
* Distributors within each item are further sorted based on country_code and region, following the rules explained * Distributors within each item are further sorted based on country_code and region, following the rules explained
* in the previous comment. * in the previous comment.
* *
* Data Handling: * Data Handling:
* - The class divides and stores component information across multiple session arrays: * - The class divides and stores component information across multiple session arrays:
* - `basic_info_results`: Stores basic information like name, description, manufacturer, and category. * - `basic_info_results`: Stores basic information like name, description, manufacturer, and category.
@ -62,15 +62,15 @@
* - `images_results`: Collects images of components from various sources, preventing duplication. * - `images_results`: Collects images of components from various sources, preventing duplication.
* - `parameters_results`: Extracts and stores key parameters parsed from component descriptions. * - `parameters_results`: Extracts and stores key parameters parsed from component descriptions.
* - `purchase_info_results`: Contains detailed purchasing information like pricing and distributor details. * - `purchase_info_results`: Contains detailed purchasing information like pricing and distributor details.
* *
* - By splitting the data into separate session arrays, the class optimizes memory usage and simplifies retrieval * - By splitting the data into separate session arrays, the class optimizes memory usage and simplifies retrieval
* of specific details without loading the entire dataset at once. * of specific details without loading the entire dataset at once.
* *
* Technical Details: * Technical Details:
* - Uses OEMSecrets API (version 3.0.1) to retrieve component data. * - Uses OEMSecrets API (version 3.0.1) to retrieve component data.
* - Data processing includes sanitizing input, avoiding duplicates, and dynamically adjusting information as new distributor * - Data processing includes sanitizing input, avoiding duplicates, and dynamically adjusting information as new distributor
* data becomes available (e.g., adding missing datasheets or parameters from subsequent API responses). * data becomes available (e.g., adding missing datasheets or parameters from subsequent API responses).
* *
* @package App\Services\InfoProviderSystem\Providers * @package App\Services\InfoProviderSystem\Providers
* @author Pasquale D'Orsi (https://github.com/pdo59) * @author Pasquale D'Orsi (https://github.com/pdo59)
* @version 1.2.0 * @version 1.2.0
@ -106,10 +106,10 @@ class OEMSecretsProvider implements InfoProviderInterface
private readonly string $set_param, private readonly string $set_param,
private readonly string $sort_criteria, private readonly string $sort_criteria,
private readonly CacheItemPoolInterface $partInfoCache private readonly CacheItemPoolInterface $partInfoCache
) )
{ {
} }
private array $countryNameToCodeMap = [ private array $countryNameToCodeMap = [
'Andorra' => 'AD', 'Andorra' => 'AD',
'United Arab Emirates' => 'AE', 'United Arab Emirates' => 'AE',
@ -270,19 +270,19 @@ class OEMSecretsProvider implements InfoProviderInterface
{ {
return $this->api_key !== ''; return $this->api_key !== '';
} }
/** /**
* Searches for products based on a given keyword using the OEMsecrets Part Search API. * Searches for products based on a given keyword using the OEMsecrets Part Search API.
* *
* This method queries the OEMsecrets API to retrieve distributor data for the provided part number, * This method queries the OEMsecrets API to retrieve distributor data for the provided part number,
* including details such as pricing, compliance, and inventory. It supports both direct API queries * including details such as pricing, compliance, and inventory. It supports both direct API queries
* and debugging with local JSON files. The results are processed, cached, and then sorted based * and debugging with local JSON files. The results are processed, cached, and then sorted based
* on the keyword and specified criteria. * on the keyword and specified criteria.
* *
* @param string $keyword The part number to search for * @param string $keyword The part number to search for
* @return array An array of processed product details, sorted by relevance and additional criteria. * @return array An array of processed product details, sorted by relevance and additional criteria.
* *
* @throws \Exception If the JSON file used for debugging is not found or contains errors. * @throws \Exception If the JSON file used for debugging is not found or contains errors.
*/ */
public function searchByKeyword(string $keyword): array public function searchByKeyword(string $keyword): array
@ -315,12 +315,12 @@ class OEMSecretsProvider implements InfoProviderInterface
To view prices in both USD and GBP add [ currency[]=USD&currency[]=GBP ] To view prices in both USD and GBP add [ currency[]=USD&currency[]=GBP ]
oemsecretsapi.com/partsearch?searchTerm=bd04&apiKey=abcexampleapikey123&currency[]=USD&currency[]=GBP oemsecretsapi.com/partsearch?searchTerm=bd04&apiKey=abcexampleapikey123&currency[]=USD&currency[]=GBP
*/ */
// Activate this block when querying the real APIs // Activate this block when querying the real APIs
//------------------ //------------------
$response = $this->oemsecretsClient->request('GET', self::ENDPOINT_URL, [ $response = $this->oemsecretsClient->request('GET', self::ENDPOINT_URL, [
'query' => [ 'query' => [
'searchTerm' => $keyword, 'searchTerm' => $keyword,
@ -346,7 +346,7 @@ class OEMSecretsProvider implements InfoProviderInterface
throw new \Exception("JSON file decode failed: " . json_last_error_msg()); throw new \Exception("JSON file decode failed: " . json_last_error_msg());
} }
//------------------*/ //------------------*/
$products = $response_array['stock'] ?? []; $products = $response_array['stock'] ?? [];
$results = []; $results = [];
@ -363,12 +363,12 @@ class OEMSecretsProvider implements InfoProviderInterface
$provider_id = $this->generateProviderId($product['part_number'], $product['manufacturer']); $provider_id = $this->generateProviderId($product['part_number'], $product['manufacturer']);
$partDetailDTO = $this->processBatch( $partDetailDTO = $this->processBatch(
$product, $product,
$provider_id, $provider_id,
$basicInfoResults, $basicInfoResults,
$datasheetsResults, $datasheetsResults,
$imagesResults, $imagesResults,
$parametersResults, $parametersResults,
$purchaseInfoResults $purchaseInfoResults
); );
@ -377,7 +377,7 @@ class OEMSecretsProvider implements InfoProviderInterface
$cacheKey = $this->getCacheKey($provider_id); $cacheKey = $this->getCacheKey($provider_id);
$cacheItem = $this->partInfoCache->getItem($cacheKey); $cacheItem = $this->partInfoCache->getItem($cacheKey);
$cacheItem->set($partDetailDTO); $cacheItem->set($partDetailDTO);
$cacheItem->expiresAfter(3600 * 24); $cacheItem->expiresAfter(3600 * 24);
$this->partInfoCache->save($cacheItem); $this->partInfoCache->save($cacheItem);
} }
} }
@ -390,10 +390,10 @@ class OEMSecretsProvider implements InfoProviderInterface
/** /**
* Generates a cache key for storing part details based on the provided provider ID. * Generates a cache key for storing part details based on the provided provider ID.
* *
* This method creates a unique cache key by prefixing the provider ID with 'part_details_' * This method creates a unique cache key by prefixing the provider ID with 'part_details_'
* and hashing the provider ID using MD5 to ensure a consistent and compact key format. * and hashing the provider ID using MD5 to ensure a consistent and compact key format.
* *
* @param string $provider_id The unique identifier of the provider or part. * @param string $provider_id The unique identifier of the provider or part.
* @return string The generated cache key. * @return string The generated cache key.
*/ */
@ -406,7 +406,7 @@ class OEMSecretsProvider implements InfoProviderInterface
* Retrieves detailed information about the part with the given provider ID from the cache. * Retrieves detailed information about the part with the given provider ID from the cache.
* *
* This method checks the cache for the details of the specified part. If the details are * This method checks the cache for the details of the specified part. If the details are
* found in the cache, they are returned. If not, an exception is thrown indicating that * found in the cache, they are returned. If not, an exception is thrown indicating that
* the details could not be found. * the details could not be found.
* *
* @param string $id The unique identifier of the provider or part. * @param string $id The unique identifier of the provider or part.
@ -469,9 +469,9 @@ class OEMSecretsProvider implements InfoProviderInterface
* @param array &$purchaseInfoResults Array containing purchase information, including distributors and pricing details. * @param array &$purchaseInfoResults Array containing purchase information, including distributors and pricing details.
* *
* @return PartDetailDTO|null Returns a PartDetailDTO object if the product is processed successfully, otherwise null. * @return PartDetailDTO|null Returns a PartDetailDTO object if the product is processed successfully, otherwise null.
* *
* @throws \Exception If a required key in the product data is missing or if there is an issue creating the DTO. * @throws \Exception If a required key in the product data is missing or if there is an issue creating the DTO.
* *
* @see createOrUpdateBasicInfo() Creates or updates the basic product information. * @see createOrUpdateBasicInfo() Creates or updates the basic product information.
* @see getPrices() Extracts the pricing information for the product. * @see getPrices() Extracts the pricing information for the product.
* @see parseDataSheets() Parses and prevents duplication of datasheets. * @see parseDataSheets() Parses and prevents duplication of datasheets.
@ -481,22 +481,22 @@ class OEMSecretsProvider implements InfoProviderInterface
* *
* @note Distributors within the product are sorted by country_code and region: * @note Distributors within the product are sorted by country_code and region:
* 1. Distributors with the environment's country_code come first. * 1. Distributors with the environment's country_code come first.
* 2. Distributors in the same region as the environment's country_code are next, * 2. Distributors in the same region as the environment's country_code are next,
* with "Global" ('XX') prioritized within this region. * with "Global" ('XX') prioritized within this region.
* 3. Distributors with null country_code or region are placed last. * 3. Distributors with null country_code or region are placed last.
* 4. Remaining distributors are sorted alphabetically by region and country_code. * 4. Remaining distributors are sorted alphabetically by region and country_code.
*/ */
private function processBatch( private function processBatch(
array $product, array $product,
string $provider_id, string $provider_id,
array &$basicInfoResults, array &$basicInfoResults,
array &$datasheetsResults, array &$datasheetsResults,
array &$imagesResults, array &$imagesResults,
array &$parametersResults, array &$parametersResults,
array &$purchaseInfoResults array &$purchaseInfoResults
): ?PartDetailDTO ): ?PartDetailDTO
{ {
if (!isset($product['manufacturer'], $product['part_number'])) { if (!isset($product['manufacturer'], $product['part_number'])) {
throw new \InvalidArgumentException("Missing required product data: 'manufacturer' or 'part_number'"); throw new \InvalidArgumentException("Missing required product data: 'manufacturer' or 'part_number'");
} }
@ -523,32 +523,32 @@ class OEMSecretsProvider implements InfoProviderInterface
$thenotes = $description; // Save the complete description $thenotes = $description; // Save the complete description
$description = substr($description, 0, 100) . '...'; // Truncate the description $description = substr($description, 0, 100) . '...'; // Truncate the description
} }
// Extract prices // Extract prices
$priceDTOs = $this->getPrices($product); $priceDTOs = $this->getPrices($product);
if (empty($priceDTOs) && (int)$this->zero_price === 0) { if (empty($priceDTOs) && (int)$this->zero_price === 0) {
return null; // Skip products without valid prices return null; // Skip products without valid prices
} }
$existingBasicInfo = isset($basicInfoResults[$provider_id]) && is_array($basicInfoResults[$provider_id]) $existingBasicInfo = isset($basicInfoResults[$provider_id]) && is_array($basicInfoResults[$provider_id])
? $basicInfoResults[$provider_id] ? $basicInfoResults[$provider_id]
: []; : [];
$basicInfoResults[$provider_id] = $this->createOrUpdateBasicInfo( $basicInfoResults[$provider_id] = $this->createOrUpdateBasicInfo(
$provider_id, $provider_id,
$product, $product,
$description, $description,
$thenotes, $thenotes,
$existingBasicInfo $existingBasicInfo
); );
// Update images, datasheets, and parameters // Update images, datasheets, and parameters
$newDatasheets = $this->parseDataSheets($product['datasheet_url'] ?? null, null, $datasheetsResults[$provider_id] ?? []); $newDatasheets = $this->parseDataSheets($product['datasheet_url'] ?? null, null, $datasheetsResults[$provider_id] ?? []);
if ($newDatasheets !== null) { if ($newDatasheets !== null) {
$datasheetsResults[$provider_id] = array_merge($datasheetsResults[$provider_id] ?? [], $newDatasheets); $datasheetsResults[$provider_id] = array_merge($datasheetsResults[$provider_id] ?? [], $newDatasheets);
} }
$imagesResults[$provider_id] = $this->getImages($product, $imagesResults[$provider_id] ?? []); $imagesResults[$provider_id] = $this->getImages($product, $imagesResults[$provider_id] ?? []);
if ($this->set_param == 1) { if ($this->set_param == 1) {
$parametersResults[$provider_id] = $this->getParameters($product, $parametersResults[$provider_id] ?? []); $parametersResults[$provider_id] = $this->getParameters($product, $parametersResults[$provider_id] ?? []);
@ -570,13 +570,13 @@ class OEMSecretsProvider implements InfoProviderInterface
$countryCodeA = $this->distributorCountryCodes[$nameA] ?? null; $countryCodeA = $this->distributorCountryCodes[$nameA] ?? null;
$countryCodeB = $this->distributorCountryCodes[$nameB] ?? null; $countryCodeB = $this->distributorCountryCodes[$nameB] ?? null;
$regionA = $this->countryCodeToRegionMap[$countryCodeA] ?? ''; $regionA = $this->countryCodeToRegionMap[$countryCodeA] ?? '';
$regionB = $this->countryCodeToRegionMap[$countryCodeB] ?? ''; $regionB = $this->countryCodeToRegionMap[$countryCodeB] ?? '';
// If the map is empty or doesn't contain the key for $this->country_code, assign a placeholder region. // If the map is empty or doesn't contain the key for $this->country_code, assign a placeholder region.
$regionForEnvCountry = $this->countryCodeToRegionMap[$this->country_code] ?? ''; $regionForEnvCountry = $this->countryCodeToRegionMap[$this->country_code] ?? '';
// Convert to string before comparison to avoid mixed types // Convert to string before comparison to avoid mixed types
$countryCodeA = (string) $countryCodeA; $countryCodeA = (string) $countryCodeA;
$countryCodeB = (string) $countryCodeB; $countryCodeB = (string) $countryCodeB;
@ -593,9 +593,9 @@ class OEMSecretsProvider implements InfoProviderInterface
// Step 1: country_code from the environment // Step 1: country_code from the environment
if ($countryCodeA === $this->country_code && $countryCodeB !== $this->country_code) { if ($countryCodeA === $this->country_code && $countryCodeB !== $this->country_code) {
return -1; return -1;
} elseif ($countryCodeA !== $this->country_code && $countryCodeB === $this->country_code) { } elseif ($countryCodeA !== $this->country_code && $countryCodeB === $this->country_code) {
return 1; return 1;
} }
// Step 2: Sort by environment's region, prioritizing "Global" (XX) // Step 2: Sort by environment's region, prioritizing "Global" (XX)
@ -613,7 +613,7 @@ class OEMSecretsProvider implements InfoProviderInterface
return 1; return 1;
} }
} }
// Step 4: Alphabetical sorting by region and country_code // Step 4: Alphabetical sorting by region and country_code
$regionComparison = strcasecmp($regionA , $regionB); $regionComparison = strcasecmp($regionA , $regionB);
if ($regionComparison !== 0) { if ($regionComparison !== 0) {
@ -625,7 +625,7 @@ class OEMSecretsProvider implements InfoProviderInterface
}); });
} }
// Convert the gathered data into a PartDetailDTO // Convert the gathered data into a PartDetailDTO
$partDetailDTO = new PartDetailDTO( $partDetailDTO = new PartDetailDTO(
provider_key: $basicInfoResults[$provider_id]['provider_key'], provider_key: $basicInfoResults[$provider_id]['provider_key'],
provider_id: $provider_id, provider_id: $provider_id,
@ -649,12 +649,12 @@ class OEMSecretsProvider implements InfoProviderInterface
// Without this instruction, when in dev mode, after the first or second call to getDetails, // Without this instruction, when in dev mode, after the first or second call to getDetails,
// a memory error occurs due to memory not being freed properly, leading to memory exhaustion. // a memory error occurs due to memory not being freed properly, leading to memory exhaustion.
gc_collect_cycles(); gc_collect_cycles();
return $partDetailDTO; return $partDetailDTO;
} }
/** /**
* Extracts pricing information from the product data, converts it to PriceDTO objects, * Extracts pricing information from the product data, converts it to PriceDTO objects,
* and returns them as an array. * and returns them as an array.
* *
@ -741,7 +741,7 @@ class OEMSecretsProvider implements InfoProviderInterface
{ {
$images = $existingImages; $images = $existingImages;
$imageUrl = $product['image_url'] ?? null; $imageUrl = $product['image_url'] ?? null;
if ($imageUrl) { if ($imageUrl) {
$imageName = basename(parse_url($imageUrl, PHP_URL_PATH)); $imageName = basename(parse_url($imageUrl, PHP_URL_PATH));
if (!in_array($imageName, array_column($images, 'name'), true)) { if (!in_array($imageName, array_column($images, 'name'), true)) {
@ -750,7 +750,7 @@ class OEMSecretsProvider implements InfoProviderInterface
} }
return $images; return $images;
} }
/** /**
* Extracts technical parameters from the product description, ensures no duplicates, and returns them as an array. * Extracts technical parameters from the product description, ensures no duplicates, and returns them as an array.
* *
@ -773,7 +773,7 @@ class OEMSecretsProvider implements InfoProviderInterface
if (!is_array($extractedParameters)) { if (!is_array($extractedParameters)) {
$extractedParameters = []; $extractedParameters = [];
} }
foreach ($extractedParameters as $newParam) { foreach ($extractedParameters as $newParam) {
$isDuplicate = false; $isDuplicate = false;
foreach ($parameters as $existingParam) { foreach ($parameters as $existingParam) {
@ -790,7 +790,7 @@ class OEMSecretsProvider implements InfoProviderInterface
return $parameters; return $parameters;
} }
/** /**
* Creates a PurchaseInfoDTO object containing distributor and pricing information for a product. * Creates a PurchaseInfoDTO object containing distributor and pricing information for a product.
* Ensures that the distributor name is valid and prices are available. * Ensures that the distributor name is valid and prices are available.
* *
@ -881,16 +881,16 @@ class OEMSecretsProvider implements InfoProviderInterface
* } $product The product data from the OEMSecrets API. * } $product The product data from the OEMSecrets API.
* @param string $description The truncated description for the product. * @param string $description The truncated description for the product.
* @param string $thenotes The full description saved as notes for the product. * @param string $thenotes The full description saved as notes for the product.
* *
* @return array The updated or newly created PartDetailDTO containing basic product information. * @return array The updated or newly created PartDetailDTO containing basic product information.
*/ */
private function createOrUpdateBasicInfo( private function createOrUpdateBasicInfo(
string $provider_id, string $provider_id,
array $product, array $product,
string $description, string $description,
string $thenotes, string $thenotes,
?array $existingBasicInfo ?array $existingBasicInfo
): array { ): array {
// 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 [
@ -907,7 +907,7 @@ class OEMSecretsProvider implements InfoProviderInterface
(int)($product['quantity_in_stock'] ?? 0) (int)($product['quantity_in_stock'] ?? 0)
), ),
'provider_url' => $this->generateInquiryUrl($product['part_number']), 'provider_url' => $this->generateInquiryUrl($product['part_number']),
'notes' => $thenotes, 'notes' => $thenotes,
'footprint' => null 'footprint' => null
]; ];
} }
@ -917,27 +917,27 @@ class OEMSecretsProvider implements InfoProviderInterface
'provider_key' => $existingBasicInfo['provider_key'] ?? $this->getProviderKey(), 'provider_key' => $existingBasicInfo['provider_key'] ?? $this->getProviderKey(),
'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
'description' => !empty($existingBasicInfo['description']) 'description' => !empty($existingBasicInfo['description'])
? $existingBasicInfo['description'] ? $existingBasicInfo['description']
: $description, : $description,
// Update category if it's null/empty // Update category if it's null/empty
'category' => !empty($existingBasicInfo['category']) 'category' => !empty($existingBasicInfo['category'])
? $existingBasicInfo['category'] ? $existingBasicInfo['category']
: $product['category'], : $product['category'],
'manufacturer' => $existingBasicInfo['manufacturer'] ?? $product['manufacturer'], 'manufacturer' => $existingBasicInfo['manufacturer'] ?? $product['manufacturer'],
'mpn' => $existingBasicInfo['mpn'] ?? $product['source_part_number'], 'mpn' => $existingBasicInfo['mpn'] ?? $product['source_part_number'],
'preview_image_url' => !empty($existingBasicInfo['preview_image_url']) 'preview_image_url' => !empty($existingBasicInfo['preview_image_url'])
? $existingBasicInfo['preview_image_url'] ? $existingBasicInfo['preview_image_url']
: ($product['image_url'] ?? null), : ($product['image_url'] ?? null),
'manufacturing_status' => !empty($existingBasicInfo['manufacturing_status']) 'manufacturing_status' => !empty($existingBasicInfo['manufacturing_status'])
? $existingBasicInfo['manufacturing_status'] ? $existingBasicInfo['manufacturing_status']
: $this->releaseStatusCodeToManufacturingStatus( : $this->releaseStatusCodeToManufacturingStatus(
$product['life_cycle'] ?? null, $product['life_cycle'] ?? null,
(int)($product['quantity_in_stock'] ?? 0) (int)($product['quantity_in_stock'] ?? 0)
), ),
'provider_url' => $existingBasicInfo['provider_url'] ?? $this->generateInquiryUrl($product['part_number']), // ?? $product['buy_now_url'], 'provider_url' => $existingBasicInfo['provider_url'] ?? $this->generateInquiryUrl($product['part_number']), // ?? $product['buy_now_url'],
'notes' => $existingBasicInfo['notes'] ?? $thenotes, 'notes' => $existingBasicInfo['notes'] ?? $thenotes,
'footprint' => null 'footprint' => null
]; ];
} }
@ -948,23 +948,23 @@ class OEMSecretsProvider implements InfoProviderInterface
* If multiple datasheets with the same default name are encountered, the function appends a * If multiple datasheets with the same default name are encountered, the function appends a
* numeric suffix to ensure uniqueness. * numeric suffix to ensure uniqueness.
* The query parameter used to extract the event link can be customized. * The query parameter used to extract the event link can be customized.
* *
* URL Requirements: * URL Requirements:
* - The URL should be a valid URL string. * - The URL should be a valid URL string.
* - The URL can include a query parameter named "event_link", which contains a sub-URL where the * - The URL can include a query parameter named "event_link", which contains a sub-URL where the
* actual datasheet file name is located (e.g., a link to a PDF file). * actual datasheet file name is located (e.g., a link to a PDF file).
* - If "event_link" is not present, the function attempts to extract the file name directly from * - If "event_link" is not present, the function attempts to extract the file name directly from
* the URL path. * the URL path.
* - The URL path should ideally end with a valid file extension (e.g., .pdf, .doc, .xls, etc.). * - The URL path should ideally end with a valid file extension (e.g., .pdf, .doc, .xls, etc.).
* *
* Example 1: * Example 1:
* Given URL: `https://example.com/datasheet.php?event_link=https%3A%2F%2Ffiles.example.com%2Fdatasheet.pdf` * Given URL: `https://example.com/datasheet.php?event_link=https%3A%2F%2Ffiles.example.com%2Fdatasheet.pdf`
* Extracted name: `datasheet.pdf` * Extracted name: `datasheet.pdf`
* *
* Example 2: * Example 2:
* Given URL: `https://example.com/files/datasheet.pdf` * Given URL: `https://example.com/files/datasheet.pdf`
* Extracted name: `datasheet.pdf` * Extracted name: `datasheet.pdf`
* *
* Example 3 (default name fallback): * Example 3 (default name fallback):
* Given URL: `https://example.com/files/noextensionfile` * Given URL: `https://example.com/files/noextensionfile`
* Extracted name: `datasheet.pdf` * Extracted name: `datasheet.pdf`
@ -1029,8 +1029,8 @@ class OEMSecretsProvider implements InfoProviderInterface
* - "Not Recommended for New Designs" / "Non raccomandato per nuovi progetti" * - "Not Recommended for New Designs" / "Non raccomandato per nuovi progetti"
* - "New Product" / "Nuovo prodotto" (if availableInStock > 0 else ANNOUNCED) * - "New Product" / "Nuovo prodotto" (if availableInStock > 0 else ANNOUNCED)
* - "End of Life" / "Fine vita" * - "End of Life" / "Fine vita"
* - vuoto / "Attivo" * - vuoto / "Attivo"
* *
* @param string|null $productStatus The lifecycle status from the Mouser API. Expected values are: * @param string|null $productStatus The lifecycle status from the Mouser API. Expected values are:
* - "Factory Special Order" * - "Factory Special Order"
* - "Not Recommended for New Designs" * - "Not Recommended for New Designs"
@ -1039,7 +1039,7 @@ class OEMSecretsProvider implements InfoProviderInterface
* - "Obsolete" * - "Obsolete"
* @param int $availableInStock The number of parts available in stock. * @param int $availableInStock The number of parts available in stock.
* @return ManufacturingStatus|null Returns the corresponding ManufacturingStatus or null if the status is unknown. * @return ManufacturingStatus|null Returns the corresponding ManufacturingStatus or null if the status is unknown.
* *
* @todo Probably need to review the values of field Lifecyclestatus. * @todo Probably need to review the values of field Lifecyclestatus.
*/ */
private function releaseStatusCodeToManufacturingStatus(?string $productStatus, int $availableInStock = 0): ?ManufacturingStatus private function releaseStatusCodeToManufacturingStatus(?string $productStatus, int $availableInStock = 0): ?ManufacturingStatus
@ -1066,13 +1066,13 @@ class OEMSecretsProvider implements InfoProviderInterface
* If the description contains only a single `:`, it is considered unstructured and ignored. * If the description contains only a single `:`, it is considered unstructured and ignored.
* The function processes the description by searching for key-value pairs in the format `name: value`, * The function processes the description by searching for key-value pairs in the format `name: value`,
* ignoring any parts of the description that do not follow this format. Parameters are split using either * ignoring any parts of the description that do not follow this format. Parameters are split using either
* `;` or `,` as separators. * `;` or `,` as separators.
* *
* The extraction logic handles typical values, ranges, units, and textual information from the description. * The extraction logic handles typical values, ranges, units, and textual information from the description.
* If the description is empty or cannot be processed into valid parameters, the function returns null. * If the description is empty or cannot be processed into valid parameters, the function returns null.
* *
* @param string|null $description The description text from which parameters are to be extracted. * @param string|null $description The description text from which parameters are to be extracted.
* *
* @return ParameterDTO[]|null Returns an array of `ParameterDTO` objects if parameters are successfully extracted, * @return ParameterDTO[]|null Returns an array of `ParameterDTO` objects if parameters are successfully extracted,
* or null if no valid parameters can be extracted from the description. * or null if no valid parameters can be extracted from the description.
*/ */
@ -1088,7 +1088,7 @@ class OEMSecretsProvider implements InfoProviderInterface
return null; return null;
} }
// Array to store parsed parameters // Array to store parsed parameters
$parameters = []; $parameters = [];
// Split the description using the ';' separator // Split the description using the ';' separator
@ -1144,15 +1144,15 @@ class OEMSecretsProvider implements InfoProviderInterface
* - "~100 Ohm" * - "~100 Ohm"
* *
* @param string $value The value string to be parsed, which may contain a number, unit, or both. * @param string $value The value string to be parsed, which may contain a number, unit, or both.
* *
* @return array An associative array with parsed components: * @return array An associative array with parsed components:
* - 'name' => string (the name of the parameter) * - 'name' => string (the name of the parameter)
* - 'value_typ' => float|null (the typical or parsed value) * - 'value_typ' => float|null (the typical or parsed value)
* - 'range_min' => float|null (the minimum value if it's a range) * - 'range_min' => float|null (the minimum value if it's a range)
* - 'range_max' => float|null (the maximum value if it's a range) * - 'range_max' => float|null (the maximum value if it's a range)
* - 'value_text' => string|null (any additional text or symbol) * - 'value_text' => string|null (any additional text or symbol)
* - 'unit' => string|null (the detected or default unit) * - 'unit' => string|null (the detected or default unit)
* - 'symbol' => string|null (any special symbol or additional text) * - 'symbol' => string|null (any special symbol or additional text)
*/ */
private function customParseValueIncludingUnit(string $name, string $value): array private function customParseValueIncludingUnit(string $name, string $value): array
{ {
@ -1180,15 +1180,15 @@ class OEMSecretsProvider implements InfoProviderInterface
// Splitting the values and units // Splitting the values and units
$parsedMin = $this->customSplitIntoValueAndUnit($rangeParts[0]); $parsedMin = $this->customSplitIntoValueAndUnit($rangeParts[0]);
$parsedMax = $this->customSplitIntoValueAndUnit($rangeParts[1]); $parsedMax = $this->customSplitIntoValueAndUnit($rangeParts[1]);
// Assigning the parsed values // Assigning the parsed values
$result['value_min'] = $parsedMin['value_typ']; $result['value_min'] = $parsedMin['value_typ'];
$result['value_max'] = $parsedMax['value_typ']; $result['value_max'] = $parsedMax['value_typ'];
// Determine the unit // Determine the unit
$result['unit'] = $parsedMax['unit'] ?? $parsedMin['unit']; $result['unit'] = $parsedMax['unit'] ?? $parsedMin['unit'];
} }
} elseif (str_contains($value, '@')) { } elseif (str_contains($value, '@')) {
// If we find "@", we treat it as additional textual information // If we find "@", we treat it as additional textual information
[$numericValue, $textValue] = explode('@', $value); [$numericValue, $textValue] = explode('@', $value);
@ -1264,9 +1264,9 @@ class OEMSecretsProvider implements InfoProviderInterface
* @param string $partNumber The part number to include in the URL. * @param string $partNumber The part number to include in the URL.
* @param string $oemInquiry The inquiry path for the OEMSecrets API, with a default value of 'compare/'. * @param string $oemInquiry The inquiry path for the OEMSecrets API, with a default value of 'compare/'.
* This parameter represents the specific API endpoint to query. * This parameter represents the specific API endpoint to query.
* *
* @return string The complete provider URL including the base provider URL, the inquiry path, and the part number. * @return string The complete provider URL including the base provider URL, the inquiry path, and the part number.
* *
* Example: * Example:
* If the base URL is "https://www.oemsecrets.com/", the inquiry path is "compare/", and the part number is "NE555", * If the base URL is "https://www.oemsecrets.com/", the inquiry path is "compare/", and the part number is "NE555",
* the resulting URL will be: "https://www.oemsecrets.com/compare/NE555" * the resulting URL will be: "https://www.oemsecrets.com/compare/NE555"
@ -1288,7 +1288,7 @@ class OEMSecretsProvider implements InfoProviderInterface
* 4. Optional sorting by completeness or manufacturer based on the sort criteria. * 4. Optional sorting by completeness or manufacturer based on the sort criteria.
* *
* The sorting criteria (`sort_criteria`) is an environment variable configured in the `.env.local` file: * The sorting criteria (`sort_criteria`) is an environment variable configured in the `.env.local` file:
* PROVIDER_OEMSECRETS_SORT_CRITERIA * PROVIDER_OEMSECRETS_SORT_CRITERIA
* It determines the final sorting phase: * It determines the final sorting phase:
* - 'C': Sort by completeness. * - 'C': Sort by completeness.
* - 'M': Sort by manufacturer. * - 'M': Sort by manufacturer.
@ -1333,7 +1333,7 @@ class OEMSecretsProvider implements InfoProviderInterface
$suffixA = substr($nameA, strlen($searchKeyword)); $suffixA = substr($nameA, strlen($searchKeyword));
$suffixB = substr($nameB, strlen($searchKeyword)); $suffixB = substr($nameB, strlen($searchKeyword));
$suffixComparison = strcasecmp($suffixA, $suffixB); $suffixComparison = strcasecmp($suffixA, $suffixB);
if ($suffixComparison !== 0) { if ($suffixComparison !== 0) {
return $suffixComparison; return $suffixComparison;
} }
@ -1366,7 +1366,7 @@ class OEMSecretsProvider implements InfoProviderInterface
// Calculate the completeness score for each object // Calculate the completeness score for each object
$completenessA = $this->calculateCompleteness($a); $completenessA = $this->calculateCompleteness($a);
$completenessB = $this->calculateCompleteness($b); $completenessB = $this->calculateCompleteness($b);
// Sort in descending order by completeness (higher score is better) // Sort in descending order by completeness (higher score is better)
return $completenessB - $completenessA; return $completenessB - $completenessA;
} }
@ -1418,7 +1418,7 @@ class OEMSecretsProvider implements InfoProviderInterface
+ $manufacturingStatusScore; + $manufacturingStatusScore;
} }
/** /**
* Generates a unique provider ID by concatenating the part number and manufacturer name, * Generates a unique provider ID by concatenating the part number and manufacturer name,
* separated by a pipe (`|`). The generated ID is typically used to uniquely identify * separated by a pipe (`|`). The generated ID is typically used to uniquely identify