Skip to content

Commit 809cb3f

Browse files
Merge branch 'release/2.22.0'
2 parents 4d4a5dd + bb58b89 commit 809cb3f

File tree

20 files changed

+349
-28
lines changed

20 files changed

+349
-28
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## [Unreleased]
99

10+
## [2.22.0] - 2023-05-08
11+
### Fixed
12+
- Get product title method ([#270](https://github.com/SnowdogApps/magento2-menu/pull/270))
13+
- Category Child node without parent category chosen makes menu disappear (DEV-99318)
14+
15+
### Changed
16+
- Change Custom URL without URL content to not clickable (DEV-99301)
17+
18+
### Added
19+
- Error skipping mechanism for some exceptions ([#271](https://github.com/SnowdogApps/magento2-menu/pull/271))
20+
- Required prop for category child field (DEV-99318)
21+
- Display a message indicating success or error after saving the menu. #274
22+
1023
## [2.21.0] - 2023-04-03
1124
### Fixed
1225
- Reset button doesn't reset menu node structure ([#256](https://github.com/SnowdogApps/magento2-menu/pull/256))

Controller/Adminhtml/Menu/ImportPost.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Snowdog\Menu\Model\ImportExport\File\Upload as FileUpload;
1414
use Snowdog\Menu\Model\ImportExport\Processor\Import as ImportProcessor;
1515
use Snowdog\Menu\Model\ImportExport\Processor\Import\Validator\ValidationAggregateError;
16+
use Throwable;
1617

1718
class ImportPost extends Action implements HttpPostActionInterface
1819
{
@@ -67,7 +68,7 @@ public function execute()
6768
$exception->flush();
6869
} catch (ValidatorException $exception) {
6970
$this->messageManager->addErrorMessage($exception->getMessage());
70-
} catch (Exception $exception) {
71+
} catch (Exception|Throwable $exception) {
7172
$this->logger->critical($exception);
7273
$this->messageManager->addErrorMessage(__('An error occurred while importing menu.'));
7374
}

Controller/Adminhtml/Menu/Save.php

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44

55
namespace Snowdog\Menu\Controller\Adminhtml\Menu;
66

7+
use Exception;
78
use Magento\Backend\App\Action\Context;
89
use Magento\Framework\App\Action\HttpPostActionInterface;
910
use Magento\Framework\Controller\ResultInterface;
11+
use Magento\Framework\Exception\AlreadyExistsException;
12+
use Magento\Framework\Exception\CouldNotSaveException;
13+
use Magento\Framework\Phrase;
1014
use Magento\Store\Model\StoreManagerInterface;
15+
use Psr\Log\LoggerInterface;
1116
use Snowdog\Menu\Api\MenuRepositoryInterface;
1217
use Snowdog\Menu\Api\Data\MenuInterface;
1318
use Snowdog\Menu\Controller\Adminhtml\MenuAction;
@@ -40,19 +45,26 @@ class Save extends MenuAction implements HttpPostActionInterface
4045
*/
4146
private $storeManager;
4247

48+
/**
49+
* @var LoggerInterface
50+
*/
51+
private $logger;
52+
4353
public function __construct(
4454
Context $context,
4555
MenuRepositoryInterface $menuRepository,
4656
MenuFactory $menuFactory,
4757
CloneRequestProcessor $cloneRequestProcessor,
4858
MenuHydrator $hydrator,
4959
MenuSaveRequestProcessor $menuSaveRequestProcessor,
50-
StoreManagerInterface $storeManager
60+
StoreManagerInterface $storeManager,
61+
LoggerInterface $logger
5162
) {
5263
$this->cloneRequestProcessor = $cloneRequestProcessor;
5364
$this->hydrator = $hydrator;
5465
$this->menuSaveRequestProcessor = $menuSaveRequestProcessor;
5566
$this->storeManager = $storeManager;
67+
$this->logger = $logger;
5668

5769
parent::__construct($context, $menuRepository, $menuFactory);
5870
}
@@ -68,10 +80,8 @@ public function execute()
6880
$nodes = $nodes ? json_decode($nodes, true) : [];
6981

7082
$this->hydrator->mapRequest($menu, $request);
71-
$this->menuRepository->save($menu);
72-
$menu->saveStores($this->getStores());
7383

74-
$this->menuSaveRequestProcessor->saveData($menu, $nodes);
84+
$this->processSave($menu, $nodes);
7585

7686
return $this->processRedirect($menu);
7787
}
@@ -106,4 +116,23 @@ private function getStores(): array
106116

107117
return $stores;
108118
}
119+
120+
private function processSave(MenuInterface $menu, $nodes): void
121+
{
122+
try {
123+
$this->menuRepository->save($menu);
124+
$menu->saveStores($this->getStores());
125+
126+
$this->menuSaveRequestProcessor->saveData($menu, $nodes);
127+
128+
if (empty($this->messageManager->getMessages()->getErrors())) {
129+
$this->messageManager->addSuccessMessage(new Phrase('Menu has been saved successfully.'));
130+
}
131+
} catch (AlreadyExistsException|CouldNotSaveException $e) {
132+
$this->messageManager->addErrorMessage(new Phrase('Could not save Menu: %1', [$e->getMessage()]));
133+
} catch (Exception $e) {
134+
$this->logger->critical($e);
135+
$this->messageManager->addErrorMessage(new Phrase('An error occurred while saving menu.'));
136+
}
137+
}
109138
}

Model/ImportExport/Processor/Import.php

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Snowdog\Menu\Model\ImportExport\Processor;
66

7+
use Magento\Framework\App\Config\ScopeConfigInterface;
78
use Snowdog\Menu\Api\Data\MenuInterface;
8-
use Snowdog\Menu\Model\ImportExport\Processor\ExtendedFields;
9+
use Snowdog\Menu\Model\ImportExport\Processor\Import\InvalidNodes as InvalidNodesProcessor;
910
use Snowdog\Menu\Model\ImportExport\Processor\Import\Menu as MenuProcessor;
1011
use Snowdog\Menu\Model\ImportExport\Processor\Import\Node as NodeProcessor;
1112
use Snowdog\Menu\Model\ImportExport\Processor\Import\Validator\ValidationAggregateError;
13+
use Snowdog\Menu\Model\ImportExport\Processor\Import\Validator\ValidationException;
1214

1315
class Import
1416
{
@@ -27,19 +29,36 @@ class Import
2729
*/
2830
private $validationAggregateError;
2931

32+
/**
33+
* @var InvalidNodesProcessor
34+
*/
35+
private $invalidNodesProcessor;
36+
/**
37+
* @var ScopeConfigInterface
38+
*/
39+
private $scopeConfig;
40+
3041
public function __construct(
3142
MenuProcessor $menuProcessor,
3243
NodeProcessor $nodeProcessor,
33-
ValidationAggregateError $validationAggregateError
44+
ValidationAggregateError $validationAggregateError,
45+
InvalidNodesProcessor $invalidNodesProcessor,
46+
ScopeConfigInterface $scopeConfig
3447
) {
3548
$this->menuProcessor = $menuProcessor;
3649
$this->nodeProcessor = $nodeProcessor;
3750
$this->validationAggregateError = $validationAggregateError;
51+
$this->invalidNodesProcessor = $invalidNodesProcessor;
52+
$this->scopeConfig = $scopeConfig;
3853
}
3954

55+
/**
56+
* @throws ValidationAggregateError
57+
*/
4058
public function importData(array $data): string
4159
{
4260
$this->validateData($data);
61+
4362
$menu = $this->createMenu($data);
4463

4564
if (isset($data[ExtendedFields::NODES])) {
@@ -63,16 +82,34 @@ private function createMenu(array $data): MenuInterface
6382
/**
6483
* @throws ValidationAggregateError
6584
*/
66-
private function validateData(array $data): void
85+
private function validateData(array &$data): void
6786
{
6887
$this->menuProcessor->validateImportData($data);
6988

7089
if (isset($data[ExtendedFields::NODES])) {
7190
$this->nodeProcessor->validateImportData($data[ExtendedFields::NODES]);
7291
}
7392

74-
if ($this->validationAggregateError->getErrors()) {
93+
if (empty($this->scopeConfig->getValue('snowmenu/import/strip_invalid_nodes'))
94+
&& $this->validationAggregateError->getErrors()
95+
) {
7596
throw $this->validationAggregateError;
7697
}
98+
99+
$this->checkExceptionTypes($this->validationAggregateError);
100+
$this->invalidNodesProcessor->process($data, $this->validationAggregateError);
101+
}
102+
103+
/**
104+
* Rethrows $e if there's at least one error not matching ValidationException
105+
* @throws ValidationAggregateError
106+
*/
107+
private function checkExceptionTypes(ValidationAggregateError $e)
108+
{
109+
foreach ($e->getErrors() as $error) {
110+
if (!($error instanceof ValidationException)) {
111+
throw $e;
112+
}
113+
}
77114
}
78115
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Snowdog\Menu\Model\ImportExport\Processor\Import;
4+
5+
use Magento\Framework\Message\Manager;
6+
use Snowdog\Menu\Model\ImportExport\Processor\Import\Node\Validator\TreeTrace;
7+
use Snowdog\Menu\Model\ImportExport\Processor\Import\Validator\ValidationAggregateError;
8+
use Snowdog\Menu\Model\ImportExport\Processor\Import\Validator\ValidationException;
9+
10+
class InvalidNodes
11+
{
12+
/**
13+
* @var TreeTrace
14+
*/
15+
private $treeTrace;
16+
17+
/**
18+
* @var Manager
19+
*/
20+
private $manager;
21+
22+
public function __construct(TreeTrace $treeTrace, Manager $manager)
23+
{
24+
$this->treeTrace = $treeTrace;
25+
$this->manager = $manager;
26+
}
27+
28+
public function process(array &$data, ValidationAggregateError $error): array
29+
{
30+
return $this->stripInvalidNodes($data, $error);
31+
}
32+
33+
/**
34+
* @param array $data
35+
* @param ValidationAggregateError $validationAggregateError
36+
* @return array
37+
*/
38+
private function stripInvalidNodes(array &$data, ValidationAggregateError $validationAggregateError): array
39+
{
40+
foreach ($validationAggregateError->getErrors() as $error) {
41+
if ($error instanceof ValidationException) {
42+
if (empty($error->getInvalidNodePath())) {
43+
continue;
44+
}
45+
46+
$this->unsetItemByPath($error->getInvalidNodePath(), $data);
47+
$this->manager->addNoticeMessage(__(
48+
"Invalid node %1 not imported. %2",
49+
implode(' > ', $error->getInvalidNodePath()),
50+
$error->getMessage()
51+
));
52+
}
53+
}
54+
return $data;
55+
}
56+
57+
/**
58+
* Unsets specific $data element by $path
59+
*/
60+
private function unsetItemByPath(array $path, array &$data): void
61+
{
62+
$path = $this->updatePathValues($path);
63+
64+
$dataElement =& $data;
65+
$lastItemKey = array_pop($path);
66+
67+
foreach ($path as $key) {
68+
$dataElement =& $dataElement["nodes"][$key];
69+
}
70+
71+
$dataElement["nodes"][$lastItemKey] = null;
72+
}
73+
74+
private function updatePathValues(array $path): array
75+
{
76+
if ($this->treeTrace->isEnabledNodeIdAddend()) {
77+
foreach ($path as &$idx) {
78+
$idx--;
79+
}
80+
}
81+
82+
return $path;
83+
}
84+
}

Model/ImportExport/Processor/Import/Node.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ public function createNodes(
6868
?int $parentId = null
6969
): void {
7070
foreach ($nodes as $nodeData) {
71+
if ($nodeData === null) {
72+
continue;
73+
}
74+
7175
$node = $this->nodeFactory->create();
7276
$data = $this->dataProcessor->getData($nodeData, $menuId, $level, $position++, $parentId);
7377

Model/ImportExport/Processor/Import/Node/Validator/NodeType.php

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Snowdog\Menu\Model\ImportExport\Processor\Import\Node\Type\Cms;
1010
use Snowdog\Menu\Model\ImportExport\Processor\Import\Node\Validator\TreeTrace;
1111
use Snowdog\Menu\Model\ImportExport\Processor\Import\Validator\ValidationAggregateError;
12+
use Snowdog\Menu\Model\ImportExport\Processor\Import\Validator\ValidationException;
1213
use Snowdog\Menu\Model\ImportExport\Processor\NodeTypes;
1314
use Snowdog\Menu\Model\NodeTypeProvider;
1415

@@ -122,12 +123,18 @@ private function validateNodeTypeContent(array $node, $nodeId, array $treeTrace)
122123
}
123124

124125
if (!$isValid) {
126+
$treeTraceBreadcrumbs = $this->treeTrace->getBreadcrumbs($treeTrace, $nodeId);
125127
$this->validationAggregateError->addError(
126-
__(
127-
'Node "%1" %2 identifier "%3" is invalid.',
128-
$this->treeTrace->getBreadcrumbs($treeTrace, $nodeId),
129-
$node[NodeInterface::TYPE],
130-
$node[NodeInterface::CONTENT]
128+
new ValidationException(
129+
__(
130+
'Node "%1" %2 identifier "%3" is invalid.',
131+
$treeTraceBreadcrumbs,
132+
$node[NodeInterface::TYPE],
133+
$node[NodeInterface::CONTENT]
134+
),
135+
null,
136+
0,
137+
explode(' > ', $treeTraceBreadcrumbs)
131138
)
132139
);
133140
}

Model/ImportExport/Processor/Import/Node/Validator/TreeTrace.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,9 @@ public function disableNodeIdAddend(): void
4646
{
4747
$this->nodeIdAddend = 0;
4848
}
49+
50+
public function isEnabledNodeIdAddend(): bool
51+
{
52+
return (bool) $this->nodeIdAddend;
53+
}
4954
}

Model/ImportExport/Processor/Import/Validator/ValidationAggregateError.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Exception;
88
use Magento\Framework\Message\ManagerInterface as MessageManagerInterface;
9+
use Magento\Framework\Phrase;
910

1011
class ValidationAggregateError extends Exception
1112
{
@@ -25,7 +26,7 @@ public function __construct(MessageManagerInterface $messageManager)
2526
}
2627

2728
/**
28-
* @param string|\Magento\Framework\Phrase $error
29+
* @param string|Phrase|Exception $error
2930
*/
3031
public function addError($error): void
3132
{
@@ -39,10 +40,26 @@ public function getErrors(): array
3940

4041
public function flush(): void
4142
{
42-
foreach ($this->errors as $error) {
43-
$this->messageManager->addErrorMessage($error);
43+
foreach ($this->getErrorMessages() as $errorMessage) {
44+
$this->messageManager->addErrorMessage($errorMessage);
4445
}
4546

4647
$this->errors = [];
4748
}
49+
50+
public function getErrorMessages(): array
51+
{
52+
$errorMessages = [];
53+
foreach ($this->errors as $error) {
54+
if (is_string($error) || $error instanceof Phrase) {
55+
$errorMessages[] = $error;
56+
}
57+
58+
if ($error instanceof Exception) {
59+
$errorMessages[] = $error->getMessage();
60+
}
61+
}
62+
63+
return $errorMessages;
64+
}
4865
}

0 commit comments

Comments
 (0)