From adf0740b014abec1fb11b14c7a628689bd7a6675 Mon Sep 17 00:00:00 2001 From: Damien Couchez Date: Wed, 30 Oct 2019 16:57:05 +0100 Subject: [PATCH] Bump to 1.12.1 (#909) --- .circleci/config.yml | 65 +-- .styleci.yml | 3 - Block/Adminhtml/BaseAdminTemplate.php | 30 -- Block/LandingPage.php | 3 + .../Navigation/Renderer/CategoryRenderer.php | 3 + Block/Navigation/Renderer/DefaultRenderer.php | 3 + Block/Navigation/Renderer/SliderRenderer.php | 3 + CHANGELOG.md | 51 +++ Controller/Adminhtml/Analytics/Update.php | 4 +- .../Adminhtml/Landingpage/Duplicate.php | 2 - Controller/Adminhtml/Query/Save.php | 47 ++- Controller/Adminhtml/Queue/AbstractAction.php | 4 +- Factory/ViewModelFactory.php | 64 --- Helper/ConfigHelper.php | 55 ++- Helper/Data.php | 7 +- Helper/Entity/AdditionalSectionHelper.php | 8 +- Helper/Entity/CategoryHelper.php | 2 +- Helper/Entity/PageHelper.php | 26 +- .../PriceManager/ProductWithoutChildren.php | 7 +- Helper/Entity/ProductHelper.php | 61 +-- Helper/Entity/SuggestionHelper.php | 11 +- Helper/Image.php | 32 +- Helper/ProxyHelper.php | 24 +- Helper/SupportHelper.php | 4 + Model/ConfigurationTracker.php | 128 ++++++ Model/ExtensionNotification.php | 141 +++++++ Model/Job.php | 1 + Model/Layer/Filter/Decimal.php | 8 +- Model/Layer/Filter/Item/Attribute.php | 9 + Model/Layer/Filter/Price.php | 7 +- Model/Observer/SaveSettings.php | 21 +- Model/Source/Facets.php | 2 +- Plugin/BackendFilterRendererPlugin.php | 11 +- README.md | 8 +- Setup/UpgradeSchema.php | 42 +- Test/Integration/CategoriesIndexingTest.php | 5 +- Test/Integration/ConfigTest.php | 4 +- Test/Integration/PagesIndexingTest.php | 10 +- Test/Integration/ProductsIndexingTest.php | 7 +- Test/Integration/TestCase.php | 5 + ViewModel/Adminhtml/Analytics/Form.php | 2 +- ViewModel/Adminhtml/Analytics/Overview.php | 9 +- ViewModel/Adminhtml/Common.php | 69 +++- .../Adminhtml/Landingpage/Suggestions.php | 2 +- ViewModel/Adminhtml/Merchandising/Page.php | 2 +- ViewModel/Adminhtml/Query/Suggestions.php | 2 +- ViewModel/Adminhtml/Support/Contact.php | 2 +- ViewModel/Adminhtml/Support/Overview.php | 12 +- composer.json | 9 +- etc/adminhtml/system.xml | 4 +- etc/di.xml | 5 + etc/module.xml | 21 +- etc/mview.xml | 1 - phpstan.neon | 15 +- .../algolia_algoliasearch_analytics_index.xml | 12 +- ...lgolia_algoliasearch_landingpage_index.xml | 10 +- ...olia_algoliasearch_merchandising_index.xml | 9 +- .../algolia_algoliasearch_query_index.xml | 10 +- .../algolia_algoliasearch_support_contact.xml | 6 +- .../algolia_algoliasearch_support_index.xml | 11 +- view/adminhtml/layout/default.xml | 7 +- view/adminhtml/requirejs-config.js | 6 +- view/adminhtml/templates/analytics/form.phtml | 2 +- .../templates/analytics/overview.phtml | 6 +- view/adminhtml/templates/common.phtml | 53 ++- .../templates/landingpage/access_denied.phtml | 2 +- .../templates/landingpage/suggestions.phtml | 4 +- .../templates/merchandising/page.phtml | 2 +- .../templates/query/access_denied.phtml | 2 +- .../templates/query/edit/merchandising.phtml | 11 +- .../templates/query/suggestions.phtml | 6 +- .../adminhtml/templates/support/contact.phtml | 2 +- .../templates/support/overview.phtml | 4 +- view/adminhtml/templates/tracking.phtml | 372 ++++++++++++++++++ view/adminhtml/templates/ui/upsell-plan.phtml | 2 +- view/adminhtml/web/js/support.js | 12 +- .../templates/autocomplete/category.phtml | 2 +- .../templates/autocomplete/product.phtml | 2 +- view/frontend/templates/instant/hit.phtml | 2 +- view/frontend/web/internals/common.js | 2 +- 80 files changed, 1325 insertions(+), 317 deletions(-) delete mode 100644 Block/Adminhtml/BaseAdminTemplate.php delete mode 100644 Factory/ViewModelFactory.php create mode 100644 Model/ConfigurationTracker.php create mode 100755 Model/ExtensionNotification.php create mode 100644 view/adminhtml/templates/tracking.phtml diff --git a/.circleci/config.yml b/.circleci/config.yml index 8f33d1cb4..309338d22 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -64,28 +64,47 @@ jobs: docker: - image: algolia/magento2-circleci:2.3.0 - "phpcompatibility": - docker: # run the steps with Docker with PHP 7.2 - - image: circleci/php:7.2 - steps: - - checkout - - run: sudo composer self-update - - run: composer config http-basic.repo.magento.com ${MAGENTO_AUTH_USERNAME} ${MAGENTO_AUTH_PASSWORD} - - restore_cache: - keys: - - composer-v1-{{ checksum "composer.lock" }} - - composer-v1- - - run: composer install -n --prefer-dist --ignore-platform-reqs --no-progress - - save_cache: - key: composer-v1-{{ checksum "composer.lock" }} - paths: - - vendor - - run: - name: PHPCS PHPCompatibility - command: | - ./vendor/bin/phpcs --config-set installed_paths vendor/phpcompatibility/php-compatibility/PHPCompatibility/ - # vendor/ is large and seems to break phpcs, ls+grep+xargs hack is used to send folders to phpcs - ls -d */ | grep -vE 'dev|Test|vendor' | xargs ./vendor/bin/phpcs -p --standard=PHPCompatibility --runtime-set testVersion 7.1- --runtime-set ignore_warnings_on_exit true + "quality-tools": + docker: + - image: algolia/magento2-circleci:2.3.0 + working_directory: ~/build_directory/algoliasearch-magento-2 + steps: + - checkout + - run: + name: Setting permissions + command: | + sudo chown circleci:circleci ~/.composer/ + - restore_cache: + keys: + - composer-v2-{{ checksum "composer.json" }} + - composer-v2- + + - run: + name: Prepare environment + command: | + sudo composer self-update + composer config http-basic.'repo.magento.com' ${MAGENTO_AUTH_USERNAME} ${MAGENTO_AUTH_PASSWORD} + composer install -n --prefer-dist --ignore-platform-reqs --no-progress + sudo chown circleci:circleci ~/.composer/ + composer global config prefer-stable true + composer global config minimum-stability dev + composer global require algolia/magento2-tools --ignore-platform-reqs + + # We have to do this again because we restore the cache above, overwriting the vendor with the original. + cd ~/magento_directory/vendor/algolia + rm -rf algoliasearch-magento-2 + cp -R ~/build_directory/algoliasearch-magento-2 ~/magento_directory/vendor/algolia + cd ~/magento_directory + composer dump-autoload + - save_cache: + key: composer-v2-{{ checksum "composer.json" }} + paths: + - vendor + - ~/.composer/vendor + - run: + name: Quality tools + command: | + sudo ~/.composer/vendor/bin/magento2-test ~/magento_directory/vendor/algolia/algoliasearch-magento-2 ~/.composer/vendor/bin/ workflows: version: 2 @@ -93,4 +112,4 @@ workflows: jobs: - "magento-2.2" - "magento-2.3" - - "phpcompatibility" + - "quality-tools" diff --git a/.styleci.yml b/.styleci.yml index baa60490d..53daa63f2 100755 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,4 +1 @@ preset: PSR2 -finder: - path: - - "code" \ No newline at end of file diff --git a/Block/Adminhtml/BaseAdminTemplate.php b/Block/Adminhtml/BaseAdminTemplate.php deleted file mode 100644 index 4c5e1fbba..000000000 --- a/Block/Adminhtml/BaseAdminTemplate.php +++ /dev/null @@ -1,30 +0,0 @@ -viewModelFactory = $viewModelFactory; - } - - public function getViewModel() - { - return $this->viewModelFactory->create($this); - } -} diff --git a/Block/LandingPage.php b/Block/LandingPage.php index 936b43b36..7ee2c1423 100644 --- a/Block/LandingPage.php +++ b/Block/LandingPage.php @@ -10,6 +10,9 @@ use Magento\Cms\Model\Template\FilterProvider; use Magento\Search\Model\QueryFactory; +/** + * @method int getPageId() + */ class LandingPage extends Result { /** @var FilterProvider */ diff --git a/Block/Navigation/Renderer/CategoryRenderer.php b/Block/Navigation/Renderer/CategoryRenderer.php index 9d96d069e..5d5b532a7 100644 --- a/Block/Navigation/Renderer/CategoryRenderer.php +++ b/Block/Navigation/Renderer/CategoryRenderer.php @@ -11,6 +11,9 @@ class CategoryRenderer extends Template implements FilterRendererInterface /** @var string */ protected $_template = 'Algolia_AlgoliaSearch::layer/filter/category.phtml'; + /** @var FilterInterface */ + protected $filter; + public function isMultipleSelectEnabled() { return false; diff --git a/Block/Navigation/Renderer/DefaultRenderer.php b/Block/Navigation/Renderer/DefaultRenderer.php index f3c78c7ce..9c98b1be3 100644 --- a/Block/Navigation/Renderer/DefaultRenderer.php +++ b/Block/Navigation/Renderer/DefaultRenderer.php @@ -24,6 +24,9 @@ class DefaultRenderer extends Template implements FilterRendererInterface /** @var ConfigHelper */ private $configHelper; + /** @var FilterInterface */ + protected $filter; + /** * Constructor. * diff --git a/Block/Navigation/Renderer/SliderRenderer.php b/Block/Navigation/Renderer/SliderRenderer.php index 7781d4022..8276b985f 100644 --- a/Block/Navigation/Renderer/SliderRenderer.php +++ b/Block/Navigation/Renderer/SliderRenderer.php @@ -23,6 +23,9 @@ class SliderRenderer extends Template implements FilterRendererInterface /** @var FormatInterface */ protected $localeFormat; + /** @var FilterInterface */ + protected $filter; + /** * * @param Context $context diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fae44fc2..b62971d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,56 @@ # CHANGE LOG +## 1.12.1 + +This release has been made possible thanks to the involvement of the community, with about half of the pull requests merged coming from the Magento ecosystem. + +The Magento team at Algolia really wanted to thank our amazing community for its help. +For this release, a big shout out for: + +- @DavidLambauer +- @JosephMaxwell +- @peterjaap +- @unicoder88 +- @VincentMarmiesse +- @vmalyk + +Thanks A LOT for your PRs, we really appreciate! + +What this release brings: + +### FEATURES +- Add extension notifier (#868) + +### UPDATES +- Removed objectManager from ProductHelper (#814) (by @peterjaap) +- Removing the BaseAdminTemplate block (#822) +- Add config warnings for ES and MSI (#889) +- Remove catalog index price update by schedule subscription (#870) (by @unicoder88) +- Added alt attribute for img tags (#896) (by @vmalyk) +- Add "suggest" section modules in composer.json (#898) (by @vmalyk) +- Create replicas if Backend Facet Rendering is enabled (#902) (by @VincentMarmiesse) + +### FIXES +- Fixed the dependency list (#843) (by @DavidLambauer) +- Pass set product website_id to load catalogrule prices with enabled customer groups (#853) (by @unicoder88) +- Clean scope code resolver when starting environment emulation (#857) (by @unicoder88) +- Fixing order of setting parameters (#859) (by @JosephMaxwell) +- Fixed Composer requirements and README.md (#884) (by @vmalyk) +- Fix Tier Price calculation (#887) +- Fix autocomplete additional sections link URL (#891) +- Fix errors in code instead ignore in PHPStan (#878) (by @vmalyk) +- Fix product image helper method to return set images (#899) +- Fix version to 1.12.1 for unsubscribe Mview migration (PR #870) (#910) (by @vmalyk) + +### TOOLING +- Events tracking (#805) +- chore: fixes styleci configuration (#847) +- chore(ignores-phpstan-fixed-errors): sets reportUnmatchedIgnoredError (#877) +- ci: quality assurance tools (#882) +- Ci/quality tools (#886) +- chore: increases phpstan level to 1 (#892) +- Make changes to pass new Marketplace test expectations (#906) + ## 1.12.0 ### FEATURES diff --git a/Controller/Adminhtml/Analytics/Update.php b/Controller/Adminhtml/Analytics/Update.php index 4aca1267b..735be09bb 100644 --- a/Controller/Adminhtml/Analytics/Update.php +++ b/Controller/Adminhtml/Analytics/Update.php @@ -2,8 +2,8 @@ namespace Algolia\AlgoliaSearch\Controller\Adminhtml\Analytics; -use Algolia\AlgoliaSearch\Block\Adminhtml\BaseAdminTemplate; use Algolia\AlgoliaSearch\ViewModel\Adminhtml\Analytics\Overview; +use Magento\Backend\Block\Template; use Magento\Framework\DataObject; class Update extends AbstractAction @@ -18,7 +18,7 @@ public function execute() $layout = $this->layoutFactory->create(); $block = $layout - ->createBlock(BaseAdminTemplate::class) + ->createBlock(Template::class) ->setData('view_model', $this->_objectManager->create(Overview::class)) ->setTemplate('Algolia_AlgoliaSearch::analytics/overview.phtml') ->toHtml(); diff --git a/Controller/Adminhtml/Landingpage/Duplicate.php b/Controller/Adminhtml/Landingpage/Duplicate.php index 74e5f0b96..3fcd8301a 100644 --- a/Controller/Adminhtml/Landingpage/Duplicate.php +++ b/Controller/Adminhtml/Landingpage/Duplicate.php @@ -75,8 +75,6 @@ private function copyQueryRules($landingPageFromId, $landingPageToId) $stores[] = $store->getId(); } } - } else { - $stores[] = $data['store_id']; } foreach ($stores as $storeId) { diff --git a/Controller/Adminhtml/Query/Save.php b/Controller/Adminhtml/Query/Save.php index 3ec928dc0..75c1366fa 100644 --- a/Controller/Adminhtml/Query/Save.php +++ b/Controller/Adminhtml/Query/Save.php @@ -2,8 +2,10 @@ namespace Algolia\AlgoliaSearch\Controller\Adminhtml\Query; +use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Helper\MerchandisingHelper; use Algolia\AlgoliaSearch\Helper\ProxyHelper; +use Algolia\AlgoliaSearch\Model\ImageUploader; use Algolia\AlgoliaSearch\Model\QueryFactory; use Magento\Framework\App\Request\DataPersistorInterface; use Magento\Framework\Controller\ResultFactory; @@ -17,6 +19,16 @@ class Save extends AbstractAction */ protected $dataPersistor; + /** + * @var ConfigHelper + */ + protected $configHelper; + + /** + * @var ImageUploader + */ + protected $imageUploader; + /** * PHP Constructor * @@ -27,6 +39,8 @@ class Save extends AbstractAction * @param ProxyHelper $proxyHelper * @param StoreManagerInterface $storeManager * @param DataPersistorInterface $dataPersistor + * @param ConfigHelper $configHelper + * @param ImageUploader $imageUploader * * @return Save */ @@ -37,9 +51,13 @@ public function __construct( MerchandisingHelper $merchandisingHelper, ProxyHelper $proxyHelper, StoreManagerInterface $storeManager, - DataPersistorInterface $dataPersistor + DataPersistorInterface $dataPersistor, + ConfigHelper $configHelper, + ImageUploader $imageUploader ) { $this->dataPersistor = $dataPersistor; + $this->configHelper = $configHelper; + $this->imageUploader = $imageUploader; parent::__construct( $context, @@ -84,9 +102,6 @@ public function execute() if (isset($data['banner_image'][0]['name']) && isset($data['banner_image'][0]['tmp_name'])) { $data['banner_image'] = $data['banner_image'][0]['name']; - $this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()->get( - 'Algolia\AlgoliaSearch\QueryImageUpload' - ); $this->imageUploader->moveFileFromTmp($data['banner_image']); } elseif (isset($data['banner_image'][0]['image']) && !isset($data['banner_image'][0]['tmp_name'])) { $data['banner_image'] = $data['banner_image'][0]['image']; @@ -97,6 +112,12 @@ public function execute() $query->setData($data); $query->setCreatedAt(time()); + $storeId = isset($data['store_id']) && $data['store_id'] != 0 ? $data['store_id'] : null; + + $this->trackQueryMerchandisingData($query, 'banner_image', 'Uploaded Banner', $storeId); + $this->trackQueryMerchandisingData($query, 'banner_alt', 'Add Alt Text', $storeId); + $this->trackQueryMerchandisingData($query, 'banner_url', 'Add Banner URL', $storeId); + try { $query->getResource()->save($query); @@ -188,4 +209,22 @@ private function prepareBannerContent($data) return $content; } + + /** + * @param string $query + * @param string $attributeCode + * @param string $eventName + * @param int|null $storeId + */ + private function trackQueryMerchandisingData($query, $attributeCode, $eventName, $storeId = null) + { + if (($query->isObjectNew() && $query->getData($attributeCode)) + || $query->getOrigData($attributeCode) !== $query->getData($attributeCode)) { + $this->proxyHelper->trackEvent( + $this->configHelper->getApplicationID($storeId), + $eventName, + ['source' => 'magento2.querymerch.edit'] + ); + } + } } diff --git a/Controller/Adminhtml/Queue/AbstractAction.php b/Controller/Adminhtml/Queue/AbstractAction.php index f40a6620d..cb2cc6837 100644 --- a/Controller/Adminhtml/Queue/AbstractAction.php +++ b/Controller/Adminhtml/Queue/AbstractAction.php @@ -58,7 +58,7 @@ protected function _isAllowed() return $this->_authorization->isAllowed('Algolia_AlgoliaSearch::manage'); } - /** @return \Algolia\AlgoliaSearch\Model */ + /** @return \Algolia\AlgoliaSearch\Model\Job */ protected function initJob() { $jobId = (int) $this->getRequest()->getParam('id'); @@ -68,7 +68,7 @@ protected function initJob() return null; } - /** @var \Algolia\AlgoliaSearch\Model $model */ + /** @var \Algolia\AlgoliaSearch\Model\Job $model */ $model = $this->jobFactory->create(); $this->jobResourceModel->load($model, $jobId); if (!$model->getId()) { diff --git a/Factory/ViewModelFactory.php b/Factory/ViewModelFactory.php deleted file mode 100644 index 07eb1505f..000000000 --- a/Factory/ViewModelFactory.php +++ /dev/null @@ -1,64 +0,0 @@ -objectManager = $objectManager; - } - - /** - * @param Template $block - * - * @return object - */ - public function create($block) - { - $templateName = $block->getTemplate(); - $classNameSuffix = $this->transformTemplateToClassNameSuffix($templateName); - - // Turns "Algolia\AlgoliaSearch\Block\Adminhtml\BaseAdminTemplate" - // to "Algolia\AlgoliaSearch\ViewModel\Adminhtml\[[specificViewModelName]]" - $viewModelClassName = str_replace( - ['\Block\\', 'BaseAdminTemplate'], - ['\ViewModel\\', $classNameSuffix], - get_class($block) - ); - - return $this->objectManager->create($viewModelClassName); - } - - /** - * It turns template name (eg. "Algolia_AlgoliaSearch::support/overview.phtml") - * to class name suffix (eg. "Support\Overview"), - * which is later on used to create ViewModel object - * - * @param string $templateName - * - * @return string - */ - private function transformTemplateToClassNameSuffix($templateName) - { - $className = str_replace(['Algolia_AlgoliaSearch::', '.phtml'], '', $templateName); - - $classNameParts = explode('/', $className); - $classNameParts = array_map(function ($part) { - return ucfirst($part); - }, $classNameParts); - - $className = implode('\\', $classNameParts); - - return $className; - } -} diff --git a/Helper/ConfigHelper.php b/Helper/ConfigHelper.php index 71efdadf4..ee466725f 100755 --- a/Helper/ConfigHelper.php +++ b/Helper/ConfigHelper.php @@ -8,6 +8,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\DataObject; use Magento\Framework\Locale\Currency; +use Magento\Framework\Serialize\SerializerInterface; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; @@ -98,6 +99,7 @@ class ConfigHelper const SHOW_OUT_OF_STOCK = 'cataloginventory/options/show_out_of_stock'; const USE_SECURE_IN_FRONTEND = 'web/secure/use_in_frontend'; + const CATALOG_SEARCH_ENGINE = 'catalog/search/engine'; const EXTRA_SETTINGS_PRODUCTS = 'algoliasearch_extra_settings/extra_settings/products_extra_settings'; const EXTRA_SETTINGS_CATEGORIES = 'algoliasearch_extra_settings/extra_settings/categories_extra_settings'; @@ -118,6 +120,7 @@ class ConfigHelper private $productMetadata; private $eventManager; private $currencyManager; + private $serializer; private $maxRecordSize; public function __construct( @@ -130,7 +133,8 @@ public function __construct( Magento\Framework\Module\ResourceInterface $moduleResource, Magento\Framework\App\ProductMetadataInterface $productMetadata, Magento\Framework\Event\ManagerInterface $eventManager, - Magento\Directory\Model\Currency $currencyManager + Magento\Directory\Model\Currency $currencyManager, + SerializerInterface $serializer ) { $this->objectManager = $objectManager; $this->configInterface = $configInterface; @@ -142,6 +146,7 @@ public function __construct( $this->productMetadata = $productMetadata; $this->eventManager = $eventManager; $this->currencyManager = $currencyManager; + $this->serializer = $serializer; } public function indexOutOfStockOptions($storeId = null) @@ -464,13 +469,23 @@ public function isAutocompleteDebugEnabled($storeId = null) return $this->configInterface->isSetFlag(self::AUTOCOMPLETE_MENU_DEBUG, ScopeInterface::SCOPE_STORE, $storeId); } - public function getSortingIndices($originalIndexName, $storeId = null, $currentCustomerGroupId = null) + public function getRawSortingValue($storeId = null) { - $attrs = $this->unserialize($this->configInterface->getValue( + return $this->configInterface->getValue( self::SORTING_INDICES, ScopeInterface::SCOPE_STORE, $storeId - )); + ); + } + + public function getSorting($storeId = null) + { + return $this->unserialize($this->getRawSortingValue($storeId)); + } + + public function getSortingIndices($originalIndexName, $storeId = null, $currentCustomerGroupId = null) + { + $attrs = $this->getSorting($storeId); $currency = $this->getCurrencyCode($storeId); $attributesToAdd = []; @@ -691,13 +706,28 @@ public function getCategoryCustomRanking($storeId = null) return []; } - public function getProductCustomRanking($storeId = null) + /** + * @param int|null $storeId + * + * @return mixed + */ + public function getRawProductCustomRanking($storeId = null) { - $attrs = $this->unserialize($this->configInterface->getValue( + return $this->configInterface->getValue( self::PRODUCT_CUSTOM_RANKING, ScopeInterface::SCOPE_STORE, $storeId - )); + ); + } + + /** + * @param int|null $storeId + * + * @return array|mixed + */ + public function getProductCustomRanking($storeId = null) + { + $attrs = $this->unserialize($this->getRawProductCustomRanking($storeId)); if (is_array($attrs)) { return $attrs; @@ -1037,13 +1067,17 @@ private function addIndexableAttributes( private function unserialize($value) { + if (false === $value || null === $value || '' === $value) { + return false; + } + $unserialized = json_decode($value, true); if (json_last_error() === JSON_ERROR_NONE) { return $unserialized; } - return unserialize($value); + return $this->serializer->unserialize($value); } public function getDefaultMaxRecordSize() @@ -1077,4 +1111,9 @@ public function getMaxRecordSizeLimit($storeId = null) return $this->maxRecordSize; } + + public function getCatalogSearchEngine($storeId = null) + { + return $this->configInterface->getValue(self::CATALOG_SEARCH_ENGINE, ScopeInterface::SCOPE_STORE, $storeId); + } } diff --git a/Helper/Data.php b/Helper/Data.php index 4d1ba0e9c..36c8f4bfb 100755 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -14,6 +14,7 @@ use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\Framework\App\Area; +use Magento\Framework\App\Config\ScopeCodeResolver; use Magento\Framework\App\ResourceConnection; use Magento\Framework\Event\ManagerInterface; use Magento\Search\Model\Query; @@ -36,6 +37,7 @@ class Data private $emulation; private $resource; private $eventManager; + private $scopeCodeResolver; private $storeManager; private $emulationRuns = false; @@ -53,6 +55,7 @@ public function __construct( Logger $logger, ResourceConnection $resource, ManagerInterface $eventManager, + ScopeCodeResolver $scopeCodeResolver, StoreManagerInterface $storeManager ) { $this->algoliaHelper = $algoliaHelper; @@ -69,6 +72,7 @@ public function __construct( $this->emulation = $emulation; $this->resource = $resource; $this->eventManager = $eventManager; + $this->scopeCodeResolver = $scopeCodeResolver; $this->storeManager = $storeManager; } @@ -549,7 +553,7 @@ private function getCategoryRecords($storeId, $collection, $potentiallyDeletedCa unset($potentiallyDeletedCategoriesIds[$categoryId]); } - if (isset($categorysToIndex[$categoryId]) || isset($categorysToRemove[$categoryId])) { + if (isset($categoriesToIndex[$categoryId]) || isset($categoriesToRemove[$categoryId])) { continue; } @@ -676,6 +680,7 @@ public function startEmulation($storeId) $this->logger->start('START EMULATION'); $this->emulation->startEnvironmentEmulation($storeId, Area::AREA_FRONTEND, true); + $this->scopeCodeResolver->clean(); $this->emulationRuns = true; $this->logger->stop('START EMULATION'); diff --git a/Helper/Entity/AdditionalSectionHelper.php b/Helper/Entity/AdditionalSectionHelper.php index 497e3d8d6..174c0a6de 100755 --- a/Helper/Entity/AdditionalSectionHelper.php +++ b/Helper/Entity/AdditionalSectionHelper.php @@ -65,14 +65,14 @@ public function getAttributeValues($storeId, $section) implode(',', $usedAttributeValues) ); - if (!$values || count($values) === 0) { - $values = array_unique($products->getColumnValues($attributeCode)); - } - if ($values && is_array($values) === false) { $values = [$values]; } + if (!$values || count($values) === 0) { + $values = array_unique($products->getColumnValues($attributeCode)); + } + $values = array_map(function ($value) use ($section, $storeId) { $record = [ 'objectID' => $value, diff --git a/Helper/Entity/CategoryHelper.php b/Helper/Entity/CategoryHelper.php index 77077f25c..9b6419fe6 100755 --- a/Helper/Entity/CategoryHelper.php +++ b/Helper/Entity/CategoryHelper.php @@ -175,9 +175,9 @@ public function getCategoryCollectionQuery($storeId, $categoryIds = null) $categories = $this->categoryCollectionFactory->create() ->distinct(true) ->addNameToResult() + ->setStoreId($storeId) ->addUrlRewriteToResult() ->addAttributeToFilter('level', ['gt' => 1]) - ->setStoreId($storeId) ->addPathFilter($storeRootCategoryPath) ->addAttributeToSelect(array_merge(['name', 'is_active', 'include_in_menu', 'image'], $additionalAttr)) ->addOrderField('entity_id'); diff --git a/Helper/Entity/PageHelper.php b/Helper/Entity/PageHelper.php index 45fba2915..dda584d41 100755 --- a/Helper/Entity/PageHelper.php +++ b/Helper/Entity/PageHelper.php @@ -162,22 +162,24 @@ private function strip($s, $completeRemoveTags = []) { if ($completeRemoveTags && $completeRemoveTags !== [] && $s) { $dom = new \DOMDocument(); - if (@$dom->loadHTML(mb_convert_encoding($s, 'HTML-ENTITIES', 'UTF-8'))) { - $toRemove = []; - foreach ($completeRemoveTags as $tag) { - $removeTags = $dom->getElementsByTagName($tag); - - foreach ($removeTags as $item) { - $toRemove[] = $item; - } - } + libxml_use_internal_errors(true); + $dom->loadHTML(mb_convert_encoding($s, 'HTML-ENTITIES', 'UTF-8')); + libxml_use_internal_errors(false); + + $toRemove = []; + foreach ($completeRemoveTags as $tag) { + $removeTags = $dom->getElementsByTagName($tag); - foreach ($toRemove as $item) { - $item->parentNode->removeChild($item); + foreach ($removeTags as $item) { + $toRemove[] = $item; } + } - $s = $dom->saveHTML(); + foreach ($toRemove as $item) { + $item->parentNode->removeChild($item); } + + $s = $dom->saveHTML(); } $s = html_entity_decode($s, null, 'UTF-8'); diff --git a/Helper/Entity/Product/PriceManager/ProductWithoutChildren.php b/Helper/Entity/Product/PriceManager/ProductWithoutChildren.php index 37966a681..321242e52 100644 --- a/Helper/Entity/Product/PriceManager/ProductWithoutChildren.php +++ b/Helper/Entity/Product/PriceManager/ProductWithoutChildren.php @@ -215,11 +215,13 @@ protected function getTierPrice(Product $product, $currencyCode, $withTax) } if (isset($tierPrices[$groupId]) && $tierPrices[$groupId] !== []) { - $currentTierPrice = min($currentTierPrice, $tierPrices[$groupId]); + $currentTierPrice = $currentTierPrice === null ? + $tierPrices[$groupId] : + min($currentTierPrice, $tierPrices[$groupId]); } if ($currencyCode !== $this->baseCurrencyCode) { - $tierPrices[$groupId] = + $currentTierPrice = $this->priceCurrency->round($this->convertPrice($currentTierPrice, $currencyCode)); } $tierPrice[$groupId] = $this->getTaxPrice($product, $currentTierPrice, $withTax); @@ -245,6 +247,7 @@ protected function addCustomerGroupsPrices(Product $product, $currencyCode, $wit $groupId = (int) $group->getData('customer_group_id'); $product->setData('customer_group_id', $groupId); + $product->setData('website_id', $product->getStore()->getWebsiteId()); $discountedPrice = $product->getPriceModel()->getFinalPrice(1, $product); if ($currencyCode !== $this->baseCurrencyCode) { diff --git a/Helper/Entity/ProductHelper.php b/Helper/Entity/ProductHelper.php index 5ed37b064..2f6499c4d 100755 --- a/Helper/Entity/ProductHelper.php +++ b/Helper/Entity/ProductHelper.php @@ -10,6 +10,7 @@ use Algolia\AlgoliaSearch\Helper\AlgoliaHelper; use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Helper\Entity\Product\PriceManager; +use Algolia\AlgoliaSearch\Helper\Image as ImageHelper; use Algolia\AlgoliaSearch\Helper\Logger; use AlgoliaSearch\AlgoliaException; use AlgoliaSearch\Index; @@ -20,19 +21,22 @@ use Magento\Catalog\Model\Product\Type\AbstractType; use Magento\Catalog\Model\Product\Visibility; use Magento\Catalog\Model\ResourceModel\Eav\Attribute as AttributeResource; +use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\CatalogInventory\Helper\Stock; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; +use Magento\Customer\Model\ResourceModel\Group\Collection as GroupCollection; use Magento\Directory\Model\Currency as CurrencyHelper; use Magento\Eav\Model\Config; use Magento\Framework\DataObject; use Magento\Framework\Event\ManagerInterface; -use Magento\Framework\ObjectManagerInterface; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; class ProductHelper { + protected $productCollectionFactory; + protected $groupCollection; private $eavConfig; private $configHelper; private $algoliaHelper; @@ -41,8 +45,7 @@ class ProductHelper private $eventManager; private $visibility; private $stockHelper; - protected $stockRegistry; - private $objectManager; + private $stockRegistry; private $currencyManager; private $categoryHelper; private $priceManager; @@ -86,6 +89,26 @@ class ProductHelper 'color', ]; + /** + * ProductHelper constructor. + * + * @param Config $eavConfig + * @param ConfigHelper $configHelper + * @param AlgoliaHelper $algoliaHelper + * @param Logger $logger + * @param StoreManagerInterface $storeManager + * @param ManagerInterface $eventManager + * @param Visibility $visibility + * @param Stock $stockHelper + * @param StockRegistryInterface $stockRegistry + * @param CurrencyHelper $currencyManager + * @param CategoryHelper $categoryHelper + * @param PriceManager $priceManager + * @param Type $productType + * @param CollectionFactory $productCollectionFactory + * @param GroupCollection $groupCollection + * @param ImageHelper $imageHelper + */ public function __construct( Config $eavConfig, ConfigHelper $configHelper, @@ -96,11 +119,13 @@ public function __construct( Visibility $visibility, Stock $stockHelper, StockRegistryInterface $stockRegistry, - ObjectManagerInterface $objectManager, CurrencyHelper $currencyManager, CategoryHelper $categoryHelper, PriceManager $priceManager, - Type $productType + Type $productType, + CollectionFactory $productCollectionFactory, + GroupCollection $groupCollection, + ImageHelper $imageHelper ) { $this->eavConfig = $eavConfig; $this->configHelper = $configHelper; @@ -111,20 +136,13 @@ public function __construct( $this->visibility = $visibility; $this->stockHelper = $stockHelper; $this->stockRegistry = $stockRegistry; - $this->objectManager = $objectManager; $this->currencyManager = $currencyManager; $this->categoryHelper = $categoryHelper; $this->priceManager = $priceManager; $this->productType = $productType; - - $this->imageHelper = $this->objectManager->create( - 'Algolia\AlgoliaSearch\Helper\Image', - [ - 'options' =>[ - 'shouldRemovePubDir' => $this->configHelper->shouldRemovePubDirectory(), - ], - ] - ); + $this->productCollectionFactory = $productCollectionFactory; + $this->groupCollection = $groupCollection; + $this->imageHelper = $imageHelper; } public function getIndexNameSuffix() @@ -201,10 +219,8 @@ public function getProductCollectionQuery( $onlyVisible = true, $includeNotVisibleIndividually = false ) { - /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $products */ - $products = $this->objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Collection'); - - $products = $products + $productCollection = $this->productCollectionFactory->create(); + $products = $productCollection ->setStoreId($storeId) ->addStoreFilter($storeId) ->distinct(true); @@ -330,7 +346,7 @@ public function setSettings($indexName, $indexNameTmp, $storeId, $saveToTmpIndic $replicas = []; - if ($this->configHelper->isInstantEnabled()) { + if ($this->configHelper->isInstantEnabled() || $this->configHelper->isBackendRenderingEnabled()) { $replicas = array_values(array_map(function ($sortingIndex) { return $sortingIndex['name']; }, $sortingIndices)); @@ -971,10 +987,7 @@ private function getAttributesForFaceting($storeId) $facet['attribute'] = 'price.' . $currency_code . '.default'; if ($this->configHelper->isCustomerGroupsEnabled($storeId)) { - $groupCollection = $this->objectManager - ->create('Magento\Customer\Model\ResourceModel\Group\Collection'); - - foreach ($groupCollection as $group) { + foreach ($this->groupCollection as $group) { $group_id = (int) $group->getData('customer_group_id'); $attributesForFaceting[] = 'price.' . $currency_code . '.group_' . $group_id; diff --git a/Helper/Entity/SuggestionHelper.php b/Helper/Entity/SuggestionHelper.php index 8281ccd98..2b4341a79 100755 --- a/Helper/Entity/SuggestionHelper.php +++ b/Helper/Entity/SuggestionHelper.php @@ -7,6 +7,7 @@ use Magento\Framework\DataObject; use Magento\Framework\Event\ManagerInterface; use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Serialize\SerializerInterface; use Magento\Search\Model\Query; class SuggestionHelper @@ -19,18 +20,22 @@ class SuggestionHelper private $configHelper; + private $serializer; + private $popularQueriesCacheId = 'algoliasearch_popular_queries_cache_tag'; public function __construct( ManagerInterface $eventManager, ObjectManagerInterface $objectManager, ConfigCache $cache, - ConfigHelper $configHelper + ConfigHelper $configHelper, + SerializerInterface $serializer ) { $this->eventManager = $eventManager; $this->objectManager = $objectManager; $this->cache = $cache; $this->configHelper = $configHelper; + $this->serializer = $serializer; } public function getIndexNameSuffix() @@ -81,7 +86,7 @@ public function getPopularQueries($storeId) { $queries = $this->cache->load($this->popularQueriesCacheId); if ($queries !== false) { - return unserialize($queries); + return $this->serializer->unserialize($queries); } $collection = $this->objectManager->create('\Magento\Search\Model\ResourceModel\Query\Collection'); @@ -111,7 +116,7 @@ public function getPopularQueries($storeId) $queries = array_slice($suggestions, 0, 9); - $this->cache->save(serialize($queries), $this->popularQueriesCacheId, [], 24*3600); + $this->cache->save($this->serializer->serialize($queries), $this->popularQueriesCacheId, [], 24*3600); return $queries; } diff --git a/Helper/Image.php b/Helper/Image.php index af6aa5280..49182a08e 100755 --- a/Helper/Image.php +++ b/Helper/Image.php @@ -10,8 +10,11 @@ class Image extends \Magento\Catalog\Helper\Image { + /** + * @var ConfigHelper + */ + protected $configHelper; private $logger; - private $options; /** * Image constructor. @@ -21,7 +24,7 @@ class Image extends \Magento\Catalog\Helper\Image * @param Repository $assetRepo * @param ConfigInterface $viewConfig * @param Logger $logger - * @param array $options + * @param ConfigHelper $configHelper */ public function __construct( Context $context, @@ -29,14 +32,11 @@ public function __construct( Repository $assetRepo, ConfigInterface $viewConfig, Logger $logger, - $options = [] + ConfigHelper $configHelper ) { parent::__construct($context, $productImageFactory, $assetRepo, $viewConfig); $this->logger = $logger; - - $this->options = array_merge([ - 'shouldRemovePubDir' => false, - ], $options); + $this->configHelper = $configHelper; } public function getUrl() @@ -55,7 +55,7 @@ public function getUrl() $url = $this->removeProtocol($url); $url = $this->removeDoubleSlashes($url); - if ($this->options['shouldRemovePubDir']) { + if ($this->configHelper->shouldRemovePubDirectory()) { $url = $this->removePubDirectory($url); } @@ -70,7 +70,7 @@ protected function initBaseFile() if ($this->getImageFile()) { $model->setBaseFile($this->getImageFile()); } else { - $model->setBaseFile($this->getProductImage()); + $model->setBaseFile($this->getProductImage($model)); } } @@ -81,14 +81,16 @@ protected function initBaseFile() * Configurable::setImageFromChildProduct() only pulls 'image' type * and not the type set by the imageHelper * - * @return string + * @param \Magento\Catalog\Model\Product\Image $model + * + * @return mixed|string|null */ - private function getProductImage() + private function getProductImage(\Magento\Catalog\Model\Product\Image $model) { - $imageUrl = $this->getProduct()->getImage(); - if (!$this->getImageFile() && $this->getType() !== 'image' - && $this->getProduct()->getTypeId() == ProductTypeConfigurable::TYPE_CODE) { - $imageUrl = $this->getConfigurableProductImage() ?: $imageUrl; + $imageUrl = $this->getProduct()->getData($model->getDestinationSubdir()); + if ($this->getProduct()->getTypeId() == ProductTypeConfigurable::TYPE_CODE) { + $imageUrl = $this->getType() !== 'image' && $this->getConfigurableProductImage() ? + $this->getConfigurableProductImage() : $this->getProduct()->getImage(); } return $imageUrl; diff --git a/Helper/ProxyHelper.php b/Helper/ProxyHelper.php index 55dd9bed1..8520f96fa 100644 --- a/Helper/ProxyHelper.php +++ b/Helper/ProxyHelper.php @@ -5,8 +5,10 @@ class ProxyHelper { const PROXY_URL = 'https://magento-proxy.algolia.com/'; + const PROXY_URL_PARAM_GET_INFO = 'get-info/'; const PROXY_URL_PARAM_POST_DATA = 'hs-push/'; + const PROXY_URL_PARAM_TRACK_EVENT = 'event/'; const INFO_TYPE_EXTENSION_SUPPORT = 'extension_support'; const INFO_TYPE_QUERY_RULES = 'query_rules'; @@ -57,6 +59,22 @@ public function getInfo($type) return $info; } + /** + * @param string $appId + * @param string $eventName + * @param array $data + */ + public function trackEvent($appId, $eventName, $data) + { + $params = [ + 'appId' => $appId, + 'eventName' => $eventName, + 'data' => $data, + ]; + + $this->postRequest($params, self::PROXY_URL_PARAM_TRACK_EVENT); + } + public function getClientConfigurationData() { if (!$this->allClientData) { @@ -75,11 +93,7 @@ public function pushSupportTicket($data) { $result = $this->postRequest($data, self::PROXY_URL_PARAM_POST_DATA); - if ($result === 'true') { - return true; - } - - return false; + return $result === 'true'; } /** diff --git a/Helper/SupportHelper.php b/Helper/SupportHelper.php index 47ddc1d4e..28399b4f0 100644 --- a/Helper/SupportHelper.php +++ b/Helper/SupportHelper.php @@ -63,6 +63,10 @@ public function processContactForm($data) 'note' => $this->noteBuilder->getNote($data['send_additional_info']), ]; + $this->proxyHelper->trackEvent($this->configHelper->getApplicationID(), 'Sent Contact Form', [ + 'source' => 'magento2.help.contact', + ]); + return $this->proxyHelper->pushSupportTicket($messageData); } diff --git a/Model/ConfigurationTracker.php b/Model/ConfigurationTracker.php new file mode 100644 index 000000000..953e49dc3 --- /dev/null +++ b/Model/ConfigurationTracker.php @@ -0,0 +1,128 @@ +proxyHelper = $proxyHelper; + $this->configHelper = $configHelper; + $this->queryCollection = $queryCollection; + $this->landingPageCollection = $landingPageCollection; + $this->upgradeSchema = $upgradeSchema; + } + + /** + * @param int $storeId + */ + public function trackConfiguration($storeId) + { + $this->proxyHelper->trackEvent($this->configHelper->getApplicationID($storeId), 'Configuration saved', [ + 'source' => 'magento2.saveconfig', + 'indexingEnabled' => $this->configHelper->isEnabledBackend($storeId), + 'searchEnabled' => $this->configHelper->isEnabledFrontEnd($storeId), + 'autocompleteEnabled' => $this->configHelper->isAutoCompleteEnabled($storeId), + 'instantsearchEnabled' => $this->configHelper->isInstantEnabled($storeId), + 'sortingChanged' => $this->isSortingChanged($storeId), + 'rankingChanged' => $this->isCustomRankingChanged($storeId), + 'replaceImageByVariantUsed' => $this->configHelper->useAdaptiveImage($storeId), + 'indexingQueueEnabled' => $this->configHelper->isQueueActive($storeId), + 'synonymsManagementEnabled' => $this->configHelper->isEnabledSynonyms($storeId), + 'clickAnalyticsEnabled' => $this->configHelper->isClickConversionAnalyticsEnabled($storeId), + 'googleAnalyticsEnabled' => $this->configHelper->isAnalyticsEnabled($storeId), + 'customerGroupsEnabled' => $this->configHelper->isCustomerGroupsEnabled($storeId), + 'merchangisingQRsCreated' => $this->getCountMerchandisingQueries() > 0, + 'noOfMerchandisingQRs' => (int) $this->getCountMerchandisingQueries(), + 'landingPageCreated' => $this->getCountLandingPages() > 0, + 'noOfLandingPages' => (int) $this->getCountLandingPages(), + 'storeId' => $storeId, + ]); + } + + /** + * @param null $storeId + * + * @return bool + */ + private function isSortingChanged($storeId = null) + { + return $this->configHelper->getRawSortingValue($storeId) + !== $this->getDefaultConfigurationFromPath(ConfigHelper::SORTING_INDICES); + } + + /** + * @param null $storeId + * + * @return bool + */ + private function isCustomRankingChanged($storeId = null) + { + return $this->configHelper->getRawProductCustomRanking($storeId) + !== $this->getDefaultConfigurationFromPath(ConfigHelper::PRODUCT_CUSTOM_RANKING); + } + + /** + * @return int + */ + private function getCountMerchandisingQueries() + { + return $this->queryCollection->getSize(); + } + + /** + * @return int + */ + private function getCountLandingPages() + { + return $this->landingPageCollection->getSize(); + } + + /** + * @param string $path + * + * @return mixed|null + */ + private function getDefaultConfigurationFromPath($path) + { + $config = $this->upgradeSchema->getDefaultConfigData(); + if (isset($config[$path]) && $config[$path]) { + return $config[$path]; + } + + return null; + } +} diff --git a/Model/ExtensionNotification.php b/Model/ExtensionNotification.php new file mode 100755 index 000000000..d5a1ed507 --- /dev/null +++ b/Model/ExtensionNotification.php @@ -0,0 +1,141 @@ + [ + 'method' => 'GET', + 'header' => [ + 'User-Agent: PHP', + ], + 'timeout' => 10, + ], + ]; + + /** @var CacheInterface */ + protected $cacheManager; + + /** @var ConfigHelper */ + private $configHelper; + + private $repoData = null; + + /** + * @param CacheInterface $cacheManager + * @param ConfigHelper $configHelper + */ + public function __construct( + CacheInterface $cacheManager, + ConfigHelper $configHelper + ) { + $this->cacheManager = $cacheManager; + $this->configHelper = $configHelper; + } + + /** + * Check the version using a one day cache and return the data if there's a new version + * + * @return array|null + */ + public function checkVersion() + { + // First, try to fetch last check and return it if the frequency is not outdated + $lastCheck = $this->getLastCheck(); + if ($lastCheck['time'] + self::CHECK_FREQUENCY > time()) { + // Return it only if the version is new + return $lastCheck['is_new'] ? $lastCheck : null; + } + + return $this->checkExtensionVersion(); + } + + /** + * Retrieve Last check time + * + * @return int + */ + private function getLastCheck() + { + $notificationData = json_decode( + $this->cacheManager->load('algoliasearch_notification_lastcheck'), + true + ); + if ($notificationData === null || !is_array($notificationData)) { + $notificationData = [ + 'time' => 0, + 'is_new' => false, + 'version' => '', + 'url' => '', + ]; + } + + return $notificationData; + } + + /** + * Set last check (time, version and url) + * + * @param array $newExtensionData + * + * @return $this + */ + private function setLastCheck($newExtensionData) + { + $this->cacheManager->save(json_encode($newExtensionData), 'algoliasearch_notification_lastcheck'); + + return $this; + } + + private function checkExtensionVersion() + { + $newVersion = null; + try { + $versionFromRepository = $this->getLatestVersionFromRepository()->name; + } catch (\Exception $e) { + return $newVersion; + } + + $newVersion = [ + 'time' => time(), + 'is_new' => false, + 'version' => $versionFromRepository, + 'url' => $this->getLatestVersionFromRepository()->html_url, + ]; + + $versionFromDb = $this->configHelper->getExtensionVersion(); + // If the db version is older than the repo one, mark it as new and return it + if (version_compare($versionFromDb, $versionFromRepository, '<')) { + $newVersion['is_new'] = true; + $this->setLastCheck($newVersion); + + return $newVersion; + } + + $this->setLastCheck($newVersion); + + return null; + } + + private function getLatestVersionFromRepository() + { + if ($this->repoData === null) { + $json = file_get_contents( + self::REPOSITORY_URL, + false, + stream_context_create(self::CURL_OPT) + ); + $this->repoData = json_decode($json); + } + + return $this->repoData; + } +} diff --git a/Model/Job.php b/Model/Job.php index c19b94b0e..2ef7ea8ba 100644 --- a/Model/Job.php +++ b/Model/Job.php @@ -17,6 +17,7 @@ * @method int getMaxRetries() * @method array getDecodedData() * @method array getMergedIds() + * @method $this setErrorLog(string $message) * @method $this setPid($pid) * @method $this setRetries($retries) * @method $this setStoreId($storeId) diff --git a/Model/Layer/Filter/Decimal.php b/Model/Layer/Filter/Decimal.php index b2117f5f2..83a9d69c4 100644 --- a/Model/Layer/Filter/Decimal.php +++ b/Model/Layer/Filter/Decimal.php @@ -4,6 +4,12 @@ use Algolia\AlgoliaSearch\Helper\ConfigHelper; +/** + * @method $this setMinValue(float $value) + * @method $this setMaxValue(float $value) + * @method string getFrom(string $value) + * @method string getTo(string $value) + */ class Decimal extends \Magento\CatalogSearch\Model\Layer\Filter\Decimal { /** @var \Magento\Catalog\Model\Layer\Filter\DataProvider\Price */ @@ -76,7 +82,7 @@ protected function _getItemsData() if (mb_strpos($key, '_') === false) { continue; } - $data[] = $this->prepareData($key, $count, $data); + $data[] = $this->prepareData($key, $count); } } diff --git a/Model/Layer/Filter/Item/Attribute.php b/Model/Layer/Filter/Item/Attribute.php index c090a0c18..6dc7aa9ad 100644 --- a/Model/Layer/Filter/Item/Attribute.php +++ b/Model/Layer/Filter/Item/Attribute.php @@ -2,6 +2,12 @@ namespace Algolia\AlgoliaSearch\Model\Layer\Filter\Item; +/** + * @method bool getIsSelected() + * @method mixed getValue() + * @method mixed getApplyFilterValue() + * @method string getLabel() + */ class Attribute extends \Magento\Catalog\Model\Layer\Filter\Item { /** @@ -41,9 +47,12 @@ public function getRemoveUrl() } } + $resetValue = null; + if (!is_null($idToRemove)) { $resetValue = array_diff($this->getApplyValue(), [$idToRemove]); } + $query = [$this->getFilter()->getRequestVar() => implode('~', $resetValue)]; } diff --git a/Model/Layer/Filter/Price.php b/Model/Layer/Filter/Price.php index 01ee9b261..745be3a9f 100644 --- a/Model/Layer/Filter/Price.php +++ b/Model/Layer/Filter/Price.php @@ -4,6 +4,11 @@ use Algolia\AlgoliaSearch\Helper\ConfigHelper; +/** + * @method $this setMinValue(float $value) + * @method $this setMaxValue(float $value) + * @method $this setCurrentValue(array $value) + */ class Price extends \Magento\CatalogSearch\Model\Layer\Filter\Price { /** @var \Magento\Catalog\Model\Layer\Filter\DataProvider\Price */ @@ -111,7 +116,7 @@ protected function _getItemsData() if (mb_strpos($key, '_') === false) { continue; } - $data[] = $this->prepareData($key, $count, $data); + $data[] = $this->prepareData($key, $count); } } diff --git a/Model/Observer/SaveSettings.php b/Model/Observer/SaveSettings.php index 53ef080c4..aacbaa8bf 100755 --- a/Model/Observer/SaveSettings.php +++ b/Model/Observer/SaveSettings.php @@ -2,6 +2,7 @@ namespace Algolia\AlgoliaSearch\Model\Observer; +use Algolia\AlgoliaSearch\Model\ConfigurationTracker; use Algolia\AlgoliaSearch\Model\IndicesConfigurator; use AlgoliaSearch\AlgoliaException; use Magento\Framework\Event\Observer; @@ -16,10 +17,17 @@ class SaveSettings implements ObserverInterface /** @var IndicesConfigurator */ private $indicesConfigurator; - public function __construct(StoreManagerInterface $storeManager, IndicesConfigurator $indicesConfigurator) - { + /** @var ConfigurationTracker */ + private $configurationTracker; + + public function __construct( + StoreManagerInterface $storeManager, + IndicesConfigurator $indicesConfigurator, + ConfigurationTracker $configurationTracker + ) { $this->storeManager = $storeManager; $this->indicesConfigurator = $indicesConfigurator; + $this->configurationTracker = $configurationTracker; } /** @@ -29,10 +37,11 @@ public function __construct(StoreManagerInterface $storeManager, IndicesConfigur */ public function execute(Observer $observer) { - foreach ($this->storeManager->getStores() as $store) { - if ($store->getIsActive()) { - $this->indicesConfigurator->saveConfigurationToAlgolia($store->getId()); - } + $storeIds = array_keys($this->storeManager->getStores()); + + foreach ($storeIds as $storeId) { + $this->indicesConfigurator->saveConfigurationToAlgolia($storeId); + $this->configurationTracker->trackConfiguration($storeId); } } } diff --git a/Model/Source/Facets.php b/Model/Source/Facets.php index 1dfcc49d0..03c42e838 100755 --- a/Model/Source/Facets.php +++ b/Model/Source/Facets.php @@ -65,7 +65,7 @@ protected function getTableData() if ($this->isQueryRulesEnabled()) { $config['create_rule'] = [ 'label' => 'Create Query rule?', - 'values' => ['1' => 'Yes', '2' => 'No'], + 'values' => ['2' => 'No', '1' => 'Yes'], ]; } diff --git a/Plugin/BackendFilterRendererPlugin.php b/Plugin/BackendFilterRendererPlugin.php index dea707e57..3a9435aa9 100755 --- a/Plugin/BackendFilterRendererPlugin.php +++ b/Plugin/BackendFilterRendererPlugin.php @@ -11,6 +11,12 @@ class BackendFilterRendererPlugin /** @var LayoutInterface */ protected $layout; + /** @var StoreManagerInterface */ + protected $storeManager; + + /** @var ConfigHelper */ + protected $configHelper; + /** @var string */ protected $defaultBlock = \Algolia\AlgoliaSearch\Block\Navigation\Renderer\DefaultRenderer::class; @@ -23,9 +29,6 @@ class BackendFilterRendererPlugin /** @var string */ protected $sliderBlock = \Algolia\AlgoliaSearch\Block\Navigation\Renderer\SliderRenderer::class; - /** @var ConfigHelper */ - private $configHelper; - /** * @param LayoutInterface $layout * @param StoreManagerInterface $storeManager @@ -37,8 +40,8 @@ public function __construct( ConfigHelper $configHelper ) { $this->layout = $layout; - $this->configHelper = $configHelper; $this->storeManager = $storeManager; + $this->configHelper = $configHelper; } /** diff --git a/README.md b/README.md index cf3e4351e..33ab7b468 100755 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ Algolia Search for Magento 2 ================== -![Latest version](https://img.shields.io/badge/latest-1.12.0-green.svg) -![Magento 2](https://img.shields.io/badge/Magento-%3E=2.1-blue.svg) -![Magento 2](https://img.shields.io/badge/Magento-%3C%202.3.2-blue.svg) -![PHP >= 5.6.5](https://img.shields.io/badge/PHP-%3E=5.6-green.svg) +![Latest version](https://img.shields.io/badge/latest-1.12.1-green.svg) +![Magento 2](https://img.shields.io/badge/Magento-%3E=2.2-blue.svg) +![PHP >= 7.0.6](https://img.shields.io/badge/PHP-%3E=7.0-green.svg) + [![CircleCI](https://circleci.com/gh/algolia/algoliasearch-magento-2/tree/master.svg?style=svg)](https://circleci.com/gh/algolia/algoliasearch-magento-2/tree/master) ------- diff --git a/Setup/UpgradeSchema.php b/Setup/UpgradeSchema.php index a3b605fa9..c9baa31d0 100644 --- a/Setup/UpgradeSchema.php +++ b/Setup/UpgradeSchema.php @@ -7,16 +7,34 @@ use Magento\Framework\App\Config\ConfigResource\ConfigInterface; use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\DB\Ddl\Table; +use Magento\Framework\Indexer\IndexerInterfaceFactory; +use Magento\Framework\Mview\View\SubscriptionFactory; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; use Magento\Framework\Setup\UpgradeSchemaInterface; class UpgradeSchema implements UpgradeSchemaInterface { + /** + * @var ConfigInterface + */ private $config; + /** + * @var IndexerInterfaceFactory + */ + private $indexerFactory; + + /** + * @var ProductMetadataInterface + */ private $productMetadata; + /** + * @var SubscriptionFactory + */ + private $subscriptionFactory; + private $defaultConfigData = [ 'algoliasearch_credentials/credentials/enable_backend' => '1', 'algoliasearch_credentials/credentials/enable_frontend' => '1', @@ -242,10 +260,16 @@ class UpgradeSchema implements UpgradeSchemaInterface ], ]; - public function __construct(ConfigInterface $config, ProductMetadataInterface $productMetadata) - { + public function __construct( + ConfigInterface $config, + IndexerInterfaceFactory $indexerFactory, + ProductMetadataInterface $productMetadata, + SubscriptionFactory $subscriptionFactory + ) { $this->config = $config; + $this->indexerFactory = $indexerFactory; $this->productMetadata = $productMetadata; + $this->subscriptionFactory = $subscriptionFactory; $this->serializeDefaultArrayConfigData(); $this->mergeDefaultDataWithArrayData(); @@ -563,6 +587,20 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con $connection->createTable($table); } + if (version_compare($context->getVersion(), '1.12.1', '<')) { + // @see \Magento\Framework\Mview\View::unsubscribe + /** @var \Magento\Framework\Indexer\IndexerInterface $indexer */ + $indexer = $this->indexerFactory->create()->load('algolia_products'); + $subscriptionInstance = $this->subscriptionFactory->create( + [ + 'view' => $indexer->getView(), + 'tableName' => 'catalog_product_index_price', + 'columnName' => 'entity_id', + ] + ); + $subscriptionInstance->remove(); + } + $setup->endSetup(); } diff --git a/Test/Integration/CategoriesIndexingTest.php b/Test/Integration/CategoriesIndexingTest.php index ab5cfefa0..f6452bce7 100644 --- a/Test/Integration/CategoriesIndexingTest.php +++ b/Test/Integration/CategoriesIndexingTest.php @@ -15,7 +15,10 @@ public function testCategories() public function testDefaultIndexableAttributes() { - $this->setConfig('algoliasearch_categories/categories/category_additional_attributes', serialize([])); + $this->setConfig( + 'algoliasearch_categories/categories/category_additional_attributes', + $this->getSerializer()->serialize([]) + ); /** @var Category $categoriesIndexer */ $categoriesIndexer = $this->getObjectManager()->create('\Algolia\AlgoliaSearch\Model\Indexer\Category'); diff --git a/Test/Integration/ConfigTest.php b/Test/Integration/ConfigTest.php index 0c3b87d5f..aaeab7b37 100644 --- a/Test/Integration/ConfigTest.php +++ b/Test/Integration/ConfigTest.php @@ -65,7 +65,7 @@ public function testAutomaticalSetOfCategoriesFacet() } } - $this->setConfig('algoliasearch_instant/instant/facets', serialize($facets)); + $this->setConfig('algoliasearch_instant/instant/facets', $this->getSerializer()->serialize($facets)); // Set don't replace category pages with Algolia - categories attribute shouldn't be included in facets $this->setConfig('algoliasearch_instant/instant/replace_categories', '0'); @@ -172,7 +172,7 @@ private function replicaCreationTest($withCustomerGroups = false) ]; $this->setConfig('algoliasearch_instant/instant/is_instant_enabled', '1'); // Needed to set replicas to Algolia - $this->setConfig('algoliasearch_instant/instant/sorts', serialize($sortingIndicesData)); + $this->setConfig('algoliasearch_instant/instant/sorts', $this->getSerializer()->serialize($sortingIndicesData)); $this->setConfig('algoliasearch_advanced/advanced/customer_groups_enable', $enableCustomGroups); $sortingIndicesWithRankingWhichShouldBeCreated = [ diff --git a/Test/Integration/PagesIndexingTest.php b/Test/Integration/PagesIndexingTest.php index 976d16a25..db6005907 100644 --- a/Test/Integration/PagesIndexingTest.php +++ b/Test/Integration/PagesIndexingTest.php @@ -9,7 +9,10 @@ class PagesIndexingTest extends IndexingTestCase { public function testOnlyOnStockProducts() { - $this->setConfig('algoliasearch_autocomplete/autocomplete/excluded_pages', serialize([])); + $this->setConfig( + 'algoliasearch_autocomplete/autocomplete/excluded_pages', + $this->getSerializer()->serialize([]) + ); /** @var Page $indexer */ $indexer = $this->getObjectManager()->create('\Algolia\AlgoliaSearch\Model\Indexer\Page'); @@ -23,7 +26,10 @@ public function testExcludedPages() ['attribute' => 'no-route'], ['attribute' => 'home'], ]; - $this->setConfig('algoliasearch_autocomplete/autocomplete/excluded_pages', serialize($excludedPages)); + $this->setConfig( + 'algoliasearch_autocomplete/autocomplete/excluded_pages', + $this->getSerializer()->serialize($excludedPages) + ); /** @var Page $indexer */ $indexer = $this->getObjectManager()->create('\Algolia\AlgoliaSearch\Model\Indexer\Page'); diff --git a/Test/Integration/ProductsIndexingTest.php b/Test/Integration/ProductsIndexingTest.php index 292ce3b7a..a13ee4496 100644 --- a/Test/Integration/ProductsIndexingTest.php +++ b/Test/Integration/ProductsIndexingTest.php @@ -33,7 +33,7 @@ public function testIncludingOutOfStock() public function testDefaultIndexableAttributes() { - $empty = serialize([]); + $empty = $this->getSerializer()->serialize([]); $this->setConfig('algoliasearch_products/products/product_additional_attributes', $empty); $this->setConfig('algoliasearch_instant/instant/facets', $empty); @@ -89,7 +89,10 @@ public function testNoProtocolImageUrls() 'order' => 'unordered', ]; - $this->setConfig('algoliasearch_products/products/product_additional_attributes', serialize($additionAttributes)); + $this->setConfig( + 'algoliasearch_products/products/product_additional_attributes', + $this->getSerializer()->serialize($additionAttributes) + ); /** @var Product $indexer */ $indexer = $this->getObjectManager()->create('\Algolia\AlgoliaSearch\Model\Indexer\Product'); diff --git a/Test/Integration/TestCase.php b/Test/Integration/TestCase.php index 9178916ff..6a4f3d56b 100644 --- a/Test/Integration/TestCase.php +++ b/Test/Integration/TestCase.php @@ -149,4 +149,9 @@ private function getMagentoVersion() return $productMetadata->getVersion(); } + + protected function getSerializer() + { + return $this->getObjectManager()->get('Magento\Framework\Serialize\SerializerInterface'); + } } diff --git a/ViewModel/Adminhtml/Analytics/Form.php b/ViewModel/Adminhtml/Analytics/Form.php index e9aaf1f0c..b1106d093 100644 --- a/ViewModel/Adminhtml/Analytics/Form.php +++ b/ViewModel/Adminhtml/Analytics/Form.php @@ -2,7 +2,7 @@ namespace Algolia\AlgoliaSearch\ViewModel\Adminhtml\Analytics; -class Form extends Overview +class Form extends Overview implements \Magento\Framework\View\Element\Block\ArgumentInterface { /** * @return string diff --git a/ViewModel/Adminhtml/Analytics/Overview.php b/ViewModel/Adminhtml/Analytics/Overview.php index c231330f1..3b17bfb7c 100644 --- a/ViewModel/Adminhtml/Analytics/Overview.php +++ b/ViewModel/Adminhtml/Analytics/Overview.php @@ -9,7 +9,7 @@ use Magento\Framework\Exception\NoSuchEntityException; use Magento\Store\Api\Data\StoreInterface; -class Overview +class Overview implements \Magento\Framework\View\Element\Block\ArgumentInterface { const LIMIT_RESULTS = 5; @@ -173,6 +173,9 @@ public function getDailySearchData() $searches = $this->getSearchesByDates(); $users = $this->getUsersCountByDates(); $rates = $this->getResultRateByDates(); + $clickPosition = null; + $conversion = null; + $ctr = null; if ($this->isClickAnalyticsEnabled()) { $clickPosition = $this->getClickPositionByDates(); @@ -452,10 +455,10 @@ public function getMessagesHtml() ->createBlock(\Magento\Framework\View\Element\Messages::class); if (!$this->checkIsValidDateRange() && $this->isAnalyticsApiEnabled()) { - $noticeHtml = __('The selected date is out of your analytics retention window (%1 days), + $noticeHtml = __('The selected date is out of your analytics retention window (%1 days), your data might not be present anymore.', $this->getAnalyticRetentionDays()); $noticeHtml .= '
'; - $noticeHtml .= __('To increase your retention and access more data, you could switch to a + $noticeHtml .= __('To increase your retention and access more data, you could switch to a higher plan.', 'https://www.algolia.com/billing/overview/'); $messagesBlock->addNotice($noticeHtml); diff --git a/ViewModel/Adminhtml/Common.php b/ViewModel/Adminhtml/Common.php index 19dd2c1ea..432b06b1a 100644 --- a/ViewModel/Adminhtml/Common.php +++ b/ViewModel/Adminhtml/Common.php @@ -4,15 +4,29 @@ use Algolia\AlgoliaSearch\Helper\ConfigHelper; use Algolia\AlgoliaSearch\Helper\ProxyHelper; +use Algolia\AlgoliaSearch\Model\ExtensionNotification; +use Magento\Framework\Module\Manager as ModuleManager; +use Magento\Framework\ObjectManagerInterface; -class Common +class Common implements \Magento\Framework\View\Element\Block\ArgumentInterface { + const CATALOG_SEARCH_MYSQL_ENGINE = 'mysql'; + /** @var ProxyHelper */ private $proxyHelper; /** @var ConfigHelper */ private $configHelper; + /** @var ModuleManager */ + private $moduleManager; + + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var ExtensionNotification */ + private $extensionNotification; + /** @var array */ private $videosConfig = [ 'algoliasearch_credentials' => [ @@ -177,10 +191,22 @@ class Common public function __construct( ProxyHelper $proxyHelper, - ConfigHelper $configHelper + ConfigHelper $configHelper, + ModuleManager $moduleManager, + ObjectManagerInterface $objectManager, + ExtensionNotification $extensionNotification ) { $this->proxyHelper = $proxyHelper; $this->configHelper = $configHelper; + $this->moduleManager = $moduleManager; + $this->objectManager = $objectManager; + $this->extensionNotification = $extensionNotification; + } + + /** @return string */ + public function getApplicationId() + { + return $this->configHelper->getApplicationID(); } /** @return bool */ @@ -217,6 +243,39 @@ public function isClickAnalyticsTurnedOnInAdmin() return $this->configHelper->isClickConversionAnalyticsEnabled(); } + public function isMysqlUsed() + { + return $this->configHelper->getCatalogSearchEngine() === self::CATALOG_SEARCH_MYSQL_ENGINE; + } + + public function isEsWarningNeeded() + { + return !$this->isMysqlUsed(); + } + + public function isMsiExternalModuleNeeded() + { + // If Magento Inventory is not installed, no need for the external module + $hasMsiModule = $this->moduleManager->isEnabled('Magento_Inventory'); + if (! $hasMsiModule) { + return false; + } + + // If the external module is already installed, no need to do it again + $hasMsiExternalModule = $this->moduleManager->isEnabled('Algolia_AlgoliaSearchInventory'); + if ($hasMsiExternalModule) { + return false; + } + + // Module installation is only needed if there's more than one source + $sourceCollection = $this->objectManager->create('\Magento\Inventory\Model\ResourceModel\Source\Collection'); + if ($sourceCollection->getSize() <= 1) { + return false; + } + + return true; + } + /** @return array|void */ public function getVideoConfig($section) { @@ -247,4 +306,10 @@ public function getLinksConfig($section) return $config; } + + /** @return array|null */ + public function getNewVersionNotification() + { + return $this->extensionNotification->checkVersion(); + } } diff --git a/ViewModel/Adminhtml/Landingpage/Suggestions.php b/ViewModel/Adminhtml/Landingpage/Suggestions.php index 1354bed08..8bba04967 100644 --- a/ViewModel/Adminhtml/Landingpage/Suggestions.php +++ b/ViewModel/Adminhtml/Landingpage/Suggestions.php @@ -4,7 +4,7 @@ use Algolia\AlgoliaSearch\Model\ResourceModel\LandingPage\CollectionFactory as LandingPageCollectionFactory; -class Suggestions +class Suggestions implements \Magento\Framework\View\Element\Block\ArgumentInterface { /** @var LandingPageCollectionFactory */ private $landingPageCollectionFactory; diff --git a/ViewModel/Adminhtml/Merchandising/Page.php b/ViewModel/Adminhtml/Merchandising/Page.php index 41702c30d..33193e747 100644 --- a/ViewModel/Adminhtml/Merchandising/Page.php +++ b/ViewModel/Adminhtml/Merchandising/Page.php @@ -4,7 +4,7 @@ use Algolia\AlgoliaSearch\Helper\ProxyHelper; -class Page +class Page implements \Magento\Framework\View\Element\Block\ArgumentInterface { /** @var ProxyHelper */ private $proxyHelper; diff --git a/ViewModel/Adminhtml/Query/Suggestions.php b/ViewModel/Adminhtml/Query/Suggestions.php index 9a2df5f0a..392f869e7 100644 --- a/ViewModel/Adminhtml/Query/Suggestions.php +++ b/ViewModel/Adminhtml/Query/Suggestions.php @@ -4,7 +4,7 @@ use Algolia\AlgoliaSearch\Model\ResourceModel\Query\CollectionFactory as QueryCollectionFactory; -class Suggestions +class Suggestions implements \Magento\Framework\View\Element\Block\ArgumentInterface { /** @var QueryCollectionFactory */ private $queryCollectionFactory; diff --git a/ViewModel/Adminhtml/Support/Contact.php b/ViewModel/Adminhtml/Support/Contact.php index 20cc7e502..89d5c847a 100644 --- a/ViewModel/Adminhtml/Support/Contact.php +++ b/ViewModel/Adminhtml/Support/Contact.php @@ -8,7 +8,7 @@ use Magento\Framework\Module\ModuleListInterface; use Magento\User\Model\User; -class Contact +class Contact implements \Magento\Framework\View\Element\Block\ArgumentInterface { /** @var BackendView */ private $backendView; diff --git a/ViewModel/Adminhtml/Support/Overview.php b/ViewModel/Adminhtml/Support/Overview.php index 318a4ddce..257688b56 100644 --- a/ViewModel/Adminhtml/Support/Overview.php +++ b/ViewModel/Adminhtml/Support/Overview.php @@ -2,12 +2,11 @@ namespace Algolia\AlgoliaSearch\ViewModel\Adminhtml\Support; -use Algolia\AlgoliaSearch\Block\Adminhtml\BaseAdminTemplate; use Algolia\AlgoliaSearch\Helper\SupportHelper; use Algolia\AlgoliaSearch\ViewModel\Adminhtml\BackendView; use Magento\Backend\Block\Template; -class Overview +class Overview implements \Magento\Framework\View\Element\Block\ArgumentInterface { /** @var BackendView */ private $backendView; @@ -50,13 +49,4 @@ public function getLegacyVersionHtml() return $block->toHtml(); } - - public function getContactHtml() - { - /** @var BaseAdminTemplate $block */ - $block = $this->backendView->getLayout()->createBlock(BaseAdminTemplate::class); - $block->setTemplate('Algolia_AlgoliaSearch::support/contact.phtml'); - - return $block->toHtml(); - } } diff --git a/composer.json b/composer.json index a2c4516c5..5bfd3eafd 100755 --- a/composer.json +++ b/composer.json @@ -3,16 +3,19 @@ "description": "Algolia Search integration for Magento 2", "type": "magento2-module", "license": ["MIT"], - "version": "1.12.0", + "version": "1.12.1", "require": { - "php": "~5.6.5|~7.0|~7.1|~7.2|~7.3", - "magento/framework": "~100.1|~101.0|~102.0", + "php": "~7.0|~7.1|~7.2|~7.3", + "magento/framework": "~101.0|~102.0", "algolia/algoliasearch-client-php": ">=1.27.0 <2.0", "ext-json": "*", "ext-PDO": "*", "ext-mbstring": "*", "ext-dom": "*" }, + "suggest": { + "algolia/algoliasearch-magento-2-es-compatibility": "Algolia Search ES Compatibility module for Magento >=2.3.1|>=2.2.8" + }, "repositories": [ { "type": "composer", diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index dab6c64f2..dc99496e0 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -249,13 +249,13 @@ - + Magento\Config\Model\Config\Source\Yesno If you turn on this feature, please make sure that every attribute you choose in the facet listing below is configured as "Use in Layered Navigation" for categories and "Use in Search Result Layered Navigation" for Catalog Search in Stores > Attributes > Product > "Storefront Properties" panel of attribute configuration. +
]]>
diff --git a/etc/di.xml b/etc/di.xml index 56cc975f0..f9f6c2c1d 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -99,4 +99,9 @@ Algolia\AlgoliaSearch\QueryImageUpload + + + Algolia\AlgoliaSearch\QueryImageUpload + + diff --git a/etc/module.xml b/etc/module.xml index 46b003c01..e0bb92ca1 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,8 +1,25 @@ - + + + + + + + + + + + + + + + + + + @@ -11,4 +28,4 @@ - \ No newline at end of file + diff --git a/etc/mview.xml b/etc/mview.xml index fc73c4a06..b968d66a9 100755 --- a/etc/mview.xml +++ b/etc/mview.xml @@ -35,7 +35,6 @@
-
\ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon index 61d28786d..95a187aa3 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,6 @@ parameters: - level: 0 + level: 1 + reportUnmatchedIgnoredErrors: false paths: - vendor/algolia/algoliasearch-magento-2/Adapter - vendor/algolia/algoliasearch-magento-2/Api @@ -17,16 +18,4 @@ parameters: - vendor/algolia/algoliasearch-magento-2/ViewModel - vendor/algolia/algoliasearch-magento-2/registration.php ignoreErrors: - - '#(class|type) Magento\\\S*Factory#i' - - '#(class|type) Algolia\\\S*Factory#i' - '#Call to static method getObjectManager\(\) on an unknown class Magento\\TestFramework\\Helper\\Bootstrap.#' - - '#Access to an undefined property Algolia\\AlgoliaSearch\\Plugin\\BackendFilterRendererPlugin::\$storeManager.#' - - '#Method Algolia\\AlgoliaSearch\\Model\\Layer\\Filter\\Price::prepareData\(\) invoked with 3 parameters, 2 required.#' - - '#Method Algolia\\AlgoliaSearch\\Model\\Layer\\Filter\\Decimal::prepareData\(\) invoked with 3 parameters, 2 required.#' - - '#Parameter \$clientFactory of method Algolia\\AlgoliaSearch\\Helper\\AlgoliaHelper::__construct\(\) has invalid typehint type AlgoliaSearch\\ClientFactory.#' - - '#Return typehint of method Algolia\\AlgoliaSearch\\Controller\\Adminhtml\\Queue\\AbstractAction::initJob\(\) has invalid type Algolia\\AlgoliaSearch\\Model.#' - - '#Access to an undefined property Algolia\\AlgoliaSearch\\Controller\\Adminhtml\\Query\\Save::\$imageUploader.#' - - '#Undefined variable: \$data#' - - '#Access to an undefined property Algolia\\AlgoliaSearch\\Block\\Navigation\\Renderer\\SliderRenderer::\$filter.#' - - '#Access to an undefined property Algolia\\AlgoliaSearch\\Block\\Navigation\\Renderer\\DefaultRenderer::\$filter.#' - - '#Access to an undefined property Algolia\\AlgoliaSearch\\Block\\Navigation\\Renderer\\CategoryRenderer::\$filter.#' diff --git a/view/adminhtml/layout/algolia_algoliasearch_analytics_index.xml b/view/adminhtml/layout/algolia_algoliasearch_analytics_index.xml index c2f74a255..75bdad6d5 100644 --- a/view/adminhtml/layout/algolia_algoliasearch_analytics_index.xml +++ b/view/adminhtml/layout/algolia_algoliasearch_analytics_index.xml @@ -14,10 +14,18 @@ Default Store View - + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Analytics\Form + + - + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Analytics\Overview + + diff --git a/view/adminhtml/layout/algolia_algoliasearch_landingpage_index.xml b/view/adminhtml/layout/algolia_algoliasearch_landingpage_index.xml index 7d45f2503..51137bda6 100644 --- a/view/adminhtml/layout/algolia_algoliasearch_landingpage_index.xml +++ b/view/adminhtml/layout/algolia_algoliasearch_landingpage_index.xml @@ -6,11 +6,11 @@ - + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Landingpage\Suggestions + + diff --git a/view/adminhtml/layout/algolia_algoliasearch_merchandising_index.xml b/view/adminhtml/layout/algolia_algoliasearch_merchandising_index.xml index 0977d2c0f..a8c49fc48 100644 --- a/view/adminhtml/layout/algolia_algoliasearch_merchandising_index.xml +++ b/view/adminhtml/layout/algolia_algoliasearch_merchandising_index.xml @@ -7,9 +7,14 @@ - - + + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Merchandising\Page + + + diff --git a/view/adminhtml/layout/algolia_algoliasearch_query_index.xml b/view/adminhtml/layout/algolia_algoliasearch_query_index.xml index 82d39dce3..3158d24f9 100644 --- a/view/adminhtml/layout/algolia_algoliasearch_query_index.xml +++ b/view/adminhtml/layout/algolia_algoliasearch_query_index.xml @@ -6,11 +6,11 @@ - + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Query\Suggestions + + diff --git a/view/adminhtml/layout/algolia_algoliasearch_support_contact.xml b/view/adminhtml/layout/algolia_algoliasearch_support_contact.xml index d1dbf8649..27ffd89b0 100644 --- a/view/adminhtml/layout/algolia_algoliasearch_support_contact.xml +++ b/view/adminhtml/layout/algolia_algoliasearch_support_contact.xml @@ -7,7 +7,11 @@ - + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Support\Contact + + diff --git a/view/adminhtml/layout/algolia_algoliasearch_support_index.xml b/view/adminhtml/layout/algolia_algoliasearch_support_index.xml index 83241ee6d..4588dbece 100644 --- a/view/adminhtml/layout/algolia_algoliasearch_support_index.xml +++ b/view/adminhtml/layout/algolia_algoliasearch_support_index.xml @@ -8,7 +8,16 @@ - + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Support\Overview + + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Support\Contact + + + diff --git a/view/adminhtml/layout/default.xml b/view/adminhtml/layout/default.xml index 5cff37748..d4ac81f3f 100755 --- a/view/adminhtml/layout/default.xml +++ b/view/adminhtml/layout/default.xml @@ -5,6 +5,11 @@ - + + + + Algolia\AlgoliaSearch\ViewModel\Adminhtml\Common + + diff --git a/view/adminhtml/requirejs-config.js b/view/adminhtml/requirejs-config.js index 37031e717..53e81fe9f 100644 --- a/view/adminhtml/requirejs-config.js +++ b/view/adminhtml/requirejs-config.js @@ -1,5 +1,5 @@ var config = { - 'paths': { - 'algoliaAdminBundle': 'Algolia_AlgoliaSearch/algoliaAdminBundle.min' + paths: { + algoliaAdminBundle: 'Algolia_AlgoliaSearch/algoliaAdminBundle.min' } -}; +}; \ No newline at end of file diff --git a/view/adminhtml/templates/analytics/form.phtml b/view/adminhtml/templates/analytics/form.phtml index 989e4e9b1..f7e4fbab8 100644 --- a/view/adminhtml/templates/analytics/form.phtml +++ b/view/adminhtml/templates/analytics/form.phtml @@ -1,6 +1,6 @@ getViewModel(); diff --git a/view/adminhtml/templates/analytics/overview.phtml b/view/adminhtml/templates/analytics/overview.phtml index 466c7c46d..c745ad839 100644 --- a/view/adminhtml/templates/analytics/overview.phtml +++ b/view/adminhtml/templates/analytics/overview.phtml @@ -1,6 +1,6 @@ getViewModel(); @@ -111,7 +111,7 @@ $view = $this->getViewModel(); - diff --git a/view/adminhtml/templates/landingpage/suggestions.phtml b/view/adminhtml/templates/landingpage/suggestions.phtml index 4cbb51fb4..5abb1acae 100644 --- a/view/adminhtml/templates/landingpage/suggestions.phtml +++ b/view/adminhtml/templates/landingpage/suggestions.phtml @@ -1,6 +1,6 @@ getViewModel(); @@ -25,6 +25,6 @@ $bookIllustration = $this->getViewFileUrl('Algolia_AlgoliaSearch::images/icon-bo

The Landing Page Builder allows you to easily create customised landing pages out of search queries.

It is a powerful marketing tool to promote products, with a strong focus on SEO. To find out more about the Landing Page Builder, please see our documentation.

-

Create a new landing page

+

Create a new landing page

\ No newline at end of file diff --git a/view/adminhtml/templates/merchandising/page.phtml b/view/adminhtml/templates/merchandising/page.phtml index e2871a429..e43b21e3b 100644 --- a/view/adminhtml/templates/merchandising/page.phtml +++ b/view/adminhtml/templates/merchandising/page.phtml @@ -1,4 +1,4 @@ - + getViewModel() ?>
diff --git a/view/adminhtml/templates/query/access_denied.phtml b/view/adminhtml/templates/query/access_denied.phtml index e0fd8f834..80b3c5ec4 100644 --- a/view/adminhtml/templates/query/access_denied.phtml +++ b/view/adminhtml/templates/query/access_denied.phtml @@ -16,6 +16,6 @@ $starsIllustration = $this->getViewFileUrl('Algolia_AlgoliaSearch::images/icon-s
-

To get access to this Algolia feature, please consider upgrading to a higher plan.

+

To get access to this Algolia feature, please consider upgrading to a higher plan.

diff --git a/view/adminhtml/templates/query/edit/merchandising.phtml b/view/adminhtml/templates/query/edit/merchandising.phtml index 6e41ea6c8..9ed9d5314 100644 --- a/view/adminhtml/templates/query/edit/merchandising.phtml +++ b/view/adminhtml/templates/query/edit/merchandising.phtml @@ -189,8 +189,17 @@ $isConfig = [ requirejs(['algoliaAdminBundle'], function (algoliaAdminBundle) { algoliaAdminBundle.$(function ($) { var config = ; + config.searchFunction = function(helper) { + if (helper.state.query !== '') { + algoliaEventsTracking.postEvent('Searched Keyword', { + source: 'magento2.querymerch.edit', + search: helper.state.query + }); + } + helper.search(); + }; - var search = algoliaAdminBundle.instantsearch(); + var search = algoliaAdminBundle.instantsearch(config); // initialize hits widget search.addWidget( diff --git a/view/adminhtml/templates/query/suggestions.phtml b/view/adminhtml/templates/query/suggestions.phtml index b9ae42182..5d3f1a307 100644 --- a/view/adminhtml/templates/query/suggestions.phtml +++ b/view/adminhtml/templates/query/suggestions.phtml @@ -1,6 +1,6 @@ getViewModel(); @@ -23,8 +23,8 @@ $bookIllustration = $this->getViewFileUrl('Algolia_AlgoliaSearch::images/icon-bo

Easily promote or demote products for a search. Based on Algolia's Query rules, the Query Merchandiser allows you to enchance the ranking behaviour for specific search queries.

-

Merchandising a query will create a new query rule (which are part of your Algolia plan). To find out more about the Query Merchandiser, please see our documentation.

+

Merchandising a query will create a new query rule (which are part of your Algolia plan). To find out more about the Query Merchandiser, please see our documentation.

-

Merchandise a new query

+

Merchandise a new query

\ No newline at end of file diff --git a/view/adminhtml/templates/support/contact.phtml b/view/adminhtml/templates/support/contact.phtml index 5e747e425..f560c1608 100644 --- a/view/adminhtml/templates/support/contact.phtml +++ b/view/adminhtml/templates/support/contact.phtml @@ -1,6 +1,6 @@ getViewModel(); diff --git a/view/adminhtml/templates/support/overview.phtml b/view/adminhtml/templates/support/overview.phtml index dfbd585fb..2c8ab6fcc 100644 --- a/view/adminhtml/templates/support/overview.phtml +++ b/view/adminhtml/templates/support/overview.phtml @@ -1,6 +1,6 @@ getViewModel(); @@ -252,7 +252,7 @@ $videoFeatures = $this->getViewFileUrl('Algolia_AlgoliaSearch::images/video-feat
- getContactHtml(); ?> + getChildHtml('support_contact') ?>
diff --git a/view/adminhtml/templates/tracking.phtml b/view/adminhtml/templates/tracking.phtml new file mode 100644 index 000000000..ce1ab066a --- /dev/null +++ b/view/adminhtml/templates/tracking.phtml @@ -0,0 +1,372 @@ + \ No newline at end of file diff --git a/view/adminhtml/templates/ui/upsell-plan.phtml b/view/adminhtml/templates/ui/upsell-plan.phtml index af5d5a48b..3e38c1abd 100644 --- a/view/adminhtml/templates/ui/upsell-plan.phtml +++ b/view/adminhtml/templates/ui/upsell-plan.phtml @@ -1,4 +1,4 @@
-

To get access to this Algolia feature, please consider upgrading to a higher plan.

+

To get access to this Algolia feature, please consider upgrading to a higher plan.

\ No newline at end of file diff --git a/view/adminhtml/web/js/support.js b/view/adminhtml/web/js/support.js index f002b09cb..357d38470 100644 --- a/view/adminhtml/web/js/support.js +++ b/view/adminhtml/web/js/support.js @@ -24,7 +24,15 @@ requirejs(['algoliaAdminBundle'], function(algoliaBundle) { filters: 'NOT tags:m1', hitsPerPage: 10 }, - searchFunction: searchFunction + searchFunction: function(helper) { + if (helper.state.query !== '') { + algoliaEventsTracking.postEvent('Performed Search', { + source: 'magento2.help.search', + search: helper.state.query + }); + } + helper.search(); + } }); documentationSearch.addWidget(getSearchBoxWidget(false)); @@ -273,7 +281,7 @@ requirejs(['algoliaAdminBundle'], function(algoliaBundle) { return algoliaBundle.instantsearch.widgets.searchBox({ container: '#search_box', placeholder: 'Search a topic, i.e. "images not showing"', - reset: showIcons, + reset: false, magnifier: showIcons }); } diff --git a/view/frontend/templates/autocomplete/category.phtml b/view/frontend/templates/autocomplete/category.phtml index d49f44f16..06d7b2f45 100644 --- a/view/frontend/templates/autocomplete/category.phtml +++ b/view/frontend/templates/autocomplete/category.phtml @@ -3,7 +3,7 @@ {{#image_url}}
- + {{{name}}}
{{/image_url}} diff --git a/view/frontend/templates/autocomplete/product.phtml b/view/frontend/templates/autocomplete/product.phtml index 61afb436d..95f25f302 100644 --- a/view/frontend/templates/autocomplete/product.phtml +++ b/view/frontend/templates/autocomplete/product.phtml @@ -12,7 +12,7 @@ $tierFormatedVar = 'price' . $priceKey . '_tier_formated'