diff --git a/app/code/Magento/Backend/Block/GlobalSearch.php b/app/code/Magento/Backend/Block/GlobalSearch.php index f4a46283808f4..9af4e9faef761 100644 --- a/app/code/Magento/Backend/Block/GlobalSearch.php +++ b/app/code/Magento/Backend/Block/GlobalSearch.php @@ -3,19 +3,61 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Backend\Block; +use Magento\Backend\Model\GlobalSearch\SearchEntityFactory; +use Magento\Backend\Model\GlobalSearch\SearchEntity; +use Magento\Framework\App\ObjectManager; + /** * @api * @since 100.0.2 */ class GlobalSearch extends \Magento\Backend\Block\Template { + /** + * @var SearchEntityFactory + */ + private $searchEntityFactory; + /** * @var string */ protected $_template = 'Magento_Backend::system/search.phtml'; + /** + * @var array + */ + private $entityResources; + + /** + * @var array + */ + private $entityPaths; + + /** + * @param Template\Context $context + * @param array $data + * @param array $entityResources + * @param array $entityPaths + * @param SearchEntityFactory|null $searchEntityFactory + */ + public function __construct( + Template\Context $context, + array $data = [], + array $entityResources = [], + array $entityPaths = [], + SearchEntityFactory $searchEntityFactory = null + ) { + $this->entityResources = $entityResources; + $this->entityPaths = $entityPaths; + $this->searchEntityFactory = $searchEntityFactory ?: ObjectManager::getInstance() + ->get(SearchEntityFactory::class); + + parent::__construct($context, $data); + } + /** * Get components configuration * @return array @@ -34,4 +76,48 @@ public function getWidgetInitOptions() ] ]; } + + /** + * Get entities which are allowed to show. + * + * @return SearchEntity[] + */ + public function getEntitiesToShow() + { + $allowedEntityTypes = []; + $entitiesToShow = []; + + foreach ($this->entityResources as $entityType => $resource) { + if ($this->getAuthorization()->isAllowed($resource)) { + $allowedEntityTypes[] = $entityType; + } + } + + foreach ($allowedEntityTypes as $entityType) { + $url = $this->getUrlEntityType($entityType); + + $searchEntity = $this->searchEntityFactory->create(); + $searchEntity->setId('searchPreview' . $entityType); + $searchEntity->setTitle('in ' . $entityType); + $searchEntity->setUrl($url); + + $entitiesToShow[] = $searchEntity; + } + + return $entitiesToShow; + } + + /** + * Get url path by entity type. + * + * @param string $entityType + * + * @return string + */ + private function getUrlEntityType(string $entityType) + { + $urlPath = $this->entityPaths[$entityType] ?? ''; + + return $this->getUrl($urlPath); + } } diff --git a/app/code/Magento/Backend/Model/GlobalSearch/SearchEntity.php b/app/code/Magento/Backend/Model/GlobalSearch/SearchEntity.php new file mode 100644 index 0000000000000..18691802b9218 --- /dev/null +++ b/app/code/Magento/Backend/Model/GlobalSearch/SearchEntity.php @@ -0,0 +1,73 @@ +getData('id'); + } + + /** + * Get url. + * + * @return string + */ + public function getUrl() + { + return $this->getData('url'); + } + + /** + * Get title. + * + * @return string + */ + public function getTitle() + { + return $this->getData('title'); + } + + /** + * Set Id. + * + * @param string $value + */ + public function setId(string $value) + { + $this->setData('id', $value); + } + + /** + * Set url. + * + * @param string $value + */ + public function setUrl(string $value) + { + $this->setData('url', $value); + } + + /** + * Set title. + * + * @param string $value + */ + public function setTitle(string $value) + { + $this->setData('title', $value); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Block/GlobalSearchTest.php b/app/code/Magento/Backend/Test/Unit/Block/GlobalSearchTest.php new file mode 100644 index 0000000000000..0010ffad87524 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Block/GlobalSearchTest.php @@ -0,0 +1,123 @@ + \Magento\Catalog\Controller\Adminhtml\Product::ADMIN_RESOURCE, + 'Orders' => \Magento\Sales\Controller\Adminhtml\Order::ADMIN_RESOURCE, + 'Customers' => \Magento\Customer\Controller\Adminhtml\Index::ADMIN_RESOURCE, + 'Pages' => \Magento\Cms\Controller\Adminhtml\Page\Index::ADMIN_RESOURCE, + ]; + + /** + * @var array + */ + private $entityPaths = [ + 'Products' => 'catalog/product/index/', + 'Orders' => 'sales/order/index/', + 'Customers' => 'customer/index/index', + 'Pages' => 'cms/page/index/', + ]; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + + $this->authorization = $this->createMock(\Magento\Framework\AuthorizationInterface::class); + $this->urlBuilder = $this->createMock(\Magento\Framework\UrlInterface::class); + $context = $this->createMock(\Magento\Backend\Block\Template\Context::class); + + $context->expects($this->atLeastOnce())->method('getAuthorization')->willReturn($this->authorization); + $context->expects($this->atLeastOnce())->method('getUrlBuilder')->willReturn($this->urlBuilder); + + $this->searchEntityFactory = $this->createMock(\Magento\Backend\Model\GlobalSearch\SearchEntityFactory::class); + + $this->globalSearch = $objectManager->getObject( + GlobalSearch::class, + [ + 'context' => $context, + 'searchEntityFactory' => $this->searchEntityFactory, + 'entityResources' => $this->entityResources, + 'entityPaths' => $this->entityPaths, + ] + ); + } + + /** + * @param array $results + * @param int $expectedEntitiesQty + * + * @dataProvider getEntitiesToShowDataProvider + */ + public function testGetEntitiesToShow(array $results, int $expectedEntitiesQty) + { + $searchEntity = $this->createMock(SearchEntity::class); + + $this->authorization->expects($this->exactly(count($results)))->method('isAllowed') + ->willReturnOnConsecutiveCalls($results[0], $results[1], $results[2], $results[3]); + $this->urlBuilder->expects($this->exactly($expectedEntitiesQty)) + ->method('getUrl')->willReturn('some/url/is/here'); + $this->searchEntityFactory->expects($this->exactly($expectedEntitiesQty)) + ->method('create')->willReturn($searchEntity); + + $searchEntity->expects($this->exactly($expectedEntitiesQty))->method('setId'); + $searchEntity->expects($this->exactly($expectedEntitiesQty))->method('setTitle'); + $searchEntity->expects($this->exactly($expectedEntitiesQty))->method('setUrl'); + + $this->assertSame($expectedEntitiesQty, count($this->globalSearch->getEntitiesToShow())); + } + + public function getEntitiesToShowDataProvider() + { + return [ + [ + [true, false, true, false], + 2, + ], + [ + [true, true, true, true], + 4, + ], + [ + [false, false, false, false], + 0, + ], + ]; + } +} diff --git a/app/code/Magento/Backend/etc/adminhtml/di.xml b/app/code/Magento/Backend/etc/adminhtml/di.xml index 8b68cca4782c9..de8286e7f3ecc 100644 --- a/app/code/Magento/Backend/etc/adminhtml/di.xml +++ b/app/code/Magento/Backend/etc/adminhtml/di.xml @@ -155,4 +155,20 @@ Magento\Backend\Block\Template + + + + Magento_Catalog::products + Magento_Sales::sales_order + Magento_Customer::manage + Magento_Cms::page + + + catalog/product/index/ + sales/order/index/ + customer/index/index + cms/page/index/ + + + diff --git a/app/code/Magento/Backend/i18n/en_US.csv b/app/code/Magento/Backend/i18n/en_US.csv index f9f44f547e25b..aa28a670b9205 100644 --- a/app/code/Magento/Backend/i18n/en_US.csv +++ b/app/code/Magento/Backend/i18n/en_US.csv @@ -461,3 +461,7 @@ Pagination,Pagination "Alternative text for the next pages link in the pagination menu. If empty, default arrow image is used.","Alternative text for the next pages link in the pagination menu. If empty, default arrow image is used." "Anchor Text for Next","Anchor Text for Next" "Theme Name","Theme Name" +"In Products","In Products" +"In Orders","In Orders" +"In Customers","In Customers" +"In Pages","In Pages" diff --git a/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml b/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml index b50183ced29b4..3c65c0358eb57 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/system/search.phtml @@ -27,18 +27,15 @@