diff --git a/app/code/Magento/Customer/Model/Plugin/Customer/DataProviderWithDefaultAddresses/AddRequestParamToDataProviderRendererUrl.php b/app/code/Magento/Customer/Model/Plugin/Customer/DataProviderWithDefaultAddresses/AddRequestParamToDataProviderRendererUrl.php new file mode 100644 index 0000000000000..acc84d3dcff04 --- /dev/null +++ b/app/code/Magento/Customer/Model/Plugin/Customer/DataProviderWithDefaultAddresses/AddRequestParamToDataProviderRendererUrl.php @@ -0,0 +1,101 @@ +url = $url; + $this->request = $request; + $this->arrayManager = $arrayManager; + } + + /** + * Modify provider configuration and return meta + * + * @param DataProviderWithDefaultAddresses $subject + * @param array $meta + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetMeta(DataProviderWithDefaultAddresses $subject, array $meta) + { + $meta = $this->modifyProviderRenderUrl($meta); + return $meta; + } + + /** + * Add parent id into renderer url request + * + * @param array $meta + * @return array + */ + private function modifyProviderRenderUrl(array $meta) + { + $meta = $this->arrayManager->set( + 'address', + $meta, + [ + 'children' => [ + 'customer_address_listing' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'render_url' => $this->url->getUrl( + 'mui/index/render', + [ + 'parent_id' => $this->request->getParam('id'), + /* + * Set empty filters to prevent load filters from bookmark + * and sharing between customers + * */ + ContextInterface::FILTER_VAR => 0 + ] + ) + ] + ] + ] + ] + ] + ] + ); + return $meta; + } +} diff --git a/app/code/Magento/Customer/etc/adminhtml/di.xml b/app/code/Magento/Customer/etc/adminhtml/di.xml index 9f207ea8bebd1..8aaa50577decc 100644 --- a/app/code/Magento/Customer/etc/adminhtml/di.xml +++ b/app/code/Magento/Customer/etc/adminhtml/di.xml @@ -6,13 +6,13 @@ */ --> - + Magento\Customer\Model\Backend\Customer - + @@ -41,4 +41,7 @@ CustomerGridCollectionReporting + + + diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 065d87792665f..dbf862356bad2 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -11,7 +11,6 @@ customer_form.customer_form_data_source Customer Information - true diff --git a/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php b/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php index f5d3af44f71f4..1dfada38273ad 100644 --- a/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php +++ b/app/code/Magento/Ui/Component/Filters/Type/AbstractFilter.php @@ -3,14 +3,21 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Ui\Component\Filters\Type; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Ui\Api\BookmarkManagementInterface; use Magento\Ui\Component\AbstractComponent; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\Api\FilterBuilder; use Magento\Ui\Component\Filters\FilterModifier; +//phpcs:disable Magento2.Classes.AbstractApi + /** * Abstract class AbstractFilter * @api @@ -51,12 +58,16 @@ abstract class AbstractFilter extends AbstractComponent protected $filterModifier; /** + * AbstractFilter constructor + * * @param ContextInterface $context * @param UiComponentFactory $uiComponentFactory * @param FilterBuilder $filterBuilder * @param FilterModifier $filterModifier * @param array $components * @param array $data + * @param BookmarkManagementInterface|null $bookmarkManagement + * @param RequestInterface|null $request */ public function __construct( ContextInterface $context, @@ -64,13 +75,40 @@ public function __construct( FilterBuilder $filterBuilder, FilterModifier $filterModifier, array $components = [], - array $data = [] + array $data = [], + BookmarkManagementInterface $bookmarkManagement = null, + RequestInterface $request = null ) { $this->uiComponentFactory = $uiComponentFactory; $this->filterBuilder = $filterBuilder; parent::__construct($context, $components, $data); - $this->filterData = $this->getContext()->getFiltersParams(); $this->filterModifier = $filterModifier; + + $bookmarkManagement = $bookmarkManagement ?: ObjectManager::getInstance() + ->get(BookmarkManagementInterface::class); + $request = $request ?: ObjectManager::getInstance()->get(RequestInterface::class); + + $this->filterData = $this->getContext()->getFiltersParams(); + if ($this->filterData !== null) { + return; + } + + $bookmark = $bookmarkManagement->getByIdentifierNamespace( + 'current', + $context->getNamespace() + ); + + if ($bookmark !== null) { + $bookmarkConfig = $bookmark->getConfig(); + $this->filterData = $bookmarkConfig['current']['filters']['applied'] ?? []; + + $request->setParams( + [ + 'paging' => $bookmarkConfig['current']['paging'] ?? [], + 'search' => $bookmarkConfig['current']['search']['value'] ?? '' + ] + ); + } } /** @@ -84,7 +122,9 @@ public function getComponentName() } /** - * {@inheritdoc} + * Prepare filter component + * + * @inheridoc */ public function prepare() { diff --git a/app/code/Magento/Ui/Component/Filters/Type/Select.php b/app/code/Magento/Ui/Component/Filters/Type/Select.php index 06a821019b680..7fac34d499a99 100644 --- a/app/code/Magento/Ui/Component/Filters/Type/Select.php +++ b/app/code/Magento/Ui/Component/Filters/Type/Select.php @@ -3,11 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Ui\Component\Filters\Type; +use Magento\Framework\App\RequestInterface; use Magento\Framework\Data\OptionSourceInterface; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Ui\Api\BookmarkManagementInterface; use Magento\Ui\Component\Form\Element\Select as ElementSelect; use Magento\Ui\Component\Filters\FilterModifier; @@ -41,6 +44,8 @@ class Select extends AbstractFilter * @param OptionSourceInterface|null $optionsProvider * @param array $components * @param array $data + * @param BookmarkManagementInterface|null $bookmarkManagement + * @param RequestInterface|null $request */ public function __construct( ContextInterface $context, @@ -49,10 +54,21 @@ public function __construct( FilterModifier $filterModifier, OptionSourceInterface $optionsProvider = null, array $components = [], - array $data = [] + array $data = [], + BookmarkManagementInterface $bookmarkManagement = null, + RequestInterface $request = null ) { $this->optionsProvider = $optionsProvider; - parent::__construct($context, $uiComponentFactory, $filterBuilder, $filterModifier, $components, $data); + parent::__construct( + $context, + $uiComponentFactory, + $filterBuilder, + $filterModifier, + $components, + $data, + $bookmarkManagement, + $request + ); } /** diff --git a/app/code/Magento/Ui/DataProvider/Plugin/AddBookmarkAvailabilityFlag.php b/app/code/Magento/Ui/DataProvider/Plugin/AddBookmarkAvailabilityFlag.php new file mode 100644 index 0000000000000..d6ba75a84f107 --- /dev/null +++ b/app/code/Magento/Ui/DataProvider/Plugin/AddBookmarkAvailabilityFlag.php @@ -0,0 +1,83 @@ +bookmarkManagement = $bookmarkManagement; + $this->sanitizer = $sanitizer; + } + + /** + * Modify provider configuration and return meta + * + * @param DataProviderInterface $subject + * @param array $meta + * @return mixed + */ + public function afterGetMeta(DataProviderInterface $subject, array $meta) + { + $this->modifyProviderConfigData($subject); + + return $meta; + } + + /** + * Modify provider configuration + * + * @param DataProviderInterface $dataProvider + */ + private function modifyProviderConfigData(DataProviderInterface $dataProvider) + { + $configData = $dataProvider->getConfigData(); + if (!isset($configData['component']) + || $configData['component'] !== 'Magento_Ui/js/grid/provider' + || !isset($configData['namespace']) + ) { + return; + } + + $bookmark = $this->bookmarkManagement->getByIdentifierNamespace( + 'current', + $configData['namespace'] + ); + + $dataProvider->setConfigData($this->sanitizer->sanitize( + array_replace( + $configData, + [ + 'firstLoad' => $bookmark !== null ? false : true + ] + ) + )); + } +} diff --git a/app/code/Magento/Ui/Model/BookmarkManagement.php b/app/code/Magento/Ui/Model/BookmarkManagement.php index 0659ce2ded7bc..78e868a65daf9 100644 --- a/app/code/Magento/Ui/Model/BookmarkManagement.php +++ b/app/code/Magento/Ui/Model/BookmarkManagement.php @@ -3,42 +3,58 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Ui\Model; -class BookmarkManagement implements \Magento\Ui\Api\BookmarkManagementInterface +use Magento\Authorization\Model\UserContextInterface; +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Ui\Api\BookmarkManagementInterface; +use Magento\Ui\Api\BookmarkRepositoryInterface; + +/** + * Bookmark Management class provide functional for retrieving bookmarks by params + * @SuppressWarnings(PHPMD.LongVariable) + */ +class BookmarkManagement implements BookmarkManagementInterface { /** - * @var \Magento\Ui\Api\BookmarkRepositoryInterface + * @var BookmarkRepositoryInterface */ protected $bookmarkRepository; /** - * @var \Magento\Framework\Api\SearchCriteriaBuilder + * @var SearchCriteriaBuilder */ protected $searchCriteriaBuilder; /** - * @var \Magento\Framework\Api\FilterBuilder + * @var FilterBuilder */ protected $filterBuilder; /** - * @var \Magento\Authorization\Model\UserContextInterface + * @var UserContextInterface */ protected $userContext; /** - * @param \Magento\Ui\Api\BookmarkRepositoryInterface $bookmarkRepository - * @param \Magento\Framework\Api\FilterBuilder $filterBuilder - * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder - * @param \Magento\Authorization\Model\UserContextInterface $userContext + * @var array + */ + private $bookmarkRegistry = []; + + /** + * @param BookmarkRepositoryInterface $bookmarkRepository + * @param FilterBuilder $filterBuilder + * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param UserContextInterface $userContext */ public function __construct( - \Magento\Ui\Api\BookmarkRepositoryInterface $bookmarkRepository, - \Magento\Framework\Api\FilterBuilder $filterBuilder, - \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder, - \Magento\Authorization\Model\UserContextInterface $userContext + BookmarkRepositoryInterface $bookmarkRepository, + FilterBuilder $filterBuilder, + SearchCriteriaBuilder $searchCriteriaBuilder, + UserContextInterface $userContext ) { $this->bookmarkRepository = $bookmarkRepository; $this->searchCriteriaBuilder = $searchCriteriaBuilder; @@ -47,9 +63,12 @@ public function __construct( } /** - * {@inheritdoc} + * Create search criteria builder with namespace and user filters + * + * @param string $namespace + * @return void */ - public function loadByNamespace($namespace) + private function prepareSearchCriteriaBuilderByNamespace(string $namespace): void { $userIdFilter = $this->filterBuilder ->setField('user_id') @@ -64,47 +83,42 @@ public function loadByNamespace($namespace) $this->searchCriteriaBuilder->addFilters([$userIdFilter]); $this->searchCriteriaBuilder->addFilters([$namespaceFilter]); + } + /** + * @inheritdoc + */ + public function loadByNamespace($namespace) + { + $this->prepareSearchCriteriaBuilderByNamespace($namespace); $searchCriteria = $this->searchCriteriaBuilder->create(); - $searchResults = $this->bookmarkRepository->getList($searchCriteria); - - return $searchResults; + return $this->bookmarkRepository->getList($searchCriteria); } /** - * {@inheritdoc} + * @inheritdoc */ public function getByIdentifierNamespace($identifier, $namespace) { - $userIdFilter = $this->filterBuilder - ->setField('user_id') - ->setConditionType('eq') - ->setValue($this->userContext->getUserId()) - ->create(); - $identifierFilter = $this->filterBuilder - ->setField('identifier') - ->setConditionType('eq') - ->setValue($identifier) - ->create(); - $namespaceFilter = $this->filterBuilder - ->setField('namespace') - ->setConditionType('eq') - ->setValue($namespace) - ->create(); + if (!isset($this->bookmarkRegistry[$identifier . $namespace])) { + $this->prepareSearchCriteriaBuilderByNamespace($namespace); + $identifierFilter = $this->filterBuilder + ->setField('identifier') + ->setConditionType('eq') + ->setValue($identifier) + ->create(); + $this->searchCriteriaBuilder->addFilters([$identifierFilter]); - $this->searchCriteriaBuilder->addFilters([$userIdFilter]); - $this->searchCriteriaBuilder->addFilters([$identifierFilter]); - $this->searchCriteriaBuilder->addFilters([$namespaceFilter]); - - $searchCriteria = $this->searchCriteriaBuilder->create(); - $searchResults = $this->bookmarkRepository->getList($searchCriteria); - if ($searchResults->getTotalCount() > 0) { - foreach ($searchResults->getItems() as $searchResult) { - $bookmark = $this->bookmarkRepository->getById($searchResult->getId()); - return $bookmark; + $searchCriteria = $this->searchCriteriaBuilder->create(); + $searchResults = $this->bookmarkRepository->getList($searchCriteria); + if ($searchResults->getTotalCount() > 0) { + $items = $searchResults->getItems(); + $this->bookmarkRegistry[$identifier . $namespace] = array_shift($items); + } else { + $this->bookmarkRegistry[$identifier . $namespace] = null; } } - return null; + return $this->bookmarkRegistry[$identifier . $namespace]; } } diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php index dd8456460d6b3..f56147570e64d 100644 --- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php +++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateRangeTest.php @@ -8,11 +8,13 @@ namespace Magento\Ui\Test\Unit\Component\Filters\Type; use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\App\RequestInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface as UiContext; use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; use Magento\Framework\View\Element\UiComponent\Processor; use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Ui\Api\BookmarkManagementInterface; use Magento\Ui\Component\Filters\FilterModifier; use Magento\Ui\Component\Filters\Type\DateRange; use Magento\Ui\Component\Form\Element\DataType\Date as FormDate; @@ -41,13 +43,23 @@ class DateRangeTest extends TestCase */ protected $filterModifierMock; + /** + * @var BookmarkManagementInterface|MockObject + */ + private $bookmarkManagementMock; + + /** + * @var RequestInterface|MockObject + */ + private $requestMock; + /** * Set up */ protected function setUp(): void { $this->contextMock = $this->getMockForAbstractClass( - \Magento\Framework\View\Element\UiComponent\ContextInterface::class, + UiContext::class, [], '', false @@ -61,6 +73,16 @@ protected function setUp(): void FilterModifier::class, ['applyFilterModifier'] ); + + $this->bookmarkManagementMock = $this->getMockForAbstractClass( + BookmarkManagementInterface::class + ); + $this->bookmarkManagementMock->expects($this->once()) + ->method('getByIdentifierNamespace') + ->willReturn(null); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->getMockForAbstractClass(); } /** @@ -76,7 +98,10 @@ public function testGetComponentName() $this->uiComponentFactory, $this->filterBuilderMock, $this->filterModifierMock, - [] + [], + [], + $this->bookmarkManagementMock, + $this->requestMock ); $this->assertSame(DateRange::NAME, $dateRange->getComponentName()); } @@ -148,7 +173,9 @@ public function testPrepare($name, $filterData, $expectedCondition) $this->filterBuilderMock, $this->filterModifierMock, [], - ['name' => $name] + ['name' => $name], + $this->bookmarkManagementMock, + $this->requestMock ); $dateRange->prepare(); diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php index ec3d864a2871a..9d78d98789298 100644 --- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php +++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/DateTest.php @@ -9,10 +9,12 @@ use Magento\Framework\Api\Filter; use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\App\RequestInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; use Magento\Framework\View\Element\UiComponent\Processor; use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Ui\Api\BookmarkManagementInterface; use Magento\Ui\Component\Filters\FilterModifier; use Magento\Ui\Component\Filters\Type\Date; use Magento\Ui\Component\Form\Element\DataType\Date as FormDate; @@ -49,6 +51,16 @@ class DateTest extends TestCase */ private $dataProviderMock; + /** + * @var BookmarkManagementInterface|MockObject + */ + private $bookmarkManagementMock; + + /** + * @var RequestInterface|MockObject + */ + private $requestMock; + /** * Set up */ @@ -69,6 +81,13 @@ protected function setUp(): void ->getMock(); $this->dataProviderMock = $this->getMockForAbstractClass(DataProviderInterface::class); + + $this->bookmarkManagementMock = $this->getMockForAbstractClass( + BookmarkManagementInterface::class + ); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->getMockForAbstractClass(); } /** @@ -79,12 +98,18 @@ protected function setUp(): void public function testGetComponentName() { $this->contextMock->expects(static::never())->method('getProcessor'); + $this->bookmarkManagementMock->expects($this->once()) + ->method('getByIdentifierNamespace') + ->willReturn(null); $date = new Date( $this->contextMock, $this->uiComponentFactory, $this->filterBuilderMock, $this->filterModifierMock, - [] + [], + [], + $this->bookmarkManagementMock, + $this->requestMock ); static::assertSame(Date::NAME, $date->getComponentName()); @@ -130,6 +155,8 @@ public function testPrepare(string $name, bool $showsTime, array $filterData, ?a ->method('getDataProvider') ->willReturn($this->dataProviderMock); + $this->bookmarkManagementMock->expects($this->never())->method('getByIdentifierNamespace'); + if ($expectedCondition !== null) { $this->processFilters($name, $showsTime, $filterData, $expectedCondition, $uiComponent); } @@ -148,7 +175,9 @@ public function testPrepare(string $name, bool $showsTime, array $filterData, ?a [ 'name' => $name, 'config' => ['options' => ['showsTime' => $showsTime]], - ] + ], + $this->bookmarkManagementMock, + $this->requestMock ); $date->prepare(); } @@ -209,8 +238,10 @@ public function getPrepareDataProvider() 'showsTime' => false, 'filterData' => ['test_date' => ['from' => '11-05-2015', 'to' => '11-05-2015']], 'expectedCondition' => [ - 'date_from' => '2015-05-11 00:00:00', 'type_from' => 'gteq', - 'date_to' => '2015-05-11 23:59:59', 'type_to' => 'lteq' + 'date_from' => '2015-05-11 00:00:00', + 'type_from' => 'gteq', + 'date_to' => '2015-05-11 23:59:59', + 'type_to' => 'lteq' ], ], [ @@ -230,8 +261,10 @@ public function getPrepareDataProvider() 'showsTime' => true, 'filterData' => ['test_date' => ['from' => '11-05-2015 10:20:00', 'to' => '11-05-2015 18:25:00']], 'expectedCondition' => [ - 'date_from' => '2015-05-11 10:20:00', 'type_from' => 'gteq', - 'date_to' => '2015-05-11 18:25:00', 'type_to' => 'lteq' + 'date_from' => '2015-05-11 10:20:00', + 'type_from' => 'gteq', + 'date_to' => '2015-05-11 18:25:00', + 'type_to' => 'lteq' ], ], ]; diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php index 83ad794107288..71609cf3c56e4 100644 --- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php +++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php @@ -9,11 +9,13 @@ use Magento\Framework\Api\Filter; use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\App\RequestInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; use Magento\Framework\View\Element\UiComponent\Processor; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Ui\Api\BookmarkManagementInterface; use Magento\Ui\Component\Filters\FilterModifier; use Magento\Ui\Component\Filters\Type\Input; use PHPUnit\Framework\MockObject\MockObject; @@ -41,6 +43,16 @@ class InputTest extends TestCase */ protected $filterModifierMock; + /** + * @var BookmarkManagementInterface|MockObject + */ + private $bookmarkManagementMock; + + /** + * @var RequestInterface|MockObject + */ + private $requestMock; + /** * @inheritdoc */ @@ -61,6 +73,13 @@ protected function setUp(): void FilterModifier::class, ['applyFilterModifier'] ); + + $this->bookmarkManagementMock = $this->getMockForAbstractClass( + BookmarkManagementInterface::class + ); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->getMockForAbstractClass(); } /** @@ -71,12 +90,18 @@ protected function setUp(): void public function testGetComponentName(): void { $this->contextMock->expects($this->never())->method('getProcessor'); + $this->bookmarkManagementMock->expects($this->once()) + ->method('getByIdentifierNamespace') + ->willReturn(null); $date = new Input( $this->contextMock, $this->uiComponentFactory, $this->filterBuilderMock, $this->filterModifierMock, - [] + [], + [], + $this->bookmarkManagementMock, + $this->requestMock ); $this->assertSame(Input::NAME, $date->getComponentName()); @@ -129,6 +154,8 @@ public function testPrepare(string $name, array $filterData, ?array $expectedCon ->method('getDataProvider') ->willReturn($dataProvider); + $this->bookmarkManagementMock->expects($this->never())->method('getByIdentifierNamespace'); + $this->uiComponentFactory->expects($this->any()) ->method('create') ->with($name, Input::COMPONENT, ['context' => $this->contextMock]) @@ -165,7 +192,9 @@ public function testPrepare(string $name, array $filterData, ?array $expectedCon $this->filterBuilderMock, $this->filterModifierMock, [], - ['name' => $name] + ['name' => $name], + $this->bookmarkManagementMock, + $this->requestMock ); $date->prepare(); diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php index e0f140b3ae901..886a85f88da15 100644 --- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php +++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/RangeTest.php @@ -9,10 +9,12 @@ use Magento\Framework\Api\Filter; use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\App\RequestInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; use Magento\Framework\View\Element\UiComponent\Processor; use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Ui\Api\BookmarkManagementInterface; use Magento\Ui\Component\Filters\FilterModifier; use Magento\Ui\Component\Filters\Type\Range; use PHPUnit\Framework\MockObject\MockObject; @@ -40,6 +42,16 @@ class RangeTest extends TestCase */ protected $filterModifierMock; + /** + * @var BookmarkManagementInterface|MockObject + */ + private $bookmarkManagementMock; + + /** + * @var RequestInterface|MockObject + */ + private $requestMock; + /** * Set up */ @@ -57,6 +69,12 @@ protected function setUp(): void FilterModifier::class, ['applyFilterModifier'] ); + $this->bookmarkManagementMock = $this->getMockForAbstractClass( + BookmarkManagementInterface::class + ); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->getMockForAbstractClass(); } /** @@ -67,12 +85,18 @@ protected function setUp(): void public function testGetComponentName() { $this->contextMock->expects($this->never())->method('getProcessor'); + $this->bookmarkManagementMock->expects($this->once()) + ->method('getByIdentifierNamespace') + ->willReturn(null); $range = new Range( $this->contextMock, $this->uiComponentFactory, $this->filterBuilderMock, $this->filterModifierMock, - [] + [], + [], + $this->bookmarkManagementMock, + $this->requestMock ); $this->assertSame(Range::NAME, $range->getComponentName()); @@ -133,13 +157,17 @@ public function testPrepare($name, $filterData, $expectedCalls) ->method('addFilter') ->with($filter); + $this->bookmarkManagementMock->expects($this->never())->method('getByIdentifierNamespace'); + $range = new Range( $this->contextMock, $this->uiComponentFactory, $this->filterBuilderMock, $this->filterModifierMock, [], - ['name' => $name] + ['name' => $name], + $this->bookmarkManagementMock, + $this->requestMock ); $range->prepare(); } diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php index 83de1a87a981c..ef3071d6155d0 100644 --- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php +++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/SelectTest.php @@ -9,12 +9,14 @@ use Magento\Framework\Api\Filter; use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\App\RequestInterface; use Magento\Framework\Data\OptionSourceInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; use Magento\Framework\View\Element\UiComponent\Processor; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Ui\Api\BookmarkManagementInterface; use Magento\Ui\Component\Filters\FilterModifier; use Magento\Ui\Component\Filters\Type\Select; use PHPUnit\Framework\MockObject\MockObject; @@ -42,6 +44,16 @@ class SelectTest extends TestCase */ protected $filterModifierMock; + /** + * @var BookmarkManagementInterface|MockObject + */ + private $bookmarkManagementMock; + + /** + * @var RequestInterface|MockObject + */ + private $requestMock; + /** * Set up */ @@ -62,6 +74,13 @@ protected function setUp(): void FilterModifier::class, ['applyFilterModifier'] ); + + $this->bookmarkManagementMock = $this->getMockForAbstractClass( + BookmarkManagementInterface::class + ); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->getMockForAbstractClass(); } /** @@ -72,13 +91,19 @@ protected function setUp(): void public function testGetComponentName() { $this->contextMock->expects($this->never())->method('getProcessor'); + $this->bookmarkManagementMock->expects($this->once()) + ->method('getByIdentifierNamespace') + ->willReturn(null); $date = new Select( $this->contextMock, $this->uiComponentFactory, $this->filterBuilderMock, $this->filterModifierMock, null, - [] + [], + [], + $this->bookmarkManagementMock, + $this->requestMock ); $this->assertSame(Select::NAME, $date->getComponentName()); @@ -132,6 +157,8 @@ public function testPrepare($data, $filterData, $expectedCondition) ->method('getDataProvider') ->willReturn($dataProvider); + $this->bookmarkManagementMock->expects($this->never())->method('getByIdentifierNamespace'); + if ($expectedCondition !== null) { $filterMock = $this->createMock(Filter::class); $this->filterBuilderMock->expects($this->any()) @@ -173,7 +200,9 @@ public function testPrepare($data, $filterData, $expectedCondition) $this->filterModifierMock, $selectOptions, [], - $data + $data, + $this->bookmarkManagementMock, + $this->requestMock ); $date->prepare(); diff --git a/app/code/Magento/Ui/Test/Unit/Model/BookmarkManagementTest.php b/app/code/Magento/Ui/Test/Unit/Model/BookmarkManagementTest.php index 45693cebf4042..3bf4e287d7214 100644 --- a/app/code/Magento/Ui/Test/Unit/Model/BookmarkManagementTest.php +++ b/app/code/Magento/Ui/Test/Unit/Model/BookmarkManagementTest.php @@ -140,10 +140,8 @@ public function testGetByIdentifierNamespace() Filter::KEY_CONDITION_TYPE => 'eq' ] ); - $bookmarkId = 1; $bookmark = $this->getMockBuilder(BookmarkInterface::class) ->getMockForAbstractClass(); - $bookmark->expects($this->once())->method('getId')->willReturn($bookmarkId); $searchCriteria = $this->getMockBuilder(SearchCriteriaInterface::class) ->getMockForAbstractClass(); $this->filterBuilder->expects($this->at(0)) @@ -169,10 +167,6 @@ public function testGetByIdentifierNamespace() ->method('getList') ->with($searchCriteria) ->willReturn($searchResult); - $this->bookmarkRepository->expects($this->once()) - ->method('getById') - ->with($bookmarkId) - ->willReturn($bookmark); $this->assertEquals( $bookmark, $this->bookmarkManagement->getByIdentifierNamespace($identifier, $namespace) diff --git a/app/code/Magento/Ui/etc/adminhtml/di.xml b/app/code/Magento/Ui/etc/adminhtml/di.xml index e220581c42c24..32a05c91cf688 100644 --- a/app/code/Magento/Ui/etc/adminhtml/di.xml +++ b/app/code/Magento/Ui/etc/adminhtml/di.xml @@ -61,4 +61,7 @@ + + + diff --git a/app/code/Magento/Ui/view/base/web/js/grid/provider.js b/app/code/Magento/Ui/view/base/web/js/grid/provider.js index 021ae83eb1c7d..71a93487ea043 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/provider.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/provider.js @@ -21,6 +21,7 @@ define([ return Element.extend({ defaults: { + initialized: false, firstLoad: true, lastError: false, storageConfig: { @@ -48,16 +49,31 @@ define([ _.bindAll(this, 'onReload'); this._super() - .initStorage() - .clearData(); - - // Load data when there will - // be no more pending assets. - resolver(this.reload, this); + .initStorage(); + + if (this.firstLoad) { + this.clearData(); + // Load data when there will + // be no more pending assets. + resolver(this.reload, this); + } else { + /* Call set data with predefined data for correct rendering action column */ + this.setData(this.data); + + resolver(this.triggerReloaded, this); + } return this; }, + /** + * Trigger reloaded event + */ + triggerReloaded: function () { + this.initialized = true; + this.trigger('reloaded'); + }, + /** * Initializes storage component. * @@ -136,7 +152,7 @@ define([ onParamsChange: function () { // It's necessary to make a reload only // after the initial loading has been made. - if (!this.firstLoad) { + if (this.initialized) { this.reload(); } }, @@ -151,7 +167,7 @@ define([ this.set('lastError', true); - this.firstLoad = false; + this.initialized = true; alert({ content: $t('Something went wrong.') @@ -164,7 +180,7 @@ define([ * @param {Object} data - Retrieved data object. */ onReload: function (data) { - this.firstLoad = false; + this.initialized = true; this.set('lastError', false); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProductsTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProductsTest.php index ea96514ebde32..a28df3edbce04 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProductsTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProductsTest.php @@ -103,7 +103,10 @@ public function testAddManuallyConfigurationsWithNotFilterableInGridAttribute(): 'test_configurable' ], ]); - $context = $this->objectManager->create(ContextInterface::class, ['request' => $request]); + $context = $this->objectManager->create(ContextInterface::class, [ + 'request' => $request, + 'namespace' => ConfigurablePanel::ASSOCIATED_PRODUCT_LISTING + ]); /** @var UiComponentFactory $uiComponentFactory */ $uiComponentFactory = $this->objectManager->get(UiComponentFactory::class); $uiComponent = $uiComponentFactory->create( diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php b/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php index 8f980d82d4be0..57d7ca52ff756 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponent/Context.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Framework\View\Element\UiComponent; use Magento\Framework\App\ObjectManager; @@ -225,7 +226,7 @@ public function getRequestParam($key, $defaultValue = null) */ public function getFiltersParams() { - return $this->getRequestParam(self::FILTER_VAR, []); + return $this->getRequestParam(self::FILTER_VAR); } /** @@ -233,7 +234,7 @@ public function getFiltersParams() */ public function getFilterParam($key, $defaultValue = null) { - $filter = $this->getFiltersParams(); + $filter = $this->getFiltersParams() ?? []; return $filter[$key] ?? $defaultValue; } @@ -386,7 +387,7 @@ public function getUrl($route = '', $params = []) * @param UiComponentInterface $component * @return void */ - protected function prepareDataSource(array & $data, UiComponentInterface $component) + protected function prepareDataSource(array &$data, UiComponentInterface $component) { $childComponents = $component->getChildComponents(); if (!empty($childComponents)) { diff --git a/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php b/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php index 5e1bc93b9c033..cb72dd6aacd5e 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php @@ -159,9 +159,9 @@ protected function createChildComponent( $components = array_filter($components); $componentArguments['components'] = $components; - /** - * Prevent passing ACL restricted blocks to htmlContent constructor - */ + /** + * Prevent passing ACL restricted blocks to htmlContent constructor + */ if (isset($componentArguments['block']) && !$componentArguments['block']) { return null; } @@ -235,7 +235,7 @@ public function create($identifier, $name = null, array $arguments = []) list($className, $componentArguments) = $this->argumentsResolver($identifier, $rawComponentData); $componentArguments = array_replace_recursive($componentArguments, $arguments); $children = isset($componentArguments['data']['config']['children']) ? - $componentArguments['data']['config']['children'] : []; + $componentArguments['data']['config']['children'] : []; $children = $this->getBundleChildren($children); } @@ -280,7 +280,7 @@ protected function getBundleChildren(array $children = []) foreach ($children as $identifier => $config) { if (!isset($config['componentType'])) { throw new LocalizedException( - new Phrase( + __( 'The "componentType" configuration parameter is required for the "%1" component.', $identifier ) @@ -289,7 +289,7 @@ protected function getBundleChildren(array $children = []) if (!isset($componentArguments['context'])) { throw new LocalizedException( - new \Magento\Framework\Phrase( + __( 'An error occurred with the UI component. Each component needs context. Verify and try again.' ) ); @@ -327,6 +327,12 @@ protected function mergeMetadata($identifier, array $bundleComponents, $reverseM $dataProvider = $this->getDataProvider($identifier, $bundleComponents); if ($dataProvider instanceof DataProviderInterface) { //Dynamic meta from data providers should not contain templates. + $dataProvider->setConfigData($this->sanitizer->sanitize(array_merge( + $dataProvider->getConfigData(), + [ + 'namespace' => $identifier + ] + ))); $metadata = $dataProvider->getMeta(); $metadata = [ $identifier => $this->sanitizer->sanitizeComponentMetadata(['children' => $metadata])