From d8e0fe5d63b7bfd25ed019c9489fe46d06f0bb25 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Thu, 11 Jun 2020 22:53:10 +0200 Subject: [PATCH 01/11] Started working on category url key checker, the empty url key check is done, duplicate url key is next (will need to check on calculated path I think). --- Checker/Catalog/Category/UrlKey.php | 38 ++++++ .../Category/UrlKey/DuplicateUrlKey.php | 30 +++++ .../Catalog/Category/UrlKey/EmptyUrlKey.php | 112 ++++++++++++++++++ Console/Command/CheckCategoryUrlKeys.php | 80 +++++++++++++ Updater/Catalog/Category/UrlKey.php | 52 ++++++++ etc/di.xml | 1 + 6 files changed, 313 insertions(+) create mode 100644 Checker/Catalog/Category/UrlKey.php create mode 100644 Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php create mode 100644 Checker/Catalog/Category/UrlKey/EmptyUrlKey.php create mode 100644 Console/Command/CheckCategoryUrlKeys.php create mode 100644 Updater/Catalog/Category/UrlKey.php diff --git a/Checker/Catalog/Category/UrlKey.php b/Checker/Catalog/Category/UrlKey.php new file mode 100644 index 0000000..81c5f25 --- /dev/null +++ b/Checker/Catalog/Category/UrlKey.php @@ -0,0 +1,38 @@ +duplicateUrlKeyChecker = $duplicateUrlKeyChecker; + $this->emptyUrlKeyChecker = $emptyUrlKeyChecker; + } + + /** + * @return array> + */ + public function execute(): array + { + $categoryData = array_merge( + $this->duplicateUrlKeyChecker->execute(), + $this->emptyUrlKeyChecker->execute() + ); + + return $categoryData; + } +} diff --git a/Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php b/Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php new file mode 100644 index 0000000..bf9fbf8 --- /dev/null +++ b/Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php @@ -0,0 +1,30 @@ +> + */ + public function execute(): array + { + $categoryData = $this->checkForDuplicatedUrlKeyAttributeValues(); + + return $categoryData; + } + + /** + * @return array> + */ + private function checkForDuplicatedUrlKeyAttributeValues(): array + { + $categoriesWithProblems = []; + + // TODO !!!!! + + return $categoriesWithProblems; + } +} diff --git a/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php b/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php new file mode 100644 index 0000000..68f288b --- /dev/null +++ b/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php @@ -0,0 +1,112 @@ +storesUtil = $storesUtil; + $this->categoryCollectionFactory = $categoryCollectionFactory; + $this->attributeScopeOverriddenValueFactory = $attributeScopeOverriddenValueFactory; + } + + /** + * @return array> + */ + public function execute(): array + { + $categoryData = $this->checkForEmptyUrlKeyAttributeValues(); + + return $categoryData; + } + + /** + * @return array> + */ + private function checkForEmptyUrlKeyAttributeValues(): array + { + $categoriesWithProblems = []; + + $storeIds = $this->storesUtil->getAllStoreIds(); + foreach ($storeIds as $storeId) { + // we need a left join when using the non-default store view + // and especially for the case where storeId 0 doesn't have a value set for this attribute + $joinType = $storeId === Store::DEFAULT_STORE_ID ? 'inner' : 'left'; + + $collection = $this->categoryCollectionFactory->create(); + $collection + ->setStoreId($storeId) + ->addAttributeToSelect(UrlKeyChecker::URL_KEY_ATTRIBUTE) + ->addAttributeToFilter('entity_id', ['neq' => CategoryModel::TREE_ROOT_ID]) + ->addAttributeToFilter([ + [ + 'attribute' => UrlKeyChecker::URL_KEY_ATTRIBUTE, + 'null' => true, + ], + [ + 'attribute' => UrlKeyChecker::URL_KEY_ATTRIBUTE, + 'eq' => '', + ], + ], null, $joinType) + ; + + $categoriesWithProblems[] = $this->getCategoriesWithProblems($storeId, $collection); + } + + if (!empty($categoriesWithProblems)) { + $categoriesWithProblems = array_merge(...$categoriesWithProblems); + } + + return $categoriesWithProblems; + } + + /** + * @param CategoryCollection $collection + * + * @return array> + */ + private function getCategoriesWithProblems(int $storeId, CategoryCollection $collection): array + { + $problems = []; + + foreach ($collection as $category) { + $isOverridden = $this + ->attributeScopeOverriddenValueFactory + ->create() + ->containsValue(CategoryInterface::class, $category, UrlKeyChecker::URL_KEY_ATTRIBUTE, $storeId) + ; + + if ($isOverridden || $storeId === Store::DEFAULT_STORE_ID) { + $problems[] = [ + 'catId' => (int) $category->getEntityId(), + 'sku' => $category->getSku(), + 'storeId' => $storeId, + 'problem' => self::EMPTY_PROBLEM_DESCRIPTION, + ]; + } + } + + return $problems; + } +} diff --git a/Console/Command/CheckCategoryUrlKeys.php b/Console/Command/CheckCategoryUrlKeys.php new file mode 100644 index 0000000..be89104 --- /dev/null +++ b/Console/Command/CheckCategoryUrlKeys.php @@ -0,0 +1,80 @@ +appState = $appState; + $this->resultOutput = $resultOutput; + $this->urlKeyUpdater = $urlKeyUpdater; + $this->metaStorage = $metaStorage; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('catalog:category:integrity:urlkey'); + $this->setDescription('Checks data integrity of the values of the url_key category attribute.'); + $this->addOption( + 'force', + 'f', + InputOption::VALUE_NONE, + 'Force the command to run, even if it is already marked as already running' + ); + + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + $this->appState->setAreaCode(AppArea::AREA_CRONTAB); + + $force = $input->getOption('force'); + if ($force === true) { + $this->metaStorage->clearStatus(UrlKeyChecker::STORAGE_IDENTIFIER); + } + + $categoryData = $this->urlKeyUpdater->refresh(MetaStorage::INITIATOR_CLI); + $cliResult = $this->resultOutput->outputResult($categoryData, $output); + + $output->writeln( + "\nData was stored and you can now also review it in the admin of Magento" + ); + + return $cliResult; + } catch (\Throwable $ex) { + $output->writeln( + "An unexpected exception occured: '{$ex->getMessage()}'\n{$ex->getTraceAsString()}" + ); + } + + return Cli::RETURN_FAILURE; + } +} diff --git a/Updater/Catalog/Category/UrlKey.php b/Updater/Catalog/Category/UrlKey.php new file mode 100644 index 0000000..1ddc29a --- /dev/null +++ b/Updater/Catalog/Category/UrlKey.php @@ -0,0 +1,52 @@ +urlKeyChecker = $urlKeyChecker; + $this->storage = $storage; + $this->metaStorage = $metaStorage; + } + + /** + * @return array> + */ + public function refresh(string $initiator): array + { + $storageIdentifier = UrlKeyChecker::STORAGE_IDENTIFIER; + + if ($this->metaStorage->isRefreshing($storageIdentifier)) { + $errorMsg = __('We are already refreshing the category url key\'s, just have a little patience 🙂'); + + $this->metaStorage->setErrorMessage($storageIdentifier, (string) $errorMsg); + throw new AlreadyRefreshingException($errorMsg); + } + + $this->metaStorage->setErrorMessage($storageIdentifier, ''); + $this->metaStorage->setStartRefreshing($storageIdentifier, $initiator); + + $categoryData = $this->urlKeyChecker->execute(); + $this->storage->write($storageIdentifier, $categoryData); + + $this->metaStorage->setFinishedRefreshing($storageIdentifier); + + return $categoryData; + } +} diff --git a/etc/di.xml b/etc/di.xml index 1c5c283..2dc4565 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -6,6 +6,7 @@ Baldwin\UrlDataIntegrityChecker\Console\Command\CheckProductUrlKeys Baldwin\UrlDataIntegrityChecker\Console\Command\CheckProductUrlPaths + Baldwin\UrlDataIntegrityChecker\Console\Command\CheckCategoryUrlKeys Baldwin\UrlDataIntegrityChecker\Console\Command\CheckCategoryUrlPaths From 467db5fdae4e8eecc88a78338096e09add055d7d Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 12 Jun 2020 22:10:16 +0200 Subject: [PATCH 02/11] Categories don't have an sku, fixed stupid copy/paste error. --- Checker/Catalog/Category/UrlKey/EmptyUrlKey.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php b/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php index 68f288b..391f8b9 100644 --- a/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php +++ b/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php @@ -58,6 +58,7 @@ private function checkForEmptyUrlKeyAttributeValues(): array $collection ->setStoreId($storeId) ->addAttributeToSelect(UrlKeyChecker::URL_KEY_ATTRIBUTE) + ->addAttributeToSelect('name') ->addAttributeToFilter('entity_id', ['neq' => CategoryModel::TREE_ROOT_ID]) ->addAttributeToFilter([ [ @@ -100,7 +101,7 @@ private function getCategoriesWithProblems(int $storeId, CategoryCollection $col if ($isOverridden || $storeId === Store::DEFAULT_STORE_ID) { $problems[] = [ 'catId' => (int) $category->getEntityId(), - 'sku' => $category->getSku(), + 'name' => $category->getName(), 'storeId' => $storeId, 'problem' => self::EMPTY_PROBLEM_DESCRIPTION, ]; From f3760ab593a491d86eeb5edb1c8936b282a3b268 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 12 Jun 2020 22:14:26 +0200 Subject: [PATCH 03/11] Added duplicate url key checker for categories, this uses the calculated url path's to determine this. --- .../Category/UrlKey/DuplicateUrlKey.php | 73 ++++++++++++++++++- Checker/Catalog/Category/UrlPath.php | 4 +- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php b/Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php index bf9fbf8..9343c12 100644 --- a/Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php +++ b/Checker/Catalog/Category/UrlKey/DuplicateUrlKey.php @@ -4,8 +4,28 @@ namespace Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey; +use Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlPath as UrlPathChecker; +use Baldwin\UrlDataIntegrityChecker\Util\Stores as StoresUtil; + class DuplicateUrlKey { + const DUPLICATED_PROBLEM_DESCRIPTION = + '%s categories were found which have a duplicated url_key value: "%s" within the same parent.' + . ' Please fix because this will cause problems.'; + + private $storesUtil; + private $urlPathChecker; + private $urlPathsInfo; + + public function __construct( + StoresUtil $storesUtil, + UrlPathChecker $urlPathChecker + ) { + $this->storesUtil = $storesUtil; + $this->urlPathChecker = $urlPathChecker; + $this->urlPathsInfo = []; + } + /** * @return array> */ @@ -23,8 +43,59 @@ private function checkForDuplicatedUrlKeyAttributeValues(): array { $categoriesWithProblems = []; - // TODO !!!!! + $storeIds = $this->storesUtil->getAllStoreIds(); + foreach ($storeIds as $storeId) { + $categoryUrlPaths = $this->getCategoryUrlPathsByStoreId($storeId); + $urlPathsCount = array_count_values($categoryUrlPaths); + + foreach ($urlPathsCount as $urlPath => $count) { + if ($count === 1) { + continue; + } + + $categories = $this->urlPathsInfo[$urlPath]; + + foreach ($categories as $category) { + $categoriesWithProblems[] = [ + 'catId' => (int) $category->getEntityId(), + 'name' => $category->getName(), + 'storeId' => $storeId, + 'problem' => sprintf( + self::DUPLICATED_PROBLEM_DESCRIPTION, + $count, + $category->getUrlKey() + ), + ]; + } + } + } return $categoriesWithProblems; } + + /** + * @return array + */ + private function getCategoryUrlPathsByStoreId(int $storeId): array + { + $urlPaths = []; + + $categories = $this->urlPathChecker->getAllVisibleCategoriesWithStoreId($storeId); + foreach ($categories as $category) { + $urlPath = $this->urlPathChecker->getCalculatedUrlPathForCategory($category, $storeId); + + $rootCatId = 0; + $path = $category->getPath() ?: ''; + if (preg_match('#^(\d+)/(\d+)/.+#', $path, $matches) === 1) { + $rootCatId = $matches[2]; + } + + $urlPath = $rootCatId . UrlPathChecker::URL_PATH_SEPARATOR . $urlPath; + + $urlPaths[] = $urlPath; + $this->urlPathsInfo[$urlPath][] = $category; + } + + return $urlPaths; + } } diff --git a/Checker/Catalog/Category/UrlPath.php b/Checker/Catalog/Category/UrlPath.php index b00e77f..8483273 100644 --- a/Checker/Catalog/Category/UrlPath.php +++ b/Checker/Catalog/Category/UrlPath.php @@ -91,7 +91,7 @@ public function checkForIncorrectUrlPathAttributeValues(): array /** * @return CategoryCollection */ - private function getAllVisibleCategoriesWithStoreId(int $storeId): CategoryCollection + public function getAllVisibleCategoriesWithStoreId(int $storeId): CategoryCollection { $categories = $this->categoryCollectionFactory->create() ->addAttributeToSelect('name') @@ -111,7 +111,7 @@ private function doesCategoryUrlPathMatchCalculatedUrlPath(Category $category, i return $calculatedUrlPath === $currentUrlPath; } - private function getCalculatedUrlPathForCategory(Category $category, int $storeId): string + public function getCalculatedUrlPathForCategory(Category $category, int $storeId): string { if ($this->calculatedUrlPathPerCategoryAndStoreId === null) { $this->fetchAllCategoriesWithUrlPathCalculatedByUrlKey(); From cbadb92f911ab8f46df66d9275834f39a1ada36e Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 12 Jun 2020 22:52:49 +0200 Subject: [PATCH 04/11] Added admin grid & cronjob for category url key checker. --- .../Catalog/Category/UrlKey/Index.php | 36 +++++ .../Catalog/Category/UrlKey/Refresh.php | 61 +++++++++ Cron/CheckCategoryUrlKey.php | 26 ++++ Makefile | 2 + .../Catalog/Category/UrlKeyCollection.php | 126 ++++++++++++++++++ etc/adminhtml/menu.xml | 3 +- etc/crontab.xml | 3 + etc/di.xml | 1 + ...ychecker_catalog_category_urlkey_index.xml | 15 +++ ...tychecker_grid_catalog_category_urlkey.xml | 73 ++++++++++ 10 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 Controller/Adminhtml/Catalog/Category/UrlKey/Index.php create mode 100644 Controller/Adminhtml/Catalog/Category/UrlKey/Refresh.php create mode 100644 Cron/CheckCategoryUrlKey.php create mode 100644 Model/ResourceModel/Catalog/Category/UrlKeyCollection.php create mode 100644 view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_category_urlkey_index.xml create mode 100644 view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml diff --git a/Controller/Adminhtml/Catalog/Category/UrlKey/Index.php b/Controller/Adminhtml/Catalog/Category/UrlKey/Index.php new file mode 100644 index 0000000..3c3e47c --- /dev/null +++ b/Controller/Adminhtml/Catalog/Category/UrlKey/Index.php @@ -0,0 +1,36 @@ +resultPageFactory = $resultPageFactory; + } + + public function execute() + { + /** @var BackendResultPage */ + $resultPage = $this->resultPageFactory->create(); + $resultPage->setActiveMenu('Baldwin_UrlDataIntegrityChecker::catalog_category_urlkey'); + $resultPage->getConfig()->getTitle()->prepend('Data Integrity - Category Url Key'); + + return $resultPage; + } +} diff --git a/Controller/Adminhtml/Catalog/Category/UrlKey/Refresh.php b/Controller/Adminhtml/Catalog/Category/UrlKey/Refresh.php new file mode 100644 index 0000000..2ddfdc9 --- /dev/null +++ b/Controller/Adminhtml/Catalog/Category/UrlKey/Refresh.php @@ -0,0 +1,61 @@ +scheduleJob = $scheduleJob; + $this->metaStorage = $metaStorage; + } + + public function execute() + { + $scheduled = $this->scheduleJob->schedule(CheckCategoryUrlKeyCron::JOB_NAME); + + if ($scheduled) { + $this->getMessageManager()->addSuccess( + (string) __( + 'The refresh job was scheduled, please check back in a few moments to see the updated results' + ) + ); + + try { + $storageIdentifier = UrlKeyChecker::STORAGE_IDENTIFIER; + $this->metaStorage->setPending($storageIdentifier, MetaStorage::INITIATOR_CRON); + } catch (AlreadyRefreshingException $ex) { + $this->getMessageManager()->addError($ex->getMessage()); + } + } else { + $this->getMessageManager()->addError( + (string) __('Couldn\'t schedule refreshing due to some unknown error') + ); + } + + $redirect = $this->resultRedirectFactory->create(); + $redirect->setRefererUrl(); + + return $redirect; + } +} diff --git a/Cron/CheckCategoryUrlKey.php b/Cron/CheckCategoryUrlKey.php new file mode 100644 index 0000000..55c753f --- /dev/null +++ b/Cron/CheckCategoryUrlKey.php @@ -0,0 +1,26 @@ +urlKeyUpdater = $urlKeyUpdater; + } + + public function execute() + { + $this->urlKeyUpdater->refresh(MetaStorage::INITIATOR_CRON); + } +} diff --git a/Makefile b/Makefile index f3a7d42..af262d6 100644 --- a/Makefile +++ b/Makefile @@ -25,9 +25,11 @@ checkquality: xmllint --noout etc/di.xml # schema validation doesn't work here since the xsd includes another xsd .. xmllint --noout --schema vendor/magento/framework/Module/etc/module.xsd etc/module.xml + xmllint --noout view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_category_urlkey_index.xml # schema validation doesn't work here since the xsd includes another xsd .. xmllint --noout view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_category_urlpath_index.xml # schema validation doesn't work here since the xsd includes another xsd .. xmllint --noout view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_product_urlkey_index.xml # schema validation doesn't work here since the xsd includes another xsd .. xmllint --noout view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_product_urlpath_index.xml # schema validation doesn't work here since the xsd includes another xsd .. + xmllint --noout view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml # schema validation doesn't work here since the xsd includes another xsd .. xmllint --noout view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlpath.xml # schema validation doesn't work here since the xsd includes another xsd .. xmllint --noout view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlkey.xml # schema validation doesn't work here since the xsd includes another xsd .. xmllint --noout view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlpath.xml # schema validation doesn't work here since the xsd includes another xsd .. diff --git a/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php b/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php new file mode 100644 index 0000000..47e29fb --- /dev/null +++ b/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php @@ -0,0 +1,126 @@ +storage = $storage; + } + + /** + * @param bool $printQuery + * @param bool $logQuery + * + * @return UrlKeyCollection + */ + public function loadData($printQuery = false, $logQuery = false) + { + if (!$this->isLoaded()) { + $urlKeys = $this->storage->read(UrlKeyChecker::STORAGE_IDENTIFIER); + foreach ($urlKeys as $urlKey) { + $this->addItem($this->createDataObject($urlKey)); + } + + foreach ($this->_orders as $field => $direction) { + usort($this->_items, function ($itemA, $itemB) use ($field, $direction) { + $comparisonFieldA = $itemA->getData($field); + $comparisonFieldB = $itemB->getData($field); + + if ($direction === DataCollection::SORT_ORDER_ASC) { + return $comparisonFieldA <=> $comparisonFieldB; + } else { + return $comparisonFieldB <=> $comparisonFieldA; + } + }); + + break; // breaking after using one entry of $this->_orders + } + + $this->_setIsLoaded(); + + // page the data, need to do this after setting the data as loaded, + // otherwise the getCurPage would create a recursive problem + $startIndex = ($this->getCurPage() - 1) * $this->getPageSize(); + $this->_items = array_slice($this->_items, $startIndex, $this->getPageSize()); + } + + return $this; + } + + /** + * @param array $arguments + */ + public function createDataObject(array $arguments = []): DataObject + { + $obj = $this->_entityFactory->create($this->_itemObjectClass, ['data' => $arguments]); + + $attributes = []; + foreach ($arguments as $key => $value) { + $attribute = new AttributeValue([ + AttributeInterface::ATTRIBUTE_CODE => $key, + AttributeInterface::VALUE => $value, + ]); + + $attributes[] = $attribute; + } + $obj->setCustomAttributes($attributes); + + return $obj; + } + + public function setItems(array $items = null) + { + throw new LocalizedException(__('Not implemented: setItems!')); + } + + public function getAggregations() + { + throw new LocalizedException(__('Not implemented: getAggregations!')); + } + + public function setAggregations($aggregations) + { + throw new LocalizedException(__('Not implemented: setAggregations!')); + } + + public function getSearchCriteria() + { + throw new LocalizedException(__('Not implemented: getSearchCriteria!')); + } + + public function setSearchCriteria(SearchCriteriaInterface $searchCriteria) + { + throw new LocalizedException(__('Not implemented: setSearchCriteria!')); + } + + public function getTotalCount() + { + return $this->getSize(); + } + + public function setTotalCount($totalCount) + { + throw new LocalizedException(__('Not implemented: setTotalCount!')); + } +} diff --git a/etc/adminhtml/menu.xml b/etc/adminhtml/menu.xml index ef28071..4cb4a1f 100644 --- a/etc/adminhtml/menu.xml +++ b/etc/adminhtml/menu.xml @@ -1,8 +1,9 @@ - + + diff --git a/etc/crontab.xml b/etc/crontab.xml index 2ab7325..b86d46b 100644 --- a/etc/crontab.xml +++ b/etc/crontab.xml @@ -4,6 +4,9 @@ 10 2 * * * + + 15 2 * * * + 20 2 * * * diff --git a/etc/di.xml b/etc/di.xml index 2dc4565..216a63d 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -15,6 +15,7 @@ + Baldwin\UrlDataIntegrityChecker\Model\ResourceModel\Catalog\Category\UrlKeyCollection Baldwin\UrlDataIntegrityChecker\Model\ResourceModel\Catalog\Category\UrlPathCollection Baldwin\UrlDataIntegrityChecker\Model\ResourceModel\Catalog\Product\UrlKeyCollection Baldwin\UrlDataIntegrityChecker\Model\ResourceModel\Catalog\Product\UrlPathCollection diff --git a/view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_category_urlkey_index.xml b/view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_category_urlkey_index.xml new file mode 100644 index 0000000..a750ee4 --- /dev/null +++ b/view/adminhtml/layout/baldwin_urldataintegritychecker_catalog_category_urlkey_index.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml new file mode 100644 index 0000000..fd2609a --- /dev/null +++ b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml @@ -0,0 +1,73 @@ + ++ + + baldwin_urldataintegritychecker_grid_catalog_category_urlkey.baldwin_urldataintegritychecker_grid_catalog_category_urlkey_data_source + baldwin_urldataintegritychecker_grid_catalog_category_urlkey.baldwin_urldataintegritychecker_grid_catalog_category_urlkey_data_source + + columns + + + refresh + Refresh + primary + */*/refresh + + + + + + Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider + baldwin_urldataintegritychecker_grid_catalog_category_urlkey_data_source + just-by-specifying-some-attribute-which-doesnt-exists-works-here + just-by-specifying-some-attribute-which-doesnt-exists-works-here + + + Magento_Ui/js/grid/provider + + + just-by-specifying-some-attribute-which-doesnt-exists-works-here + + + + + + + + + + + + + textRange + asc + Category ID + + + + + + + text + Name + + + + + + + text + Store ID + + + + + + + text + Problem + + + + + From d74c633b8ff4bfdbb2a1fe44a4f7eb138c82e20c Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 12 Jun 2020 23:02:08 +0200 Subject: [PATCH 05/11] Updated README file. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d2440d5..cbcbf5a 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ It should be up to the store owner to figure out how he/she wants to fix these p ## Implemented features - It can detect categories having incorrect `url_path` attribute values +- It can detect categories having duplicated `url_key` attribute values within the same parent +- It can detect categories having an empty `url_key` attribute value - It can detect products having non-empty `url_path` attribute values - It can detect products having duplicated `url_key` attribute values on the same store view - It can detect products having an empty `url_key` attribute value @@ -47,11 +49,12 @@ bin/magento setup:upgrade ## Usage -There are some automatic cronjobs running every night at 02:10, 02:20 and 02:30 which will run the various checkers of this module. +There are some automatic cronjobs running every night at 02:10, 02:15, 02:20 and 02:30 which will run the various checkers of this module. You can also opt to manually refresh one of the checkers in the Magento admin, which will schedule one of the cronjobs to be ran the next minute. You'll have to wait a few minutes (depending on the number of problems and how big your catalog is) before you'll see the results appearing. You'll need to refresh the page yourself btw, it won't happen by itself. There are also some cli commands you can execute, which will give you instant feedback about found problems, and will also store that data so you can see them in the Magento admin: +- `bin/magento catalog:category:integrity:urlkey` - `bin/magento catalog:category:integrity:urlpath` - `bin/magento catalog:product:integrity:urlkey` - `bin/magento catalog:product:integrity:urlpath` From 904587e3876a68f78639e8be98aaa31e594d0d68 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 26 Jun 2020 16:54:26 +0200 Subject: [PATCH 06/11] Since url_key's of categories with level 0 or 1 aren't being used on the frontend, we can ignore these (prevents some false positives on a few shops I tested this on). --- Checker/Catalog/Category/UrlKey/EmptyUrlKey.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php b/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php index 391f8b9..b0fb31f 100644 --- a/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php +++ b/Checker/Catalog/Category/UrlKey/EmptyUrlKey.php @@ -59,6 +59,7 @@ private function checkForEmptyUrlKeyAttributeValues(): array ->setStoreId($storeId) ->addAttributeToSelect(UrlKeyChecker::URL_KEY_ATTRIBUTE) ->addAttributeToSelect('name') + ->addAttributeToFilter('level', ['gt' => 1]) // cats with levels 0 or 1 aren't used in the frontend ->addAttributeToFilter('entity_id', ['neq' => CategoryModel::TREE_ROOT_ID]) ->addAttributeToFilter([ [ From dc53b31ec18d70ac6a817dca317e1b1f019e2d84 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 26 Jun 2020 17:34:37 +0200 Subject: [PATCH 07/11] Added unique index per row entry for the admin grids, prevents duplicated rows from showing up after sorting the grid a few times. Fixes #6 --- Model/ResourceModel/Catalog/Category/UrlKeyCollection.php | 2 ++ Model/ResourceModel/Catalog/Category/UrlPathCollection.php | 2 ++ Model/ResourceModel/Catalog/Product/UrlKeyCollection.php | 2 ++ Model/ResourceModel/Catalog/Product/UrlPathCollection.php | 2 ++ ...urldataintegritychecker_grid_catalog_category_urlkey.xml | 6 +++--- ...rldataintegritychecker_grid_catalog_category_urlpath.xml | 6 +++--- ..._urldataintegritychecker_grid_catalog_product_urlkey.xml | 6 +++--- ...urldataintegritychecker_grid_catalog_product_urlpath.xml | 6 +++--- 8 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php b/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php index 47e29fb..a11b4db 100644 --- a/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php +++ b/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php @@ -73,6 +73,8 @@ public function loadData($printQuery = false, $logQuery = false) */ public function createDataObject(array $arguments = []): DataObject { + $arguments['hash'] = sha1(json_encode($arguments) ?: ''); + $obj = $this->_entityFactory->create($this->_itemObjectClass, ['data' => $arguments]); $attributes = []; diff --git a/Model/ResourceModel/Catalog/Category/UrlPathCollection.php b/Model/ResourceModel/Catalog/Category/UrlPathCollection.php index aec70db..619cf16 100644 --- a/Model/ResourceModel/Catalog/Category/UrlPathCollection.php +++ b/Model/ResourceModel/Catalog/Category/UrlPathCollection.php @@ -73,6 +73,8 @@ public function loadData($printQuery = false, $logQuery = false) */ public function createDataObject(array $arguments = []): DataObject { + $arguments['hash'] = sha1(json_encode($arguments) ?: ''); + $obj = $this->_entityFactory->create($this->_itemObjectClass, ['data' => $arguments]); $attributes = []; diff --git a/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php b/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php index 75f54d4..85b4664 100644 --- a/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php +++ b/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php @@ -73,6 +73,8 @@ public function loadData($printQuery = false, $logQuery = false) */ public function createDataObject(array $arguments = []): DataObject { + $arguments['hash'] = sha1(json_encode($arguments) ?: ''); + $obj = $this->_entityFactory->create($this->_itemObjectClass, ['data' => $arguments]); $attributes = []; diff --git a/Model/ResourceModel/Catalog/Product/UrlPathCollection.php b/Model/ResourceModel/Catalog/Product/UrlPathCollection.php index 0657415..5f18ef8 100644 --- a/Model/ResourceModel/Catalog/Product/UrlPathCollection.php +++ b/Model/ResourceModel/Catalog/Product/UrlPathCollection.php @@ -73,6 +73,8 @@ public function loadData($printQuery = false, $logQuery = false) */ public function createDataObject(array $arguments = []): DataObject { + $arguments['hash'] = sha1(json_encode($arguments) ?: ''); + $obj = $this->_entityFactory->create($this->_itemObjectClass, ['data' => $arguments]); $attributes = []; diff --git a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml index fd2609a..e145034 100644 --- a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml +++ b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlkey.xml @@ -19,14 +19,14 @@ Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider baldwin_urldataintegritychecker_grid_catalog_category_urlkey_data_source - just-by-specifying-some-attribute-which-doesnt-exists-works-here - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash + hash Magento_Ui/js/grid/provider - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash diff --git a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlpath.xml b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlpath.xml index 5b3f74f..0a5ccc4 100644 --- a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlpath.xml +++ b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_category_urlpath.xml @@ -19,14 +19,14 @@ Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider baldwin_urldataintegritychecker_grid_catalog_category_urlpath_data_source - just-by-specifying-some-attribute-which-doesnt-exists-works-here - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash + hash Magento_Ui/js/grid/provider - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash diff --git a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlkey.xml b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlkey.xml index 374c348..fd85dad 100644 --- a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlkey.xml +++ b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlkey.xml @@ -19,14 +19,14 @@ Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider baldwin_urldataintegritychecker_grid_catalog_product_urlkey_data_source - just-by-specifying-some-attribute-which-doesnt-exists-works-here - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash + hash Magento_Ui/js/grid/provider - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash diff --git a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlpath.xml b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlpath.xml index 08653d3..3a15a20 100644 --- a/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlpath.xml +++ b/view/adminhtml/ui_component/baldwin_urldataintegritychecker_grid_catalog_product_urlpath.xml @@ -19,14 +19,14 @@ Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider baldwin_urldataintegritychecker_grid_catalog_product_urlpath_data_source - just-by-specifying-some-attribute-which-doesnt-exists-works-here - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash + hash Magento_Ui/js/grid/provider - just-by-specifying-some-attribute-which-doesnt-exists-works-here + hash From 395446f41efc0d9482c5b499df935bf35a1eb318 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 26 Jun 2020 22:20:56 +0200 Subject: [PATCH 08/11] Clear results when start refreshing. --- Storage/AbstractStorage.php | 5 ++++ Storage/StorageInterface.php | 2 ++ Test/Storage/CacheStorageTest.php | 35 ++++++++++++++++++++++++++++ Updater/Catalog/Category/UrlKey.php | 2 ++ Updater/Catalog/Category/UrlPath.php | 2 ++ Updater/Catalog/Product/UrlKey.php | 2 ++ Updater/Catalog/Product/UrlPath.php | 2 ++ 7 files changed, 50 insertions(+) diff --git a/Storage/AbstractStorage.php b/Storage/AbstractStorage.php index 6b197ae..f5b2270 100644 --- a/Storage/AbstractStorage.php +++ b/Storage/AbstractStorage.php @@ -13,4 +13,9 @@ public function update(string $identifier, array $data): bool return $this->write($identifier, $newData); } + + public function clear(string $identifier): bool + { + return $this->write($identifier, []); + } } diff --git a/Storage/StorageInterface.php b/Storage/StorageInterface.php index d2ab6cb..33754f0 100644 --- a/Storage/StorageInterface.php +++ b/Storage/StorageInterface.php @@ -20,4 +20,6 @@ public function read(string $identifier): array; * @param array $data */ public function update(string $identifier, array $data): bool; + + public function clear(string $identifier): bool; } diff --git a/Test/Storage/CacheStorageTest.php b/Test/Storage/CacheStorageTest.php index 462ff19..7b8bda7 100644 --- a/Test/Storage/CacheStorageTest.php +++ b/Test/Storage/CacheStorageTest.php @@ -85,6 +85,41 @@ public function testUpdatingExisting() $this->assertEquals($expectedData, $cacheStorage->read($identifier)); } + public function testClear() + { + $identifier = 'identifier'; + $existingData = [ + 'key1' => 'value1', + 'key2' => 'value2', + ]; + + $expectedData = []; + + /** @var AppCache&MockObject */ + $cacheMock = $this + ->getMockBuilder(AppCache::class) + ->disableOriginalConstructor() + ->getMock(); + + $cacheMock->expects($this->exactly(2)) + ->method('save') + ->withConsecutive( + [$this->jsonEncode($existingData)], + [$this->jsonEncode($expectedData)] + ) + ->willReturn(true); + + $cacheMock->expects($this->exactly(1)) + ->method('load') + ->willReturn($this->jsonEncode($expectedData)); + + $cacheStorage = new CacheStorage($cacheMock); + $cacheStorage->write($identifier, $existingData); + $cacheStorage->clear($identifier); + + $this->assertEquals($expectedData, $cacheStorage->read($identifier)); + } + /** * @param array $data */ diff --git a/Updater/Catalog/Category/UrlKey.php b/Updater/Catalog/Category/UrlKey.php index 1ddc29a..bb5c8f7 100644 --- a/Updater/Catalog/Category/UrlKey.php +++ b/Updater/Catalog/Category/UrlKey.php @@ -39,6 +39,8 @@ public function refresh(string $initiator): array throw new AlreadyRefreshingException($errorMsg); } + $this->storage->clear($storageIdentifier); + $this->metaStorage->setErrorMessage($storageIdentifier, ''); $this->metaStorage->setStartRefreshing($storageIdentifier, $initiator); diff --git a/Updater/Catalog/Category/UrlPath.php b/Updater/Catalog/Category/UrlPath.php index cb3e74f..4380816 100644 --- a/Updater/Catalog/Category/UrlPath.php +++ b/Updater/Catalog/Category/UrlPath.php @@ -39,6 +39,8 @@ public function refresh(string $initiator): array throw new AlreadyRefreshingException($errorMsg); } + $this->storage->clear($storageIdentifier); + $this->metaStorage->setErrorMessage($storageIdentifier, ''); $this->metaStorage->setStartRefreshing($storageIdentifier, $initiator); diff --git a/Updater/Catalog/Product/UrlKey.php b/Updater/Catalog/Product/UrlKey.php index 5e978f8..57a4eef 100644 --- a/Updater/Catalog/Product/UrlKey.php +++ b/Updater/Catalog/Product/UrlKey.php @@ -39,6 +39,8 @@ public function refresh(string $initiator): array throw new AlreadyRefreshingException($errorMsg); } + $this->storage->clear($storageIdentifier); + $this->metaStorage->setErrorMessage($storageIdentifier, ''); $this->metaStorage->setStartRefreshing($storageIdentifier, $initiator); diff --git a/Updater/Catalog/Product/UrlPath.php b/Updater/Catalog/Product/UrlPath.php index b33503f..47f2de8 100644 --- a/Updater/Catalog/Product/UrlPath.php +++ b/Updater/Catalog/Product/UrlPath.php @@ -39,6 +39,8 @@ public function refresh(string $initiator): array throw new AlreadyRefreshingException($errorMsg); } + $this->storage->clear($storageIdentifier); + $this->metaStorage->setErrorMessage($storageIdentifier, ''); $this->metaStorage->setStartRefreshing($storageIdentifier, $initiator); From b26e352db08e59d73efa27a28a2341c56fee300e Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 26 Jun 2020 22:51:37 +0200 Subject: [PATCH 09/11] Updated phpstan from 0.12.28 to 0.12.31 and fixed the new errors it reported. --- .../Catalog/Category/UrlKeyCollection.php | 12 ++++++++++++ .../Catalog/Category/UrlPathCollection.php | 12 ++++++++++++ .../Catalog/Product/UrlKeyCollection.php | 12 ++++++++++++ .../Catalog/Product/UrlPathCollection.php | 12 ++++++++++++ composer.lock | 10 +++++----- 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php b/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php index a11b4db..697d7d1 100644 --- a/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php +++ b/Model/ResourceModel/Catalog/Category/UrlKeyCollection.php @@ -91,6 +91,9 @@ public function createDataObject(array $arguments = []): DataObject return $obj; } + /** + * @return UrlKeyCollection + */ public function setItems(array $items = null) { throw new LocalizedException(__('Not implemented: setItems!')); @@ -101,6 +104,9 @@ public function getAggregations() throw new LocalizedException(__('Not implemented: getAggregations!')); } + /** + * @return UrlKeyCollection + */ public function setAggregations($aggregations) { throw new LocalizedException(__('Not implemented: setAggregations!')); @@ -111,6 +117,9 @@ public function getSearchCriteria() throw new LocalizedException(__('Not implemented: getSearchCriteria!')); } + /** + * @return UrlKeyCollection + */ public function setSearchCriteria(SearchCriteriaInterface $searchCriteria) { throw new LocalizedException(__('Not implemented: setSearchCriteria!')); @@ -121,6 +130,9 @@ public function getTotalCount() return $this->getSize(); } + /** + * @return UrlKeyCollection + */ public function setTotalCount($totalCount) { throw new LocalizedException(__('Not implemented: setTotalCount!')); diff --git a/Model/ResourceModel/Catalog/Category/UrlPathCollection.php b/Model/ResourceModel/Catalog/Category/UrlPathCollection.php index 619cf16..583a4c3 100644 --- a/Model/ResourceModel/Catalog/Category/UrlPathCollection.php +++ b/Model/ResourceModel/Catalog/Category/UrlPathCollection.php @@ -91,6 +91,9 @@ public function createDataObject(array $arguments = []): DataObject return $obj; } + /** + * @return UrlPathCollection + */ public function setItems(array $items = null) { throw new LocalizedException(__('Not implemented: setItems!')); @@ -101,6 +104,9 @@ public function getAggregations() throw new LocalizedException(__('Not implemented: getAggregations!')); } + /** + * @return UrlPathCollection + */ public function setAggregations($aggregations) { throw new LocalizedException(__('Not implemented: setAggregations!')); @@ -111,6 +117,9 @@ public function getSearchCriteria() throw new LocalizedException(__('Not implemented: getSearchCriteria!')); } + /** + * @return UrlPathCollection + */ public function setSearchCriteria(SearchCriteriaInterface $searchCriteria) { throw new LocalizedException(__('Not implemented: setSearchCriteria!')); @@ -121,6 +130,9 @@ public function getTotalCount() return $this->getSize(); } + /** + * @return UrlPathCollection + */ public function setTotalCount($totalCount) { throw new LocalizedException(__('Not implemented: setTotalCount!')); diff --git a/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php b/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php index 85b4664..7d5de1d 100644 --- a/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php +++ b/Model/ResourceModel/Catalog/Product/UrlKeyCollection.php @@ -91,6 +91,9 @@ public function createDataObject(array $arguments = []): DataObject return $obj; } + /** + * @return UrlKeyCollection + */ public function setItems(array $items = null) { throw new LocalizedException(__('Not implemented: setItems!')); @@ -101,6 +104,9 @@ public function getAggregations() throw new LocalizedException(__('Not implemented: getAggregations!')); } + /** + * @return UrlKeyCollection + */ public function setAggregations($aggregations) { throw new LocalizedException(__('Not implemented: setAggregations!')); @@ -111,6 +117,9 @@ public function getSearchCriteria() throw new LocalizedException(__('Not implemented: getSearchCriteria!')); } + /** + * @return UrlKeyCollection + */ public function setSearchCriteria(SearchCriteriaInterface $searchCriteria) { throw new LocalizedException(__('Not implemented: setSearchCriteria!')); @@ -121,6 +130,9 @@ public function getTotalCount() return $this->getSize(); } + /** + * @return UrlKeyCollection + */ public function setTotalCount($totalCount) { throw new LocalizedException(__('Not implemented: setTotalCount!')); diff --git a/Model/ResourceModel/Catalog/Product/UrlPathCollection.php b/Model/ResourceModel/Catalog/Product/UrlPathCollection.php index 5f18ef8..7212a83 100644 --- a/Model/ResourceModel/Catalog/Product/UrlPathCollection.php +++ b/Model/ResourceModel/Catalog/Product/UrlPathCollection.php @@ -91,6 +91,9 @@ public function createDataObject(array $arguments = []): DataObject return $obj; } + /** + * @return UrlPathCollection + */ public function setItems(array $items = null) { throw new LocalizedException(__('Not implemented: setItems!')); @@ -101,6 +104,9 @@ public function getAggregations() throw new LocalizedException(__('Not implemented: getAggregations!')); } + /** + * @return UrlPathCollection + */ public function setAggregations($aggregations) { throw new LocalizedException(__('Not implemented: setAggregations!')); @@ -111,6 +117,9 @@ public function getSearchCriteria() throw new LocalizedException(__('Not implemented: getSearchCriteria!')); } + /** + * @return UrlPathCollection + */ public function setSearchCriteria(SearchCriteriaInterface $searchCriteria) { throw new LocalizedException(__('Not implemented: setSearchCriteria!')); @@ -121,6 +130,9 @@ public function getTotalCount() return $this->getSize(); } + /** + * @return UrlPathCollection + */ public function setTotalCount($totalCount) { throw new LocalizedException(__('Not implemented: setTotalCount!')); diff --git a/composer.lock b/composer.lock index 6c36e8f..429b17b 100644 --- a/composer.lock +++ b/composer.lock @@ -7493,16 +7493,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.28", + "version": "0.12.31", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "76c0c4ec90b1eed66fa4855b8b4b53fa9054353f" + "reference": "776c8056b401e1b67f277b9e9fb334d1a274671d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/76c0c4ec90b1eed66fa4855b8b4b53fa9054353f", - "reference": "76c0c4ec90b1eed66fa4855b8b4b53fa9054353f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/776c8056b401e1b67f277b9e9fb334d1a274671d", + "reference": "776c8056b401e1b67f277b9e9fb334d1a274671d", "shasum": "" }, "require": { @@ -7545,7 +7545,7 @@ "type": "tidelift" } ], - "time": "2020-06-10T06:20:14+00:00" + "time": "2020-06-24T20:55:29+00:00" }, { "name": "phpunit/php-code-coverage", From 0afcc2d7be71271ac9512e017afca4747dfe4483 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 26 Jun 2020 22:53:12 +0200 Subject: [PATCH 10/11] Updated all other dependencies, see list: - Updating colinmollenhour/credis (1.11.1 => 1.11.2) - Updating composer/composer (1.10.7 => 1.10.8) - Updating guzzlehttp/guzzle (6.5.4 => 6.5.5) - Updating laminas/laminas-form (2.14.5 => 2.14.6) - Updating laminas/laminas-http (2.11.2 => 2.12.0) - Updating phpdocumentor/type-resolver (1.1.0 => 1.2.0) - Updating symfony/console (v4.4.9 => v4.4.10) - Updating symfony/event-dispatcher (v4.4.9 => v4.4.10) - Updating symfony/filesystem (v5.1.0 => v5.1.2) - Updating symfony/finder (v5.1.0 => v5.1.2) - Updating symfony/options-resolver (v5.1.0 => v5.1.2) - Updating symfony/polyfill-ctype (v1.17.0 => v1.17.1) - Updating symfony/polyfill-intl-idn (v1.17.0 => v1.17.1) - Updating symfony/polyfill-mbstring (v1.17.0 => v1.17.1) - Updating symfony/polyfill-php70 (v1.17.0 => v1.17.1) - Updating symfony/polyfill-php73 (v1.17.0 => v1.17.1) - Updating symfony/polyfill-php80 (v1.17.0 => v1.17.1) - Updating symfony/process (v4.4.9 => v4.4.10) - Updating symfony/stopwatch (v5.1.0 => v5.1.2) - Updating vimeo/psalm (3.11.5 => 3.12.1) - Updating webmozart/assert (1.8.0 => 1.9.0) --- composer.lock | 208 +++++++++++++++++++++++++++++--------------------- 1 file changed, 122 insertions(+), 86 deletions(-) diff --git a/composer.lock b/composer.lock index 429b17b..5122886 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "colinmollenhour/credis", - "version": "1.11.1", + "version": "1.11.2", "source": { "type": "git", "url": "https://github.com/colinmollenhour/credis.git", - "reference": "bd1da4698ab1918477f9e71e5ff0062b9a345008" + "reference": "b8b2bd6b87d2d4df67065f3510efb80d5f9c4e53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/bd1da4698ab1918477f9e71e5ff0062b9a345008", - "reference": "bd1da4698ab1918477f9e71e5ff0062b9a345008", + "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/b8b2bd6b87d2d4df67065f3510efb80d5f9c4e53", + "reference": "b8b2bd6b87d2d4df67065f3510efb80d5f9c4e53", "shasum": "" }, "require": { @@ -44,7 +44,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2019-11-26T18:09:45+00:00" + "time": "2020-06-15T19:25:47+00:00" }, { "name": "colinmollenhour/php-redis-session-abstract", @@ -151,16 +151,16 @@ }, { "name": "composer/composer", - "version": "1.10.7", + "version": "1.10.8", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "956608ea4f7de9e58c53dfb019d85ae62b193c39" + "reference": "56e0e094478f30935e9128552188355fa9712291" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/956608ea4f7de9e58c53dfb019d85ae62b193c39", - "reference": "956608ea4f7de9e58c53dfb019d85ae62b193c39", + "url": "https://api.github.com/repos/composer/composer/zipball/56e0e094478f30935e9128552188355fa9712291", + "reference": "56e0e094478f30935e9128552188355fa9712291", "shasum": "" }, "require": { @@ -179,12 +179,11 @@ "symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0" }, "conflict": { - "symfony/console": "2.8.38", - "symfony/phpunit-bridge": "3.4.40" + "symfony/console": "2.8.38" }, "require-dev": { "phpspec/prophecy": "^1.10", - "symfony/phpunit-bridge": "^3.4" + "symfony/phpunit-bridge": "^4.2" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -242,7 +241,7 @@ "type": "tidelift" } ], - "time": "2020-06-03T08:03:56+00:00" + "time": "2020-06-24T19:23:30+00:00" }, { "name": "composer/semver", @@ -457,16 +456,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "6.5.4", + "version": "6.5.5", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "a4a1b6930528a8f7ee03518e6442ec7a44155d9d" + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a4a1b6930528a8f7ee03518e6442ec7a44155d9d", - "reference": "a4a1b6930528a8f7ee03518e6442ec7a44155d9d", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", + "reference": "9d4290de1cfd701f38099ef7e183b64b4b7b0c5e", "shasum": "" }, "require": { @@ -474,7 +473,7 @@ "guzzlehttp/promises": "^1.0", "guzzlehttp/psr7": "^1.6.1", "php": ">=5.5", - "symfony/polyfill-intl-idn": "1.17.0" + "symfony/polyfill-intl-idn": "^1.17.0" }, "require-dev": { "ext-curl": "*", @@ -520,7 +519,7 @@ "rest", "web service" ], - "time": "2020-05-25T19:35:05+00:00" + "time": "2020-06-16T21:01:06+00:00" }, { "name": "guzzlehttp/promises", @@ -1255,16 +1254,16 @@ }, { "name": "laminas/laminas-form", - "version": "2.14.5", + "version": "2.14.6", "source": { "type": "git", "url": "https://github.com/laminas/laminas-form.git", - "reference": "3e22e09751cf6ae031be87a44e092e7925ce5b7b" + "reference": "c19b62ed8394bcf2038ab3f51a49b7d0ef4e1700" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-form/zipball/3e22e09751cf6ae031be87a44e092e7925ce5b7b", - "reference": "3e22e09751cf6ae031be87a44e092e7925ce5b7b", + "url": "https://api.github.com/repos/laminas/laminas-form/zipball/c19b62ed8394bcf2038ab3f51a49b7d0ef4e1700", + "reference": "c19b62ed8394bcf2038ab3f51a49b7d0ef4e1700", "shasum": "" }, "require": { @@ -1333,20 +1332,26 @@ "form", "laminas" ], - "time": "2020-03-29T12:46:16+00:00" + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2020-06-22T20:17:02+00:00" }, { "name": "laminas/laminas-http", - "version": "2.11.2", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-http.git", - "reference": "8c66963b933c80da59433da56a44dfa979f3ec88" + "reference": "48bd06ffa3a6875e2b77d6852405eb7b1589d575" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-http/zipball/8c66963b933c80da59433da56a44dfa979f3ec88", - "reference": "8c66963b933c80da59433da56a44dfa979f3ec88", + "url": "https://api.github.com/repos/laminas/laminas-http/zipball/48bd06ffa3a6875e2b77d6852405eb7b1589d575", + "reference": "48bd06ffa3a6875e2b77d6852405eb7b1589d575", "shasum": "" }, "require": { @@ -1358,7 +1363,7 @@ "php": "^5.6 || ^7.0" }, "replace": { - "zendframework/zend-http": "self.version" + "zendframework/zend-http": "^2.11.2" }, "require-dev": { "laminas/laminas-coding-standard": "~1.0.0", @@ -1371,8 +1376,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.11.x-dev", - "dev-develop": "2.12.x-dev" + "dev-master": "2.12.x-dev", + "dev-develop": "2.13.x-dev" } }, "autoload": { @@ -1391,7 +1396,13 @@ "http client", "laminas" ], - "time": "2019-12-31T17:02:36+00:00" + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2020-06-23T15:14:37+00:00" }, { "name": "laminas/laminas-hydrator", @@ -4820,7 +4831,7 @@ }, { "name": "symfony/console", - "version": "v4.4.9", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", @@ -4911,7 +4922,7 @@ }, { "name": "symfony/filesystem", - "version": "v5.1.0", + "version": "v5.1.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -4975,7 +4986,7 @@ }, { "name": "symfony/finder", - "version": "v5.1.0", + "version": "v5.1.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", @@ -5038,16 +5049,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.17.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9" + "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9", - "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d", + "reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d", "shasum": "" }, "require": { @@ -5060,6 +5071,10 @@ "extra": { "branch-alias": { "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5106,20 +5121,20 @@ "type": "tidelift" } ], - "time": "2020-05-12T16:14:59+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.17.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "3bff59ea7047e925be6b7f2059d60af31bb46d6a" + "reference": "a57f8161502549a742a63c09f0a604997bf47027" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/3bff59ea7047e925be6b7f2059d60af31bb46d6a", - "reference": "3bff59ea7047e925be6b7f2059d60af31bb46d6a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a57f8161502549a742a63c09f0a604997bf47027", + "reference": "a57f8161502549a742a63c09f0a604997bf47027", "shasum": "" }, "require": { @@ -5134,6 +5149,10 @@ "extra": { "branch-alias": { "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5182,20 +5201,20 @@ "type": "tidelift" } ], - "time": "2020-05-12T16:47:27+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.17.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fa79b11539418b02fc5e1897267673ba2c19419c" + "reference": "7110338d81ce1cbc3e273136e4574663627037a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c", - "reference": "fa79b11539418b02fc5e1897267673ba2c19419c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7", + "reference": "7110338d81ce1cbc3e273136e4574663627037a7", "shasum": "" }, "require": { @@ -5208,6 +5227,10 @@ "extra": { "branch-alias": { "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5255,7 +5278,7 @@ "type": "tidelift" } ], - "time": "2020-05-12T16:47:27+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-php72", @@ -5328,16 +5351,16 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.17.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "a760d8964ff79ab9bf057613a5808284ec852ccc" + "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a760d8964ff79ab9bf057613a5808284ec852ccc", - "reference": "a760d8964ff79ab9bf057613a5808284ec852ccc", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a", + "reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a", "shasum": "" }, "require": { @@ -5347,6 +5370,10 @@ "extra": { "branch-alias": { "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5396,20 +5423,20 @@ "type": "tidelift" } ], - "time": "2020-05-12T16:47:27+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.17.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd" + "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/5e30b2799bc1ad68f7feb62b60a73743589438dd", - "reference": "5e30b2799bc1ad68f7feb62b60a73743589438dd", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2", + "reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2", "shasum": "" }, "require": { @@ -5419,6 +5446,10 @@ "extra": { "branch-alias": { "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -5472,11 +5503,11 @@ "type": "tidelift" } ], - "time": "2020-05-12T16:47:27+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/process", - "version": "v4.4.9", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -7339,16 +7370,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95" + "reference": "30441f2752e493c639526b215ed81d54f369d693" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/7462d5f123dfc080dfdf26897032a6513644fc95", - "reference": "7462d5f123dfc080dfdf26897032a6513644fc95", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30441f2752e493c639526b215ed81d54f369d693", + "reference": "30441f2752e493c639526b215ed81d54f369d693", "shasum": "" }, "require": { @@ -7362,7 +7393,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-1.x": "1.x-dev" } }, "autoload": { @@ -7381,7 +7412,7 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2020-02-18T18:59:58+00:00" + "time": "2020-06-19T20:22:09+00:00" }, { "name": "phpspec/prophecy", @@ -8562,7 +8593,7 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.4.9", + "version": "v4.4.10", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -8704,7 +8735,7 @@ }, { "name": "symfony/options-resolver", - "version": "v5.1.0", + "version": "v5.1.2", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", @@ -8774,16 +8805,16 @@ }, { "name": "symfony/polyfill-php70", - "version": "v1.17.0", + "version": "v1.17.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "82225c2d7d23d7e70515496d249c0152679b468e" + "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/82225c2d7d23d7e70515496d249c0152679b468e", - "reference": "82225c2d7d23d7e70515496d249c0152679b468e", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/471b096aede7025bace8eb356b9ac801aaba7e2d", + "reference": "471b096aede7025bace8eb356b9ac801aaba7e2d", "shasum": "" }, "require": { @@ -8794,6 +8825,10 @@ "extra": { "branch-alias": { "dev-master": "1.17-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { @@ -8843,11 +8878,11 @@ "type": "tidelift" } ], - "time": "2020-05-12T16:47:27+00:00" + "time": "2020-06-06T08:46:27+00:00" }, { "name": "symfony/stopwatch", - "version": "v5.1.0", + "version": "v5.1.2", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -8951,22 +8986,22 @@ }, { "name": "vimeo/psalm", - "version": "3.11.5", + "version": "3.12.1", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "3c60609c218d4d4b3b257728b8089094e5c6c6c2" + "reference": "9b860214d58c48b5cbe99bdb17914d0eb723c9cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/3c60609c218d4d4b3b257728b8089094e5c6c6c2", - "reference": "3c60609c218d4d4b3b257728b8089094e5c6c6c2", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/9b860214d58c48b5cbe99bdb17914d0eb723c9cd", + "reference": "9b860214d58c48b5cbe99bdb17914d0eb723c9cd", "shasum": "" }, "require": { "amphp/amp": "^2.1", "amphp/byte-stream": "^1.5", - "composer/semver": "^1.4", + "composer/semver": "^1.4 || ^2.0 || ^3.0", "composer/xdebug-handler": "^1.1", "ext-dom": "*", "ext-json": "*", @@ -9044,20 +9079,20 @@ "inspection", "php" ], - "time": "2020-05-27T15:12:09+00:00" + "time": "2020-06-23T00:24:34+00:00" }, { "name": "webmozart/assert", - "version": "1.8.0", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6" + "reference": "9dc4f203e36f2b486149058bade43c851dd97451" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6", - "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6", + "url": "https://api.github.com/repos/webmozart/assert/zipball/9dc4f203e36f2b486149058bade43c851dd97451", + "reference": "9dc4f203e36f2b486149058bade43c851dd97451", "shasum": "" }, "require": { @@ -9065,6 +9100,7 @@ "symfony/polyfill-ctype": "^1.8" }, "conflict": { + "phpstan/phpstan": "<0.12.20", "vimeo/psalm": "<3.9.1" }, "require-dev": { @@ -9092,7 +9128,7 @@ "check", "validate" ], - "time": "2020-04-18T12:12:48+00:00" + "time": "2020-06-16T10:16:42+00:00" }, { "name": "webmozart/glob", From 5664102e24b6d12d5f35b0142e6a1287e0b101e2 Mon Sep 17 00:00:00 2001 From: Pieter Hoste Date: Fri, 26 Jun 2020 23:08:32 +0200 Subject: [PATCH 11/11] Increased minimum version of certain dev dependencies we use, now all tests pass when we run them after executing 'composer update --prefer-lowest'. --- composer.json | 6 +++--- composer.lock | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 908ae9a..b979aed 100644 --- a/composer.json +++ b/composer.json @@ -23,13 +23,13 @@ "require-dev": { "bitexpert/phpstan-magento": "^0.3.0", "ergebnis/composer-normalize": "^2.2", - "friendsofphp/php-cs-fixer": "^2.15", + "friendsofphp/php-cs-fixer": "^2.16", "magento/magento-coding-standard": "^5.0", "phpcompatibility/php-compatibility": "^9.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.0", + "phpstan/phpstan": "^0.12.26", "phpunit/phpunit": "^7.5", - "vimeo/psalm": "^3.9" + "vimeo/psalm": "^3.11" }, "config": { "sort-packages": true diff --git a/composer.lock b/composer.lock index 5122886..28f7229 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ca54f60666ffaf5f27b9e9856cb1e8e2", + "content-hash": "feeaf8065d293025acf29d23193cafbd", "packages": [ { "name": "colinmollenhour/credis",