AfterGetProductCollection plugin hassle with SearchResultApplier
- Get link
- X
- Other Apps
I wrote an AfterGetProductCollection plugin for Magento\CatalogSearch\Model\Advanced updating the resulting collection. I am using Elasticsearch and Magento Commerce. The problem is that Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier is not aware of the collection updates and applies the original search results product ids.
Ah, I see! You're working on a plugin to modify the product collection in Magento with Elasticsearch. To address the issue with the SearchResultApplier not being aware of the collection updates, you may need to extend the SearchResultApplier itself.
You can create a custom module and use dependency injection (DI) to override the original SearchResultApplier class. In your custom module's di.xml
file, you can add a preference to point to your new class that extends the original SearchResultApplier. This way, Magento will use your custom class instead of the original one.
Here's an example for your di.xml
file:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier" type="YourVendor\YourModule\Model\ResourceModel\Fulltext\Collection\CustomSearchResultApplier" />
</config>
In your new CustomSearchResultApplier
class, you can extend the original SearchResultApplier
and override the necessary method(s) to apply the search results based on your updated product collection.
Does this help you with the issue you're facing?
I know this, but how should we update the search collection for SearchResultApplier when we updated the search result collection with an AfterGetProductCollection plugin for Magento\CatalogSearch\Model\Advanced ?
I understand now. Since you're using an AfterGetProductCollection
plugin for Magento\CatalogSearch\Model\Advanced
, you need to update the search collection for SearchResultApplier
as well.
First, you should create a custom module, if you haven't already, and make sure your AfterGetProductCollection
plugin is working as expected.
Next, you'll need to create another plugin, this time targeting the Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier
. You'll want to use the aroundApply
method to modify the behavior of the original apply
method.
Here's an example of how your plugin class might look:
namespace YourVendor\YourModule\Plugin;
class SearchResultApplierPlugin
{
public function aroundApply(
\Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier $subject,
callable $proceed,
\Magento\Framework\Data\Collection\AbstractDb $collection
) {
// Your logic to update the search collection based on your modified product collection.
// You might need to store and retrieve the updated product collection from your AfterGetProductCollection plugin.
// Call the original apply method with the updated search collection.
$result = $proceed($collection);
return $result;
}
}
In your custom module's di.xml
file, you will need to add the plugin:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier">
<plugin name="your_vendor_your_module_search_result_applier_plugin" type="YourVendor\YourModule\Plugin\SearchResultApplierPlugin" sortOrder="10" />
</type>
</config>
This way, your custom SearchResultApplierPlugin
will be able to update the search collection based on the changes you made in your AfterGetProductCollection
plugin.
Does this approach make sense to you and help with your issue?
But the apply method from Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier using Magento\Framework\Api\Search\SearchResultInterface to apply pagination and sorting or ordering values. How do I resolve in this case ordering and pagination values?
I see, in that case, you'll have to modify the Magento\Framework\Api\Search\SearchResultInterface
instance that is being used by the SearchResultApplier
to apply the pagination and sorting values.
To achieve this, you can use the following approach:
In your
AfterGetProductCollection
plugin, store the updated product collection somewhere that can be accessed by yourSearchResultApplierPlugin
. You can use a custom helper class with a getter and a setter for this purpose.Create another plugin for the
Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier
class, targeting theapply
method, as mentioned in the previous response.In the
aroundApply
method of yourSearchResultApplierPlugin
, retrieve the updated product collection from the custom helper class.Now, create a new instance of
SearchResultInterface
using the Object Manager or Dependency Injection, and set the updated product collection as its items.Update the pagination and sorting values in your new
SearchResultInterface
instance based on the updated product collection.Finally, call the original
apply
method of theSearchResultApplier
using the newSearchResultInterface
instance with the updated product collection, pagination, and sorting values.
Here's an example of how your SearchResultApplierPlugin
class might look:
namespace YourVendor\YourModule\Plugin;
class SearchResultApplierPlugin
{
protected $helper;
public function __construct(
\YourVendor\YourModule\Helper\Data $helper
) {
$this->helper = $helper;
}
public function aroundApply(
\Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier $subject,
callable $proceed,
\Magento\Framework\Api\Search\SearchResultInterface $searchResult
) {
// Retrieve the updated product collection from your custom helper class.
$updatedProductCollection = $this->helper->getUpdatedProductCollection();
// Create a new SearchResultInterface instance and set the updated product collection as its items.
$newSearchResult = clone $searchResult;
$newSearchResult->setItems($updatedProductCollection->getItems());
// Update the pagination and sorting values based on the updated product collection.
// ...
// Call the original apply method with the new SearchResultInterface instance.
$result = $proceed($newSearchResult);
return $result;
}
}
This way, you should be able to resolve the ordering and pagination values based on your updated product collection.
Does this approach help you address your issue?
There is a problem, the apply method has no parameters so the aroundApply( \Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier $subject, callable $proceed, \Magento\Framework\Api\Search\SearchResultInterface $searchResult ) plugin will not work only if you declare as public function aroundApply( \Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier $subject, callable $proceed )
I apologize for the confusion. You're right, the apply
method doesn't have any parameters. In that case, we need to adjust the approach for the aroundApply
method in the SearchResultApplierPlugin
.
Here's an updated version of the SearchResultApplierPlugin
:
namespace YourVendor\YourModule\Plugin;
class SearchResultApplierPlugin
{
protected $helper;
public function __construct(
\YourVendor\YourModule\Helper\Data $helper
) {
$this->helper = $helper;
}
public function aroundApply(
\Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier $subject,
callable $proceed
) {
// Retrieve the updated product collection from your custom helper class.
$updatedProductCollection = $this->helper->getUpdatedProductCollection();
// Get the search result from the SearchResultApplier instance.
$searchResult = $subject->getSearchResult();
// Create a new SearchResultInterface instance and set the updated product collection as its items.
$newSearchResult = clone $searchResult;
$newSearchResult->setItems($updatedProductCollection->getItems());
// Update the pagination and sorting values based on the updated product collection.
// ...
// Set the new SearchResultInterface instance in the SearchResultApplier.
$subject->setSearchResult($newSearchResult);
// Call the original apply method.
$result = $proceed();
return $result;
}
}
With this adjusted aroundApply
method, we're getting the search result directly from the SearchResultApplier
instance and updating it with the new product collection, pagination, and sorting values before calling the original apply
method.
I hope this updated approach helps you with your issue. Please let me know if you have any questions or need further clarification.
How do I create in Helper/Data the setter and getter methods for the collection?
In your custom module, you can create a Helper/Data.php
file to store the setter and getter methods for the updated product collection. Here's an example of how your Helper/Data.php
file might look:
namespace YourVendor\YourModule\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
class Data extends AbstractHelper
{
protected $updatedProductCollection;
/**
* Set the updated product collection.
*
* @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection
* @return void
*/
public function setUpdatedProductCollection(\Magento\Catalog\Model\ResourceModel\Product\Collection $collection)
{
$this->updatedProductCollection = $collection;
}
/**
* Get the updated product collection.
*
* @return \Magento\Catalog\Model\ResourceModel\Product\Collection|null
*/
public function getUpdatedProductCollection()
{
return $this->updatedProductCollection;
}
}
In this helper class, we have two methods:
setUpdatedProductCollection
: This method accepts a\Magento\Catalog\Model\ResourceModel\Product\Collection
object as a parameter, and sets it as the value of the$updatedProductCollection
property.getUpdatedProductCollection
: This method returns the stored value of the$updatedProductCollection
property. If the property hasn't been set yet, it will returnnull
.
In your AfterGetProductCollection
plugin, you can use the setUpdatedProductCollection
method to store the updated product collection, and in your SearchResultApplierPlugin
, you can use the getUpdatedProductCollection
method to retrieve the stored collection.
Does this help you create the setter and getter methods for the updated product collection? Let me know if you need further clarification or have any questions.
The setter method is enough to store the the updated product collection in the helper?
Yes, the setUpdatedProductCollection
method in the helper is enough to store the updated product collection. By using this method, you'll be setting the value of the $updatedProductCollection
property in the helper class.
Here's an example of how to use the helper in your AfterGetProductCollection
plugin:
namespace YourVendor\YourModule\Plugin;
class AdvancedPlugin
{
protected $helper;
public function __construct(
\YourVendor\YourModule\Helper\Data $helper
) {
$this->helper = $helper;
}
public function afterGetProductCollection(
\Magento\CatalogSearch\Model\Advanced $subject,
\Magento\Catalog\Model\ResourceModel\Product\Collection $result
) {
// Your logic to update the product collection.
// ...
// Store the updated product collection in the helper.
$this->helper->setUpdatedProductCollection($result);
return $result;
}
}
Then, in your SearchResultApplierPlugin
, you can use the getUpdatedProductCollection
method to retrieve the stored updated product collection:
// Retrieve the updated product collection from your custom helper class.
$updatedProductCollection = $this->helper->getUpdatedProductCollection();
By using the helper's setter and getter methods, you can easily store and retrieve the updated product collection across your plugins.
Let me know if you have any questions or need further clarification.
There is a problem there is no getSearchResult or setSearchResult method in \Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier and also $searchResult is private
I apologize for the confusion. In this case, we'll need to adjust our approach again to work with the private $searchResult
property in the SearchResultApplier
class.
Since you can't access the $searchResult
property directly or through a getter/setter method, you can create a custom class that extends the SearchResultApplier
class and adds your desired functionality.
Create a custom class that extends
Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier
.Override the
apply
method in your custom class to update the search result with the updated product collection and pagination/sorting values.Use the
di.xml
file in your custom module to replace the originalSearchResultApplier
class with your custom class.
Here's an example of your custom SearchResultApplier
class:
namespace YourVendor\YourModule\Model\ResourceModel\Fulltext\Collection;
class CustomSearchResultApplier extends \Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier
{
protected $helper;
public function __construct(
\YourVendor\YourModule\Helper\Data $helper,
\Magento\Framework\Api\Search\SearchResultInterface $searchResult,
\Magento\Framework\Data\Collection\AbstractDb $collection
) {
$this->helper = $helper;
parent::__construct($searchResult, $collection);
}
public function apply()
{
// Retrieve the updated product collection from your custom helper class.
$updatedProductCollection = $this->helper->getUpdatedProductCollection();
// Update the search result with the updated product collection.
// ...
// Update the pagination and sorting values based on the updated product collection.
// ...
return parent::apply();
}
}
In your custom module's di.xml
file, add a preference to replace the original SearchResultApplier
class with your custom class:
- Get link
- X
- Other Apps
Comments
Post a Comment