Skip to content

Commit 296a7d8

Browse files
authored
Merge pull request #1736 from algolia/feat/MAGE-1258-rule-editor-categories
MAGE-1258 Rule editor friendly categories
2 parents 227e007 + 5458c3f commit 296a7d8

File tree

2 files changed

+210
-53
lines changed

2 files changed

+210
-53
lines changed

Service/Product/FacetBuilder.php

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public function __construct(
3434
{}
3535

3636
/**
37-
* @param int $storeId
37+
* Return the configuration to be used for the store product index `attributesForFaceting`
38+
* @param int $storeId - The store ID for the index to be configured
3839
* @return string[]
3940
* @throws LocalizedException
4041
* @throws NoSuchEntityException
@@ -45,12 +46,13 @@ public function getAttributesForFaceting(int $storeId): array
4546
function($facet) {
4647
return $this->decorateAttributeForFaceting($facet);
4748
},
48-
$this->getRawFacets($storeId)
49+
$this->addMerchandisingFacets($storeId, $this->getRawFacets($storeId))
4950
);
5051
}
5152

5253
/**
53-
* @param int $storeId
54+
* Return the configuration to be used for the store product index `renderingContent`
55+
* @param int $storeId - The store ID for the index to be configured
5456
* @return array<string, array>|null
5557
* @throws LocalizedException
5658
* @throws NoSuchEntityException
@@ -73,6 +75,8 @@ public function getRenderingContent(int $storeId): ?array
7375
}
7476

7577
/**
78+
* For an array of facet data, return an array of attribute names only
79+
*
7680
* @param array<array<string, mixed>> $facets
7781
* @return string[]
7882
*/
@@ -87,8 +91,9 @@ function($facet) {
8791
}
8892

8993
/**
94+
* Format the facet data to be : renderingContent > facetOrdering > values
9095
* @param string[] $attributes
91-
* @return array<string, array>
96+
* @return array<string, array> - Array key is the attribute name and the value is an object containing a `sortRemainingBy` value
9297
*/
9398
protected function getRenderingContentValues(array $attributes): array
9499
{
@@ -99,6 +104,7 @@ protected function getRenderingContentValues(array $attributes): array
99104
}
100105

101106
/**
107+
* Take raw facet (common) attributes and convert to include attributes specifically needed for `renderingContent`
102108
* @param string[] $facets
103109
* @return string[]
104110
*/
@@ -107,7 +113,7 @@ protected function getRenderingContentAttributes(array $facets): array
107113
return array_map(
108114
function(string $attribute) {
109115
if ($attribute === self::FACET_ATTRIBUTE_CATEGORIES) {
110-
$attribute = self::FACET_ATTRIBUTE_CATEGORIES . '.level0';
116+
$attribute = $this->getCategoryAttributeNameForRenderingContent();
111117
}
112118
return $attribute;
113119
},
@@ -116,9 +122,23 @@ function(string $attribute) {
116122
}
117123

118124
/**
125+
* `renderingContent` cannot utilize the entire categories object but instead must reference a scalar value
126+
* Obtaining the root level of the category data will enable it to become selectable in the Algolia Dashboard
127+
* for "Facet Display" and "Order facets" within merchandising rules
128+
*
129+
* @return string
130+
*/
131+
protected function getCategoryAttributeNameForRenderingContent(): string
132+
{
133+
return self::FACET_ATTRIBUTE_CATEGORIES . '.level0';
134+
}
135+
136+
/**
137+
* Return an associative array for an attribute that mimics the minimum structure used by the Magento configuration
138+
*
119139
* @param string $attribute
120140
* @param bool $searchable
121-
* @return array<string, string>
141+
* @return array{attribute: string, searchable: string}
122142
*/
123143
protected function getRawFacet(string $attribute, bool $searchable = false): array
124144
{
@@ -129,7 +149,8 @@ protected function getRawFacet(string $attribute, bool $searchable = false): arr
129149
}
130150

131151
/**
132-
* Generates common data to be used for both attributesForFaceting and renderingContent
152+
* Generates common data to be used for both `attributesForFaceting` and `renderingContent`
153+
*
133154
* @return array<array<string, mixed>>
134155
* @throws NoSuchEntityException
135156
* @throws LocalizedException
@@ -155,26 +176,57 @@ function(string $attribute) {
155176
}
156177
}
157178

158-
$this->facets[$storeId] = $this->addCategoryFacets($storeId, $rawFacets);
179+
$this->facets[$storeId] = $this->assertCategoryFacet($storeId, $rawFacets);
180+
159181
return $this->facets[$storeId];
160182
}
161183

162184
/**
185+
* Does a given array of facets include a category facet?
186+
*
187+
* @param array<array<string, mixed>> $facets
188+
* @return bool
189+
*/
190+
protected function hasCategoryFacet(array $facets): bool
191+
{
192+
return !!array_filter($facets, function($facet) {
193+
return $facet['attribute'] === self::FACET_ATTRIBUTE_CATEGORIES;
194+
});
195+
}
196+
197+
/**
198+
* Applies the category facet if not manually configured but necessary for category functionality
199+
* (The presence of the category facet drives logic for `attributesForFaceting` and `renderingContent`)
200+
*
163201
* @param int $storeId
164202
* @param array<array<string, mixed>> $facets
165203
* @return array<array<string, mixed>>
166204
*/
167-
protected function addCategoryFacets(int $storeId, array $facets): array
205+
protected function assertCategoryFacet(int $storeId, array $facets): array
168206
{
169207
if ($this->configHelper->replaceCategories($storeId)
170-
&& !array_filter($facets, function($facet) {
171-
return $facet['attribute'] === self::FACET_ATTRIBUTE_CATEGORIES;
172-
})
208+
&& !$this->hasCategoryFacet($facets)
173209
) {
174210
$facets[] = $this->getRawFacet(self::FACET_ATTRIBUTE_CATEGORIES);
175211
}
176212

177-
// Added for legacy merchandising features
213+
return $facets;
214+
}
215+
216+
/**
217+
* Add merchandising facets as needed for `attributesForFaceting`
218+
*
219+
* @param int $storeId
220+
* @param array<array<string, mixed>> $facets
221+
* @return array|string[]
222+
*/
223+
protected function addMerchandisingFacets(int $storeId, array $facets): array
224+
{
225+
if ($this->hasCategoryFacet($facets)) {
226+
$facets[] = $this->getRawFacet($this->getCategoryAttributeNameForRenderingContent());
227+
}
228+
229+
// Used for legacy merchandising features - always required!
178230
$facets[] = $this->getRawFacet(self::FACET_ATTRIBUTES_CATEGORY_ID);
179231

180232
if ($this->configHelper->isVisualMerchEnabled($storeId)) {
@@ -186,6 +238,8 @@ protected function addCategoryFacets(int $storeId, array $facets): array
186238
}
187239

188240
/**
241+
* Get an array of pricing attribute names based on currency and customer group configuration
242+
*
189243
* @param int $storeId
190244
* @return string[]
191245
* @throws NoSuchEntityException
@@ -204,6 +258,8 @@ protected function getPricingAttributes(int $storeId): array
204258
}
205259

206260
/**
261+
* Get an array of pricing attribute names based on customer group configuration
262+
*
207263
* @param int $storeId
208264
* @param string $currencyCode
209265
* @return string[]
@@ -229,6 +285,8 @@ protected function getGroupPricingAttributes(int $storeId, string $currencyCode)
229285

230286

231287
/**
288+
* Format the `attributesForFaceting` values based on modifiers defined at:
289+
* https://www.algolia.com/doc/api-reference/api-parameters/attributesForFaceting/#modifiers
232290
* @param array<string, string|int> $facet
233291
* @return string
234292
*/

0 commit comments

Comments
 (0)