Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .phpunit.cache/test-results
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":1,"defects":[],"times":{"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testConstructorWithEmptyLocales":0.004,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testGetSupportedLocales":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testGetDefaultLocale":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformWithInvalidData":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformWithMissingProductsArray":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformSimpleProduct":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithMultipleLocales":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithVariants":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithMissingRequiredFields":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithMissingSku":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformVariantWithoutRemoteId":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testCategoryFlattening":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testEmptyCategories":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testImageUrlTransformation":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testSingleLocaleAdapter":0.001,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testFallbackToFirstAvailableValue":0}}
{"version":1,"defects":{"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithVariants":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testSingleLocaleAdapter":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testFallbackToFirstAvailableValue":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithFeaturesOnlyInOneLocale":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformSimpleProduct":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithMultipleLocales":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformVariantWithoutRemoteId":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testCategoryFlattening":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testEmptyCategories":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testMultiLangName":7,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testConstructorWithEmptyLocales":7},"times":{"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testConstructorWithEmptyLocales":0.01,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testGetSupportedLocales":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testGetDefaultLocale":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformWithInvalidData":0.004,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformWithMissingProductsArray":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformSimpleProduct":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithMultipleLocales":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithVariants":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithMissingRequiredFields":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithMissingSku":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformVariantWithoutRemoteId":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testCategoryFlattening":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testEmptyCategories":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testImageUrlTransformation":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testSingleLocaleAdapter":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testFallbackToFirstAvailableValue":0,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithLocalizedFeatures":0.001,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testTransformProductWithFeaturesOnlyInOneLocale":0.007,"BradSearch\\SyncSdk\\Tests\\Adapters\\PrestaShopAdapterTest::testMultiLangName":0}}
4 changes: 1 addition & 3 deletions examples/prestashop-sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
$syncSdk = new SynchronizationApiSdk($config, $fieldConfiguration);

// Initialize PrestaShop adapter with supported locales
$prestaShopAdapter = new PrestaShopAdapter(['en-US', 'lt-LT']);
$prestaShopAdapter = new PrestaShopAdapter();

// Index name
$indexName = 'prestashop-products-example';
Expand Down Expand Up @@ -282,8 +282,6 @@

// Step 8: Show adapter configuration
echo "\nPrestaShop Adapter Configuration:\n";
echo "Supported Locales: " . implode(', ', $prestaShopAdapter->getSupportedLocales()) . "\n";
echo "Default Locale: " . $prestaShopAdapter->getDefaultLocale() . "\n";

echo "\nField Configuration Used:\n";
$fields = $syncSdk->getFieldConfiguration();
Expand Down
165 changes: 57 additions & 108 deletions src/Adapters/PrestaShopAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,8 @@

class PrestaShopAdapter
{
private array $supportedLocales;
private string $defaultLocale;

/**
* @param array<string> $supportedLocales List of supported locales (first one becomes default)
*/
public function __construct(array $supportedLocales = ['en-US'])
public function __construct()
{
if (empty($supportedLocales)) {
throw new ValidationException('At least one locale must be specified');
}

$this->supportedLocales = $supportedLocales;
$this->defaultLocale = $supportedLocales[0];
}

/**
Expand Down Expand Up @@ -65,7 +53,7 @@ private function transformProduct(array $product): array
}

// Handle categories (flatten all levels)
$result['categories'] = $this->extractCategories($product);
$this->extractCategories($result, $product);

// Handle image URLs
if (isset($product['imageUrl'])) {
Expand All @@ -74,53 +62,56 @@ private function transformProduct(array $product): array

// Handle product URL
if (isset($product['productUrl'])) {
$this->addLocalizedField($result, 'productUrl', $product['productUrl']);
foreach ($product['productUrl'] as $url) {
$result['productUrl'] = $url;
break;
}
}

// Handle variants
if (isset($product['variants']) && is_array($product['variants'])) {
$result['variants'] = $this->transformVariants($product['variants']);
$this->transformVariants($result, $product['variants']);
}

// Handle features
if (isset($product['features']) && is_array($product['features'])) {
$result['features'] = $this->transformFeatures($product['features']);
$this->transformFeatures($result, $product['features']);
}

return $result;
}

private function transformFeatures(array $features): array
private function transformFeatures(array &$result, array $features): void
{
$transformedFeatures = [];
$featuresByLocale = [];

foreach ($features as $feature) {
// Extract the feature name (key) from localized names
$featureName = $this->extractDefaultLocaleValue($feature['localizedNames'] ?? []);
if (!$featureName) {
if (!isset($feature['localizedNames']) || !isset($feature['localizedValues'])) {
continue;
}

// Extract the feature value from localized values
$featureValue = $this->extractDefaultLocaleValue($feature['localizedValues'] ?? []);
if (!$featureValue) {
continue;
foreach ($feature['localizedNames'] as $locale => $name) {
$featuresByLocale[$locale][] = [
'name' => $name,
'value' => $feature['localizedValues'][$locale]
];
}

// Create the feature structure: {featureName: {name: featureName, value: featureValue}}
$transformedFeatures[$featureName] = [
'name' => $featureName,
'value' => $featureValue
];
}

return $transformedFeatures;
foreach ($featuresByLocale as $locale => $features) {
if ($locale === 'en-US') {
$result['features'] = $features;
} else {
$result["features_{$locale}"] = $features;
}
}
}

/**
* Transform PrestaShop variants to BradSearch format
*/
private function transformVariants(array $variants): array
private function transformVariants(array &$result, array $variants): void
{
$transformedVariants = [];

Expand All @@ -132,14 +123,19 @@ private function transformVariants(array $variants): array
$transformedVariant = [
'id' => (string) $variant['remoteId'],
'sku' => $variant['sku'] ?? '',
'url' => $this->extractDefaultLocaleValue($variant['productUrl']['localizedValues'] ?? []),
'url' => $this->extractFirstLocaleValue($variant['productUrl']['localizedValues'] ?? []),
'attributes' => $this->transformVariantAttributes($variant['attributes'] ?? [])
];

$transformedVariants[] = $transformedVariant;
}

return $transformedVariants;
$result['variants'] = $transformedVariants;
}

private function extractFirstLocaleValue(array $localizedValues): string
{
return array_values($localizedValues)[0] ?? '';
}

/**
Expand All @@ -150,13 +146,18 @@ private function transformVariantAttributes(array $attributes): array
$transformedAttributes = [];

foreach ($attributes as $attributeName => $attributeData) {
$attributeValue = $this->extractDefaultLocaleValue($attributeData['localizedValues'] ?? []);

if ($attributeValue !== null) {
$transformedAttributes[$attributeName] = [
'name' => $attributeName,
'value' => $attributeValue
];
foreach ($attributeData['localizedValues'] as $locale => $value) {
if ($locale === 'en-US') {
$transformedAttributes[strtolower($attributeName)] = [
'name' => strtolower($attributeName),
'value' => $value
];
} else {
$transformedAttributes[strtolower($attributeName) . '_' . $locale] = [
'name' => strtolower($attributeName),
'value' => $value
];
}
}
}

Expand All @@ -166,12 +167,11 @@ private function transformVariantAttributes(array $attributes): array
/**
* Extract categories from all levels and flatten them
*/
private function extractCategories(array $product): array
private function extractCategories(array &$result, array $product): void
{
$categories = [];

if (!isset($product['categories'])) {
return $categories;
$result['categories'] = [];
return;
}

// Process all category levels (lvl2, lvl3, lvl4, etc.)
Expand All @@ -182,15 +182,16 @@ private function extractCategories(array $product): array

foreach ($levelCategories as $category) {
if (isset($category['localizedValues']['path'])) {
$path = $this->extractDefaultLocaleValue($category['localizedValues']['path']);
if ($path && !in_array($path, $categories, true)) {
$categories[] = $path;
foreach ($category['localizedValues']['path'] as $locale => $path) {
if ($locale === 'en-US') {
$result['categories'][] = $path;
} else {
$result["categories_{$locale}"][] = $path;
}
}
}
}
}

return $categories;
}

/**
Expand Down Expand Up @@ -224,49 +225,15 @@ private function addLocalizedField(array &$result, string $fieldName, array $loc
return;
}

// Extract default locale value (first supported locale found)
$defaultValue = $this->extractDefaultLocaleValue($localizedValues);
if ($defaultValue !== null) {
$result[$fieldName] = $defaultValue;
}

// Add additional locales with suffixes
foreach ($this->supportedLocales as $index => $locale) {
if ($index === 0) {
continue; // Skip default locale (already added above)
}

if (isset($localizedValues[$locale])) {
$result["{$fieldName}_{$locale}"] = $localizedValues[$locale];
foreach ($localizedValues as $locale => $value) {
if ($locale === 'en-US') {
$result[$fieldName] = $value;
} else {
$result["{$fieldName}_{$locale}"] = $value;
}
}
}

/**
* Extract value for the default locale
*/
private function extractDefaultLocaleValue(array $localizedValues): ?string
{
if (empty($localizedValues)) {
return null;
}

// Try to find value for default locale first
if (isset($localizedValues[$this->defaultLocale])) {
return $localizedValues[$this->defaultLocale];
}

// Try other supported locales
foreach ($this->supportedLocales as $locale) {
if (isset($localizedValues[$locale])) {
return $localizedValues[$locale];
}
}

// Fallback to first available value
return array_values($localizedValues)[0] ?? null;
}

/**
* Get required field with validation
*/
Expand All @@ -278,22 +245,4 @@ private function getRequiredField(array $data, string $field): string

return (string) $data[$field];
}

/**
* Get supported locales
*
* @return array<string>
*/
public function getSupportedLocales(): array
{
return $this->supportedLocales;
}

/**
* Get default locale
*/
public function getDefaultLocale(): string
{
return $this->defaultLocale;
}
}
32 changes: 6 additions & 26 deletions tests/Adapters/PrestaShopAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,7 @@ class PrestaShopAdapterTest extends TestCase

protected function setUp(): void
{
$this->adapter = new PrestaShopAdapter(['en-US', 'lt-LT']);
}

public function testConstructorWithEmptyLocales(): void
{
$this->expectException(ValidationException::class);
$this->expectExceptionMessage('At least one locale must be specified');
new PrestaShopAdapter([]);
}

public function testGetSupportedLocales(): void
{
$this->assertEquals(['en-US', 'lt-LT'], $this->adapter->getSupportedLocales());
}

public function testGetDefaultLocale(): void
{
$this->assertEquals('en-US', $this->adapter->getDefaultLocale());
$this->adapter = new PrestaShopAdapter();
}

public function testTransformWithInvalidData(): void
Expand Down Expand Up @@ -167,7 +150,6 @@ public function testTransformProductWithMultipleLocales(): void
// Additional locale fields (with suffix)
$this->assertEquals('Sportiniai batai Multi', $product['name_lt-LT']);
$this->assertEquals('Springa LT', $product['brand_lt-LT']);
$this->assertEquals('http://prestashop/lt/sportiniai-batai.html', $product['productUrl_lt-LT']);
}

public function testTransformProductWithVariants(): void
Expand Down Expand Up @@ -462,7 +444,7 @@ public function testImageUrlTransformation(): void

public function testSingleLocaleAdapter(): void
{
$adapter = new PrestaShopAdapter(['lt-LT']);
$adapter = new PrestaShopAdapter();

$prestaShopData = [
'products' => [
Expand All @@ -482,15 +464,12 @@ public function testSingleLocaleAdapter(): void
$result = $adapter->transform($prestaShopData);
$product = $result[0];

// Should use lt-LT as default since it's the only supported locale
$this->assertEquals('Lithuanian Name', $product['name']);
// Should not have any suffixed fields since there's only one locale
$this->assertArrayNotHasKey('name_lt-LT', $product);
$this->assertEquals('Lithuanian Name', $product['name_lt-LT']);
}

public function testFallbackToFirstAvailableValue(): void
public function testMultiLangName(): void
{
$adapter = new PrestaShopAdapter(['fr-FR', 'de-DE']); // Locales not in data
$adapter = new PrestaShopAdapter();

$prestaShopData = [
'products' => [
Expand All @@ -512,5 +491,6 @@ public function testFallbackToFirstAvailableValue(): void

// Should fallback to first available value (en-US)
$this->assertEquals('English Name', $product['name']);
$this->assertEquals('Lithuanian Name', $product['name_lt-LT']);
}
}