Skip to content

Commit d8e0fe5

Browse files
committed
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).
1 parent a6e5876 commit d8e0fe5

File tree

6 files changed

+313
-0
lines changed

6 files changed

+313
-0
lines changed

Checker/Catalog/Category/UrlKey.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category;
6+
7+
use Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey\DuplicateUrlKey as DuplicateUrlKeyChecker;
8+
use Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey\EmptyUrlKey as EmptyUrlKeyChecker;
9+
10+
class UrlKey
11+
{
12+
const URL_KEY_ATTRIBUTE = 'url_key';
13+
const STORAGE_IDENTIFIER = 'category-url-key';
14+
15+
private $duplicateUrlKeyChecker;
16+
private $emptyUrlKeyChecker;
17+
18+
public function __construct(
19+
DuplicateUrlKeyChecker $duplicateUrlKeyChecker,
20+
EmptyUrlKeyChecker $emptyUrlKeyChecker
21+
) {
22+
$this->duplicateUrlKeyChecker = $duplicateUrlKeyChecker;
23+
$this->emptyUrlKeyChecker = $emptyUrlKeyChecker;
24+
}
25+
26+
/**
27+
* @return array<array<string, mixed>>
28+
*/
29+
public function execute(): array
30+
{
31+
$categoryData = array_merge(
32+
$this->duplicateUrlKeyChecker->execute(),
33+
$this->emptyUrlKeyChecker->execute()
34+
);
35+
36+
return $categoryData;
37+
}
38+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey;
6+
7+
class DuplicateUrlKey
8+
{
9+
/**
10+
* @return array<array<string, mixed>>
11+
*/
12+
public function execute(): array
13+
{
14+
$categoryData = $this->checkForDuplicatedUrlKeyAttributeValues();
15+
16+
return $categoryData;
17+
}
18+
19+
/**
20+
* @return array<array<string, mixed>>
21+
*/
22+
private function checkForDuplicatedUrlKeyAttributeValues(): array
23+
{
24+
$categoriesWithProblems = [];
25+
26+
// TODO !!!!!
27+
28+
return $categoriesWithProblems;
29+
}
30+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey;
6+
7+
use Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey as UrlKeyChecker;
8+
use Baldwin\UrlDataIntegrityChecker\Util\Stores as StoresUtil;
9+
use Magento\Catalog\Api\Data\CategoryInterface;
10+
use Magento\Catalog\Model\Attribute\ScopeOverriddenValueFactory as AttributeScopeOverriddenValueFactory;
11+
use Magento\Catalog\Model\Category as CategoryModel;
12+
use Magento\Catalog\Model\ResourceModel\Category\Collection as CategoryCollection;
13+
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
14+
use Magento\Store\Model\Store;
15+
16+
class EmptyUrlKey
17+
{
18+
const EMPTY_PROBLEM_DESCRIPTION = 'Category has an empty url_key value. This needs to be fixed.';
19+
20+
private $storesUtil;
21+
private $categoryCollectionFactory;
22+
private $attributeScopeOverriddenValueFactory;
23+
24+
public function __construct(
25+
StoresUtil $storesUtil,
26+
CategoryCollectionFactory $categoryCollectionFactory,
27+
AttributeScopeOverriddenValueFactory $attributeScopeOverriddenValueFactory
28+
) {
29+
$this->storesUtil = $storesUtil;
30+
$this->categoryCollectionFactory = $categoryCollectionFactory;
31+
$this->attributeScopeOverriddenValueFactory = $attributeScopeOverriddenValueFactory;
32+
}
33+
34+
/**
35+
* @return array<array<string, mixed>>
36+
*/
37+
public function execute(): array
38+
{
39+
$categoryData = $this->checkForEmptyUrlKeyAttributeValues();
40+
41+
return $categoryData;
42+
}
43+
44+
/**
45+
* @return array<array<string, mixed>>
46+
*/
47+
private function checkForEmptyUrlKeyAttributeValues(): array
48+
{
49+
$categoriesWithProblems = [];
50+
51+
$storeIds = $this->storesUtil->getAllStoreIds();
52+
foreach ($storeIds as $storeId) {
53+
// we need a left join when using the non-default store view
54+
// and especially for the case where storeId 0 doesn't have a value set for this attribute
55+
$joinType = $storeId === Store::DEFAULT_STORE_ID ? 'inner' : 'left';
56+
57+
$collection = $this->categoryCollectionFactory->create();
58+
$collection
59+
->setStoreId($storeId)
60+
->addAttributeToSelect(UrlKeyChecker::URL_KEY_ATTRIBUTE)
61+
->addAttributeToFilter('entity_id', ['neq' => CategoryModel::TREE_ROOT_ID])
62+
->addAttributeToFilter([
63+
[
64+
'attribute' => UrlKeyChecker::URL_KEY_ATTRIBUTE,
65+
'null' => true,
66+
],
67+
[
68+
'attribute' => UrlKeyChecker::URL_KEY_ATTRIBUTE,
69+
'eq' => '',
70+
],
71+
], null, $joinType)
72+
;
73+
74+
$categoriesWithProblems[] = $this->getCategoriesWithProblems($storeId, $collection);
75+
}
76+
77+
if (!empty($categoriesWithProblems)) {
78+
$categoriesWithProblems = array_merge(...$categoriesWithProblems);
79+
}
80+
81+
return $categoriesWithProblems;
82+
}
83+
84+
/**
85+
* @param CategoryCollection<CategoryModel> $collection
86+
*
87+
* @return array<array<string, mixed>>
88+
*/
89+
private function getCategoriesWithProblems(int $storeId, CategoryCollection $collection): array
90+
{
91+
$problems = [];
92+
93+
foreach ($collection as $category) {
94+
$isOverridden = $this
95+
->attributeScopeOverriddenValueFactory
96+
->create()
97+
->containsValue(CategoryInterface::class, $category, UrlKeyChecker::URL_KEY_ATTRIBUTE, $storeId)
98+
;
99+
100+
if ($isOverridden || $storeId === Store::DEFAULT_STORE_ID) {
101+
$problems[] = [
102+
'catId' => (int) $category->getEntityId(),
103+
'sku' => $category->getSku(),
104+
'storeId' => $storeId,
105+
'problem' => self::EMPTY_PROBLEM_DESCRIPTION,
106+
];
107+
}
108+
}
109+
110+
return $problems;
111+
}
112+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Baldwin\UrlDataIntegrityChecker\Console\Command;
6+
7+
use Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey as UrlKeyChecker;
8+
use Baldwin\UrlDataIntegrityChecker\Console\CategoryResultOutput;
9+
use Baldwin\UrlDataIntegrityChecker\Storage\Meta as MetaStorage;
10+
use Baldwin\UrlDataIntegrityChecker\Updater\Catalog\Category\UrlKey as UrlKeyUpdater;
11+
use Magento\Framework\App\Area as AppArea;
12+
use Magento\Framework\App\State as AppState;
13+
use Magento\Framework\Console\Cli;
14+
use Symfony\Component\Console\Command\Command as ConsoleCommand;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Input\InputOption;
17+
use Symfony\Component\Console\Output\OutputInterface;
18+
19+
class CheckCategoryUrlKeys extends ConsoleCommand
20+
{
21+
private $appState;
22+
private $resultOutput;
23+
private $urlKeyUpdater;
24+
private $metaStorage;
25+
26+
public function __construct(
27+
AppState $appState,
28+
CategoryResultOutput $resultOutput,
29+
UrlKeyUpdater $urlKeyUpdater,
30+
MetaStorage $metaStorage
31+
) {
32+
$this->appState = $appState;
33+
$this->resultOutput = $resultOutput;
34+
$this->urlKeyUpdater = $urlKeyUpdater;
35+
$this->metaStorage = $metaStorage;
36+
37+
parent::__construct();
38+
}
39+
40+
protected function configure()
41+
{
42+
$this->setName('catalog:category:integrity:urlkey');
43+
$this->setDescription('Checks data integrity of the values of the url_key category attribute.');
44+
$this->addOption(
45+
'force',
46+
'f',
47+
InputOption::VALUE_NONE,
48+
'Force the command to run, even if it is already marked as already running'
49+
);
50+
51+
parent::configure();
52+
}
53+
54+
protected function execute(InputInterface $input, OutputInterface $output)
55+
{
56+
try {
57+
$this->appState->setAreaCode(AppArea::AREA_CRONTAB);
58+
59+
$force = $input->getOption('force');
60+
if ($force === true) {
61+
$this->metaStorage->clearStatus(UrlKeyChecker::STORAGE_IDENTIFIER);
62+
}
63+
64+
$categoryData = $this->urlKeyUpdater->refresh(MetaStorage::INITIATOR_CLI);
65+
$cliResult = $this->resultOutput->outputResult($categoryData, $output);
66+
67+
$output->writeln(
68+
"\n<info>Data was stored and you can now also review it in the admin of Magento</info>"
69+
);
70+
71+
return $cliResult;
72+
} catch (\Throwable $ex) {
73+
$output->writeln(
74+
"<error>An unexpected exception occured: '{$ex->getMessage()}'</error>\n{$ex->getTraceAsString()}"
75+
);
76+
}
77+
78+
return Cli::RETURN_FAILURE;
79+
}
80+
}

Updater/Catalog/Category/UrlKey.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Baldwin\UrlDataIntegrityChecker\Updater\Catalog\Category;
6+
7+
use Baldwin\UrlDataIntegrityChecker\Checker\Catalog\Category\UrlKey as UrlKeyChecker;
8+
use Baldwin\UrlDataIntegrityChecker\Exception\AlreadyRefreshingException;
9+
use Baldwin\UrlDataIntegrityChecker\Storage\Meta as MetaStorage;
10+
use Baldwin\UrlDataIntegrityChecker\Storage\StorageInterface;
11+
12+
class UrlKey
13+
{
14+
private $urlKeyChecker;
15+
private $storage;
16+
private $metaStorage;
17+
18+
public function __construct(
19+
UrlKeyChecker $urlKeyChecker,
20+
StorageInterface $storage,
21+
MetaStorage $metaStorage
22+
) {
23+
$this->urlKeyChecker = $urlKeyChecker;
24+
$this->storage = $storage;
25+
$this->metaStorage = $metaStorage;
26+
}
27+
28+
/**
29+
* @return array<array<string, mixed>>
30+
*/
31+
public function refresh(string $initiator): array
32+
{
33+
$storageIdentifier = UrlKeyChecker::STORAGE_IDENTIFIER;
34+
35+
if ($this->metaStorage->isRefreshing($storageIdentifier)) {
36+
$errorMsg = __('We are already refreshing the category url key\'s, just have a little patience 🙂');
37+
38+
$this->metaStorage->setErrorMessage($storageIdentifier, (string) $errorMsg);
39+
throw new AlreadyRefreshingException($errorMsg);
40+
}
41+
42+
$this->metaStorage->setErrorMessage($storageIdentifier, '');
43+
$this->metaStorage->setStartRefreshing($storageIdentifier, $initiator);
44+
45+
$categoryData = $this->urlKeyChecker->execute();
46+
$this->storage->write($storageIdentifier, $categoryData);
47+
48+
$this->metaStorage->setFinishedRefreshing($storageIdentifier);
49+
50+
return $categoryData;
51+
}
52+
}

etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<argument name="commands" xsi:type="array">
77
<item name="baldwin_urldataintegritychecker_console_command_checkproducturlkeys" xsi:type="object">Baldwin\UrlDataIntegrityChecker\Console\Command\CheckProductUrlKeys</item>
88
<item name="baldwin_urldataintegritychecker_console_command_checkproducturlpaths" xsi:type="object">Baldwin\UrlDataIntegrityChecker\Console\Command\CheckProductUrlPaths</item>
9+
<item name="baldwin_urldataintegritychecker_console_command_checkcategoryurlkeys" xsi:type="object">Baldwin\UrlDataIntegrityChecker\Console\Command\CheckCategoryUrlKeys</item>
910
<item name="baldwin_urldataintegritychecker_console_command_checkcategoryurlpaths" xsi:type="object">Baldwin\UrlDataIntegrityChecker\Console\Command\CheckCategoryUrlPaths</item>
1011
<!-- <item name="baldwin_urldataintegritychecker_console_command_checkurlrewrites" xsi:type="object">Baldwin\UrlDataIntegrityChecker\Console\Command\CheckUrlRewrites</item> -->
1112
</argument>

0 commit comments

Comments
 (0)