diff --git a/config/rapidez/indexer.php b/config/rapidez/indexer.php index 517991e66..e0d6efcab 100644 --- a/config/rapidez/indexer.php +++ b/config/rapidez/indexer.php @@ -1,22 +1,13 @@ [2, 3, 4], - - // Additional searchable attributes with the search weight. - 'searchable' => [ - // 'attribute' => 4.0, - ], - - // From Magento only "Yes/No, Dropdown, Multiple Select and Price" attribute types - // can be configured as filter. If you'd like to have a filter for an attribute - // with, for example, the type of "Text", you can specify the attribute_code here. - 'additional_filters' => [ - // eav_attribute attribute_code. e.g. brand - ], ]; diff --git a/config/rapidez/searchkit.php b/config/rapidez/searchkit.php new file mode 100644 index 000000000..ffd36e1f2 --- /dev/null +++ b/config/rapidez/searchkit.php @@ -0,0 +1,56 @@ + [ + // 'name', + ], + + // Attributes that are used to search the results. + // This will be merged with the searchable + // attributes configured in Magento. + 'search_attributes' => [ + // ['field' => 'attribute_code', 'weight' => 4.0], + ], + + // Attributes that are returned in the search result response. + // Don't want to keep track of this? An empty array will + // return all attributes, but that's not recommended! + 'result_attributes' => [ + 'entity_id', + 'name', + 'sku', + 'price', + 'special_price', + 'image', + 'images', + 'url', + 'thumbnail', + 'in_stock', + 'children', + 'super_*', + 'reviews_count', + 'reviews_score', + ], + + // Attributes that are used to create facets. + // From Magento only "Yes/No, Dropdown, Multiple Select and Price" attribute types + // can be configured as filter. If you'd like to have a filter for an attribute + // with, for example, the type of "Text", you can specify the attribute_code here. + 'facet_attributes' => [ + // ['attribute' => 'brand', 'field' => 'brand.keyword', 'type' => 'string'], + ], + + // Attributes that are used to create filters. + // TODO: Do we really need this? With ReactiveSearch + // we didn't need to keep a list to filter. + 'filter_attributes' => [ + ['attribute' => 'entity_id', 'field' => 'entity_id', 'type' => 'numeric'], + ['attribute' => 'category_ids', 'field' => 'category_ids', 'type' => 'numeric'], + ['attribute' => 'visibility', 'field' => 'visibility', 'type' => 'numeric'], + ], + + // TODO: Sorting... + // 'sorting' => [] +]; diff --git a/resources/js/components/Listing/Listing.vue b/resources/js/components/Listing/Listing.vue index 2d376ae86..2251a4ec9 100644 --- a/resources/js/components/Listing/Listing.vue +++ b/resources/js/components/Listing/Listing.vue @@ -16,6 +16,8 @@ import useAttributes from '../../stores/useAttributes.js' export default { props: { // TODO: Do we still use/need this? + // Maybe transform it to a callback + // so the items can be manipulated? additionalFilters: { type: Array, default: () => [], @@ -94,25 +96,26 @@ export default { password: url.password, }, }, - search_settings: { - // Are we using this? In the autocomplete maybe? - // highlight_attributes: ['title'], - - search_attributes: Object.entries(config.searchable).map(([field, weight]) => ({ field, weight })), - // We could make the response smaller with this - // result_attributes: ['title', 'actors', 'poster', 'plot'], + // TODO: Maybe just do: search_settings: config.searchkit + // so it's possible to add anything to the PHP config + // and that will appear here? + search_settings: { + highlight_attributes: config.searchkit.highlight_attributes, + search_attributes: config.searchkit.search_attributes, + result_attributes: config.searchkit.result_attributes, + // TODO: For consistency maybe make it possible to do this: + // facet_attributes: config.searchkit.facet_attributes, facet_attributes: this.facets, - // TODO: Do we really need this? With ReactiveSearch - // we didn't need to keep a list to filter. - filter_attributes: [ - { attribute: 'entity_id', field: 'entity_id', type: 'numeric' }, - { attribute: 'category_ids', field: 'category_ids', type: 'numeric' }, - { attribute: 'visibility', field: 'visibility', type: 'numeric' }, - ], + filter_attributes: config.searchkit.filter_attributes, + // TODO: Let's also change this to a PHP config. + // So we start there and that will be merged + // with the Magento configured attributes + // and lastly from a prop it's possible + // to manipulate it from a callback? sorting: this.sortOptions.reduce((acc, item) => { acc[item.key] = { field: item.field, @@ -128,6 +131,9 @@ export default { return searchkit }, + // TODO: Maybe move this completely to PHP? + // Any drawbacks? A window.config that + // becomes to big? Is that an issue? filters: function () { return Object.values(this.attributes) .filter((attribute) => attribute.filter) diff --git a/src/Http/ViewComposers/ConfigComposer.php b/src/Http/ViewComposers/ConfigComposer.php index 5abbb2086..0f57a507c 100644 --- a/src/Http/ViewComposers/ConfigComposer.php +++ b/src/Http/ViewComposers/ConfigComposer.php @@ -10,13 +10,26 @@ use Illuminate\View\View; use Rapidez\Core\Facades\Rapidez; +// TODO: Can we improve anything in this file? +// It doesn't feel very clean currently. class ConfigComposer { public function compose(View $view) { + $this + ->exposeGraphqlQueries() + ->configureSearchkit(); + $exposedFrontendConfigValues = Arr::only( - array_merge_recursive(config('rapidez'), config('rapidez.frontend')), - array_merge(config('rapidez.frontend.exposed'), ['store_code', 'index']) + array_merge_recursive( + config('rapidez'), + config('rapidez.frontend'), + config('rapidez.searchkit'), + ), + array_merge( + config('rapidez.frontend.exposed'), + ['store_code', 'index', 'searchkit'], + ), ); Config::set('frontend', array_merge( @@ -25,37 +38,11 @@ public function compose(View $view) $this->getConfig() )); - Config::set('frontend.queries', [ - 'customer' => view('rapidez::customer.queries.customer')->renderOneliner(), - 'setGuestEmailOnCart' => view('rapidez::checkout.queries.setGuestEmailOnCart')->renderOneliner(), - 'setNewShippingAddressesOnCart' => view('rapidez::checkout.queries.setNewShippingAddressesOnCart')->renderOneliner(), - 'setExistingShippingAddressesOnCart' => view('rapidez::checkout.queries.setExistingShippingAddressesOnCart')->renderOneliner(), - 'setNewBillingAddressOnCart' => view('rapidez::checkout.queries.setNewBillingAddressOnCart')->renderOneliner(), - 'setExistingBillingAddressOnCart' => view('rapidez::checkout.queries.setExistingBillingAddressOnCart')->renderOneliner(), - 'setShippingMethodsOnCart' => view('rapidez::checkout.queries.setShippingMethodsOnCart')->renderOneliner(), - 'setPaymentMethodOnCart' => view('rapidez::checkout.queries.setPaymentMethodOnCart')->renderOneliner(), - 'placeOrder' => view('rapidez::checkout.queries.placeOrder')->renderOneliner(), - ]); - - Config::set('frontend.fragments', [ - 'cart' => view('rapidez::cart.queries.fragments.cart')->renderOneliner(), - 'order' => view('rapidez::checkout.queries.fragments.order')->renderOneliner(), - 'orderV2' => view('rapidez::checkout.queries.fragments.orderV2')->renderOneliner(), - ]); - Event::dispatch('rapidez:frontend-config-composed'); } public function getConfig(): array { - $attributeModel = config('rapidez.models.attribute'); - $searchableAttributes = Arr::pluck( - $attributeModel::getCachedWhere(fn ($attribute) => $attribute['search'] && in_array($attribute['type'], ['text', 'varchar', 'static']) - ), - 'search_weight', - 'code' - ); - return [ 'locale' => Rapidez::config('general/locale/code', 'en_US'), 'default_country' => Rapidez::config('general/country/default', 'NL'), @@ -65,7 +52,6 @@ public function getConfig(): array 'show_swatches' => (bool) Rapidez::config('catalog/frontend/show_swatches_in_product_list'), 'translations' => __('rapidez::frontend'), 'recaptcha' => Rapidez::config('recaptcha_frontend/type_recaptcha_v3/public_key', null, true), - 'searchable' => array_merge($searchableAttributes, config('rapidez.indexer.searchable')), 'show_customer_address_fields' => $this->getCustomerAddressFields(), 'street_lines' => Rapidez::config('customer/address/street_lines', 2), 'show_tax' => (bool) Rapidez::config('tax/display/type', 1), @@ -94,4 +80,60 @@ public function getCustomerAddressFields(): array 'fax' => Rapidez::config('customer/address/fax_show', 'opt'), ]; } + + public function exposeGraphqlQueries(): self + { + $checkoutQueries = [ + 'setGuestEmailOnCart', + 'setNewShippingAddressesOnCart', + 'setExistingShippingAddressesOnCart', + 'setNewBillingAddressOnCart', + 'setExistingBillingAddressOnCart', + 'setShippingMethodsOnCart', + 'setPaymentMethodOnCart', + 'placeOrder', + ]; + + // TODO: Maybe limit this to just the checkout pages? + foreach ($checkoutQueries as $checkoutQuery) { + Config::set( + 'frontend.queries.'.$checkoutQuery, + view('rapidez::checkout.queries.'.$checkoutQuery)->renderOneliner() + ); + } + + Config::set( + 'frontend.queries.customer', + view('rapidez::customer.queries.customer')->renderOneliner() + ); + + Config::set('frontend.fragments', [ + 'cart' => view('rapidez::cart.queries.fragments.cart')->renderOneliner(), + 'order' => view('rapidez::checkout.queries.fragments.order')->renderOneliner(), + 'orderV2' => view('rapidez::checkout.queries.fragments.orderV2')->renderOneliner(), + ]); + + return $this; + } + + public function configureSearchkit(): self + { + $attributeModel = config('rapidez.models.attribute'); + + // Get all searchable attributes from Magento. + $searchableAttributes = $attributeModel::getCachedWhere(function ($attribute) { + return $attribute['search'] + && in_array($attribute['type'], ['text', 'varchar', 'static']); + }); + + // Map and merge them with the config. + $searchableAttributes = collect($searchableAttributes)->map(fn ($attribute) => [ + 'field' => $attribute['code'], + 'weight' => $attribute['search_weight'], + ])->merge(config('rapidez.searchkit.search_attributes'))->values()->toArray(); + + Config::set('rapidez.searchkit.search_attributes', $searchableAttributes); + + return $this; + } } diff --git a/src/Models/Attribute.php b/src/Models/Attribute.php index 532d04a8a..2d5b19733 100644 --- a/src/Models/Attribute.php +++ b/src/Models/Attribute.php @@ -20,6 +20,7 @@ protected static function booting() protected function filter(): CastsAttribute { + // TODO: Double check; this config has been (re)moved. return CastsAttribute::make( get: fn ($value) => $value || in_array($this->code, config('rapidez.indexer.additional_filters')), )->shouldCache(); diff --git a/src/RapidezServiceProvider.php b/src/RapidezServiceProvider.php index 428bb3e99..7241409b5 100644 --- a/src/RapidezServiceProvider.php +++ b/src/RapidezServiceProvider.php @@ -48,6 +48,7 @@ class RapidezServiceProvider extends ServiceProvider 'jwt', 'models', 'routing', + 'searchkit', 'system', ];