├── Api ├── CustomEntityAttributeRepositoryInterface.php ├── CustomEntityRepositoryInterface.php └── Data │ ├── CustomEntityAttributeInterface.php │ ├── CustomEntityAttributeSearchResultsInterface.php │ ├── CustomEntityInterface.php │ └── CustomEntitySearchResultsInterface.php ├── Block ├── Adminhtml │ ├── Attribute │ │ └── Edit │ │ │ └── Tab │ │ │ ├── Front.php │ │ │ └── Main.php │ ├── Entity.php │ └── Set │ │ └── Main.php ├── CustomEntity │ ├── Image.php │ ├── ImageFactory.php │ └── View.php ├── Html │ └── Pager.php └── Set │ ├── Entity │ └── Renderer.php │ └── View.php ├── Controller ├── Adminhtml │ ├── Attribute │ │ ├── Builder.php │ │ ├── Delete.php │ │ ├── Edit.php │ │ ├── Index.php │ │ ├── NewAction.php │ │ ├── Save.php │ │ └── Validate.php │ ├── Entity │ │ ├── Builder.php │ │ ├── Delete.php │ │ ├── Edit.php │ │ ├── Index.php │ │ ├── MassDelete.php │ │ ├── NewAction.php │ │ ├── Reload.php │ │ └── Save.php │ └── Set │ │ ├── Add.php │ │ ├── Delete.php │ │ ├── Edit.php │ │ ├── Index.php │ │ └── Save.php ├── Entity │ └── View.php ├── Router.php └── Set │ └── View.php ├── Model ├── CustomEntity.php ├── CustomEntity │ ├── Attribute.php │ └── AttributeSet │ │ ├── Options.php │ │ └── Url.php ├── CustomEntityAttributeRepository.php ├── CustomEntityRepository.php ├── ResourceModel │ ├── CustomEntity.php │ └── CustomEntity │ │ ├── Attribute │ │ ├── Collection.php │ │ └── Grid │ │ │ └── Collection.php │ │ ├── AttributeSet │ │ └── Url.php │ │ ├── Collection.php │ │ └── MediaImageDeleteProcessor.php ├── Sitemap │ ├── ConfigReader.php │ └── CustomEntityProvider.php └── Source │ └── Attribute │ └── CustomEntity.php ├── Setup ├── CustomEntitySetup.php └── Patch │ ├── Data │ ├── CustomEntityAttributeSetIdMigration.php │ └── PatchData.php │ └── Schema │ └── RemoveCatalogAttributeCustomEntitySetId.php ├── Ui └── DataProvider │ └── CustomEntity │ ├── Form │ ├── CustomEntityDataProvider.php │ └── Modifier │ │ ├── AttributeSet.php │ │ └── CustomEntityAttribute.php │ └── Listing │ ├── AddStoreFieldToCollection.php │ └── CustomEntityDataProvider.php ├── ViewModel ├── Attribute │ └── Data.php └── Output.php ├── composer.json ├── etc ├── acl.xml ├── adminhtml │ ├── di.xml │ ├── menu.xml │ ├── routes.xml │ └── system.xml ├── config.xml ├── db_schema.xml ├── db_schema_whitelist.json ├── di.xml ├── events.xml ├── frontend │ ├── di.xml │ └── routes.xml └── module.xml ├── phpstan.neon.dist ├── registration.php └── view ├── adminhtml ├── layout │ ├── custom_entity_attribute.xml │ ├── custom_entity_attribute_edit.xml │ ├── custom_entity_attribute_index.xml │ ├── custom_entity_entity_edit.xml │ ├── custom_entity_entity_form.xml │ ├── custom_entity_entity_index.xml │ ├── custom_entity_entity_new.xml │ ├── custom_entity_entity_reload.xml │ ├── custom_entity_set_add.xml │ ├── custom_entity_set_edit.xml │ └── custom_entity_set_index.xml └── ui_component │ ├── custom_entity_attribute_listing.xml │ ├── custom_entity_entity_form.xml │ └── custom_entity_entity_listing.xml └── frontend ├── layout ├── smile_custom_entity_entity_renderers.xml ├── smile_custom_entity_entity_view.xml └── smile_custom_entity_set_view.xml └── templates ├── custom_entity ├── image.phtml ├── view.phtml └── view │ └── image.phtml ├── html └── pager.phtml └── set ├── entity └── default.phtml └── view.phtml /Api/CustomEntityAttributeRepositoryInterface.php: -------------------------------------------------------------------------------- 1 | yesNo = $yesNo; 40 | } 41 | 42 | /** 43 | * @inheritdoc 44 | * @SuppressWarnings(PHPMD.CamelCaseMethodName) 45 | */ 46 | protected function _prepareForm() 47 | { 48 | /** @var DataObject $attributeObject */ 49 | $attributeObject = $this->getAttributeObject(); 50 | 51 | /** @var \Magento\Framework\Data\Form $form */ 52 | $form = $this->_formFactory->create( 53 | ['data' => ['id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post']] 54 | ); 55 | 56 | $fieldset = $form->addFieldset('front_fieldset', ['legend' => __('Storefront Properties')]); 57 | 58 | $fieldset->addField('is_wysiwyg_enabled', 'select', [ 59 | 'name' => 'is_wysiwyg_enabled', 60 | 'label' => __('Enable WYSIWYG'), 61 | 'title' => __('Enable WYSIWYG'), 62 | 'values' => $this->yesNo->toOptionArray(), 63 | ]); 64 | 65 | $fieldset->addField('is_html_allowed_on_front', 'select', [ 66 | 'name' => 'is_html_allowed_on_front', 67 | 'label' => __('Allow HTML Tags on Storefront'), 68 | 'title' => __('Allow HTML Tags on Storefront'), 69 | 'values' => $this->yesNo->toOptionArray(), 70 | ]); 71 | 72 | $this->setForm($form); 73 | $form->setValues($attributeObject->getData()); 74 | 75 | return parent::_prepareForm(); 76 | } 77 | 78 | /** 79 | * Retrieve attribute object from registry 80 | */ 81 | private function getAttributeObject(): ?CustomEntityAttributeInterface 82 | { 83 | return $this->_coreRegistry->registry('entity_attribute'); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Block/Adminhtml/Attribute/Edit/Tab/Main.php: -------------------------------------------------------------------------------- 1 | attributeSetOptions = $attributeSetOptions; 50 | } 51 | 52 | /** 53 | * @inheritDoc 54 | */ 55 | protected function _prepareForm(): self 56 | { 57 | parent::_prepareForm(); 58 | 59 | $form = $this->getForm(); 60 | $fieldset = $form->getElement('base_fieldset'); 61 | 62 | // Add input to select custom entity type. 63 | $fieldset->addField( 64 | 'custom_entity_attribute_set_id', 65 | 'select', 66 | [ 67 | 'name' => 'custom_entity_attribute_set_id', 68 | 'label' => __('Custom entity type'), 69 | 'title' => __('Custom entity type'), 70 | 'component' => 'Magento_Catalog/js/components/visible-on-option/fieldset', 71 | 'values' => array_merge( 72 | [['value' => null, 'label' => __('Select...')]], 73 | $this->attributeSetOptions->toOptionArray() 74 | ), 75 | 'visible' => 'false', 76 | ], 77 | 'frontend_input' 78 | ); 79 | 80 | /** @var Dependence $block */ 81 | $block = $this->getLayout()->createBlock(Dependence::class); 82 | 83 | $block->addFieldMap( 84 | "frontend_input", 85 | 'frontend_input_type' 86 | )->addFieldMap( 87 | "custom_entity_attribute_set_id", 88 | 'custom_entity_attribute_set_id' 89 | )->addFieldDependence( 90 | 'custom_entity_attribute_set_id', 91 | 'frontend_input_type', 92 | 'smile_custom_entity_select' 93 | ); 94 | 95 | //Added dependency between 'Custom entity type' and 'Input Type'. 96 | $this->setChild('form_after', $block); 97 | 98 | // Disable 'Custom entity type' input if the attribute is already created. 99 | if ($this->getAttributeObject() && $this->getAttributeObject()->getAttributeId()) { 100 | $form->getElement('custom_entity_attribute_set_id')->setDisabled(1); 101 | } 102 | 103 | return $this; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Block/Adminhtml/Entity.php: -------------------------------------------------------------------------------- 1 | _collectionFactory = $attributeCollectionFactory; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Block/CustomEntity/Image.php: -------------------------------------------------------------------------------- 1 | setTemplate($data['template']); 28 | unset($data['template']); 29 | } 30 | 31 | parent::__construct($context, $data); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Block/CustomEntity/ImageFactory.php: -------------------------------------------------------------------------------- 1 | objectManager = $objectManager; 30 | $this->instanceName = $instanceName; 31 | } 32 | 33 | /** 34 | * Return custom entity image block. 35 | * 36 | * @param CustomEntityInterface $entity Current custom entity. 37 | */ 38 | public function create(CustomEntityInterface $entity): ?Image 39 | { 40 | 41 | /** @var \Smile\ScopedEav\Model\AbstractEntity $entity */ 42 | $data = [ 43 | 'data' => [ 44 | 'template' => 'Smile_CustomEntity::custom_entity/image.phtml', 45 | 'image_url' => $entity->getImageUrl('image'), 46 | 'image_alt' => $entity->getName(), 47 | ], 48 | ]; 49 | 50 | // @codingStandardsIgnoreLine Factory class (MEQP2.Classes.ObjectManager.ObjectManagerFound) 51 | return $this->objectManager->create($this->instanceName, $data); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Block/CustomEntity/View.php: -------------------------------------------------------------------------------- 1 | registry = $registry; 45 | $this->customEntity = $customEntity; 46 | $this->imageFactory = $imageFactory; 47 | } 48 | 49 | /** 50 | * Return current custom entity. 51 | */ 52 | public function getEntity(): ?CustomEntity 53 | { 54 | if (empty($this->customEntity->getId())) { 55 | $this->customEntity = $this->registry->registry('current_custom_entity'); 56 | } 57 | 58 | return $this->customEntity; 59 | } 60 | 61 | /** 62 | * Return custom entity image. 63 | */ 64 | public function getImage(): ?string 65 | { 66 | return $this->imageFactory->create($this->getEntity())->toHtml(); 67 | } 68 | 69 | /** 70 | * Return unique ID(s) for each object in system. 71 | * 72 | * @return string[]|null 73 | */ 74 | public function getIdentities(): ?array 75 | { 76 | return $this->getEntity()->getIdentities(); 77 | } 78 | 79 | /** 80 | * Prepare layout: add title and breadcrumbs. 81 | * 82 | * @return $this|Template 83 | * @throws LocalizedException 84 | * @throws NoSuchEntityException 85 | */ 86 | protected function _prepareLayout() 87 | { 88 | parent::_prepareLayout(); 89 | if ($this->getEntity()) { 90 | $this->setPageTitle() 91 | ->setBreadcrumbs(); 92 | } 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Set the current page title. 99 | * 100 | * @return $this 101 | * @throws LocalizedException 102 | */ 103 | private function setPageTitle(): self 104 | { 105 | $customEntity = $this->getEntity(); 106 | 107 | /** @var Title $titleBlock */ 108 | $titleBlock = $this->getLayout()->getBlock('page.main.title'); 109 | $pageTitle = $customEntity->getName(); 110 | $titleBlock->setPageTitle($pageTitle); 111 | $this->pageConfig->getTitle()->set((string) __($pageTitle)); 112 | 113 | return $this; 114 | } 115 | 116 | /** 117 | * Build breadcrumbs for the current page. 118 | * 119 | * @return $this 120 | * @throws LocalizedException 121 | * @throws NoSuchEntityException 122 | */ 123 | private function setBreadcrumbs(): self 124 | { 125 | /** @var Breadcrumbs $breadcrumbsBlock */ 126 | $breadcrumbsBlock = $this->getLayout()->getBlock('breadcrumbs'); 127 | 128 | /** @var CustomEntity $customEntity */ 129 | $customEntity = $this->getEntity(); 130 | 131 | /** @var \Magento\Store\Model\Store $store */ 132 | $store = $this->_storeManager->getStore(); 133 | $homeUrl = $store->getBaseUrl(); 134 | 135 | $breadcrumbsBlock->addCrumb( 136 | 'home', 137 | ['label' => __('Home'), 'title' => __('Go to Home Page'), 'link' => $homeUrl] 138 | ); 139 | $breadcrumbsBlock->addCrumb( 140 | 'set', 141 | [ 142 | 'label' => $customEntity->getAttributeSet()->getAttributeSetName(), 143 | 'title' => $customEntity->getAttributeSet()->getAttributeSetName(), 144 | 'link' => $this->_urlBuilder->getDirectUrl($customEntity->getAttributeSetUrlKey()), 145 | ] 146 | ); 147 | $breadcrumbsBlock->addCrumb( 148 | 'custom_entity', 149 | ['label' => $customEntity->getName(), 'title' => $customEntity->getName()] 150 | ); 151 | 152 | return $this; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Block/Html/Pager.php: -------------------------------------------------------------------------------- 1 | setCurrentPage($this->getCurrentPage()); 30 | if ((int) $this->getLimit()) { 31 | $searchCriteriaBuilder->setPageSize($this->getLimit()); 32 | } 33 | 34 | return $searchCriteriaBuilder; 35 | } 36 | 37 | /** 38 | * Set search result. 39 | * 40 | * @param SearchResultsInterface $searchResult Search result. 41 | * @return $this 42 | */ 43 | public function setSearchResult(SearchResultsInterface $searchResult): self 44 | { 45 | $this->searchResult = $searchResult; 46 | 47 | return $this; 48 | } 49 | 50 | /** 51 | * Return first page number. 52 | */ 53 | public function getFirstNum(): ?int 54 | { 55 | return $this->getLimit() * ($this->getCurrentPage() - 1) + 1; 56 | } 57 | 58 | /** 59 | * Return last page number. 60 | */ 61 | public function getLastNum(): ?int 62 | { 63 | return $this->getLimit() * ($this->getCurrentPage() - 1) + count($this->searchResult->getItems()); 64 | } 65 | 66 | /** 67 | * Retrieve total number of items. 68 | */ 69 | public function getTotalNum(): ?int 70 | { 71 | return$this->searchResult->getTotalCount(); 72 | } 73 | 74 | /** 75 | * Check if current page is a first page in collection 76 | */ 77 | public function isFirstPage(): bool 78 | { 79 | return $this->getCurrentPage() == 1; 80 | } 81 | 82 | /** 83 | * Retrieve number of last page 84 | */ 85 | public function getLastPageNum(): int 86 | { 87 | return (int) ceil($this->searchResult->getTotalCount() / $this->getLimit()); 88 | } 89 | 90 | /** 91 | * Check if current page is a last page in collection 92 | */ 93 | public function isLastPage(): bool 94 | { 95 | return $this->getCurrentPage() >= $this->getLastPageNum(); 96 | } 97 | 98 | /** 99 | * Return pages range. 100 | * 101 | * @return array|null 102 | */ 103 | public function getPages(): ?array 104 | { 105 | [$start, $finish] = $this->getPagesInterval(); 106 | 107 | return range($start, $finish); 108 | } 109 | 110 | /** 111 | * Return previous page url. 112 | */ 113 | public function getPreviousPageUrl(): string 114 | { 115 | $page = (string) ($this->getCurrentPage() - 1); 116 | return $this->getPageUrl($page); 117 | } 118 | 119 | /** 120 | * Return next page url. 121 | */ 122 | public function getNextPageUrl(): string 123 | { 124 | $page = (string) ($this->getCurrentPage() + 1); 125 | return $this->getPageUrl($page); 126 | } 127 | 128 | /** 129 | * Retrieve last page URL. 130 | */ 131 | public function getLastPageUrl(): string 132 | { 133 | $lastNumPage = (string) $this->getLastPageNum(); 134 | return $this->getPageUrl($lastNumPage); 135 | } 136 | 137 | /** 138 | * Initialize frame data, such as frame start, frame start etc. 139 | * 140 | * @return $this 141 | */ 142 | protected function _initFrame(): self 143 | { 144 | if (!$this->isFrameInitialized()) { 145 | [$start, $end] = $this->getPagesInterval(); 146 | $this->_frameStart = $start; 147 | $this->_frameEnd = $end; 148 | $this->_setFrameInitialized(true); 149 | } 150 | 151 | return $this; 152 | } 153 | 154 | /** 155 | * Return start and end pages number. 156 | * 157 | * @return array 158 | */ 159 | private function getPagesInterval(): array 160 | { 161 | if ($this->getLastPageNum() <= $this->_displayPages) { 162 | return [1, $this->getLastPageNum()]; 163 | } 164 | 165 | $half = ceil($this->_displayPages / 2); 166 | $start = 1; 167 | $finish = $this->_displayPages; 168 | if ( 169 | $this->getCurrentPage() >= $half && 170 | $this->getCurrentPage() <= $this->getLastPageNum() - $half 171 | ) { 172 | $start = $this->getCurrentPage() - $half + 1; 173 | $finish = $start + $this->_displayPages - 1; 174 | } elseif ($this->getCurrentPage() > $this->getLastPageNum() - $half) { 175 | $finish = $this->getLastPageNum(); 176 | $start = $finish - $this->_displayPages + 1; 177 | } 178 | 179 | return [$start, $finish]; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Block/Set/Entity/Renderer.php: -------------------------------------------------------------------------------- 1 | imageFactory = $imageFactory; 35 | } 36 | 37 | /** 38 | * Return custom entity image. 39 | */ 40 | public function getImage(): ?string 41 | { 42 | return $this->imageFactory->create($this->getEntity())->toHtml(); 43 | } 44 | 45 | /** 46 | * Return entity url. 47 | */ 48 | public function getEntityUrl(): ?string 49 | { 50 | return $this->_urlBuilder->getDirectUrl($this->getEntity()->getUrlPath()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Block/Set/View.php: -------------------------------------------------------------------------------- 1 | registry = $registry; 57 | $this->customEntityRepository = $customEntityRepository; 58 | $this->searchCriteriaBuilderFactory = $searchCriteriaBuilderFactory; 59 | } 60 | 61 | /** 62 | * Return custom entities. 63 | * 64 | * @return CustomEntityInterface[]|null 65 | */ 66 | public function getEntities(): ?array 67 | { 68 | if (!$this->entities) { 69 | /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ 70 | $searchCriteriaBuilder = $this->searchCriteriaBuilderFactory->create(); 71 | $searchCriteriaBuilder->addFilter( 72 | 'attribute_set_id', 73 | $this->getAttributeSet()->getAttributeSetId() 74 | ); 75 | $searchCriteriaBuilder->addFilter( 76 | 'is_active', 77 | true 78 | ); 79 | $this->getPager()->addCriteria($searchCriteriaBuilder); 80 | $searchResult = $this->customEntityRepository->getList($searchCriteriaBuilder->create()); 81 | $this->getPager()->setSearchResult($searchResult); 82 | 83 | $this->entities = $searchResult->getItems(); 84 | } 85 | 86 | return $this->entities; 87 | } 88 | 89 | /** 90 | * Return custom entity html. 91 | * 92 | * @param CustomEntityInterface $entity Custom entity. 93 | */ 94 | public function getEntityHtml(CustomEntityInterface $entity): ?string 95 | { 96 | return $this->getEntityRenderer($this->getAttributeSet()->getAttributeSetName())->setEntity($entity)->toHtml(); 97 | } 98 | 99 | /** 100 | * Return current attribute set. 101 | */ 102 | public function getAttributeSet(): ?AttributeSetInterface 103 | { 104 | return $this->registry->registry('current_attribute_set'); 105 | } 106 | 107 | /** 108 | * Return block identities. 109 | * 110 | * @return array|string[] 111 | */ 112 | public function getIdentities(): array 113 | { 114 | $identities = []; 115 | foreach ($this->getEntities() as $entity) { 116 | // @codingStandardsIgnoreLine 117 | $identities = array_merge($identities, $entity->getIdentities()); 118 | } 119 | $identities[] = CustomEntity::CACHE_CUSTOM_ENTITY_SET_TAG . '_' . $this->getAttributeSet()->getAttributeSetId(); 120 | 121 | return $identities; 122 | } 123 | 124 | /** 125 | * Return pager. 126 | */ 127 | public function getPager(): Pager 128 | { 129 | /** @var Pager $pager */ 130 | $pager = $this->getChildBlock('pager'); 131 | return $pager; 132 | } 133 | 134 | /** 135 | * Prepare layout: add title and breadcrumbs. 136 | * 137 | * @return $this|Template 138 | * @throws LocalizedException 139 | * @throws NoSuchEntityException 140 | */ 141 | protected function _prepareLayout() 142 | { 143 | parent::_prepareLayout(); 144 | if ($this->getAttributeSet()) { 145 | $this->setPageTitle() 146 | ->setBreadcrumbs(); 147 | } 148 | 149 | return $this; 150 | } 151 | 152 | /** 153 | * Set the current page title. 154 | * 155 | * @return $this 156 | * @throws LocalizedException 157 | */ 158 | private function setPageTitle() 159 | { 160 | $attributeSet = $this->getAttributeSet(); 161 | 162 | /** @var Title $titleBlock */ 163 | $titleBlock = $this->getLayout()->getBlock('page.main.title'); 164 | $pageTitle = $attributeSet->getAttributeSetName(); 165 | $titleBlock->setPageTitle($pageTitle); 166 | $this->pageConfig->getTitle()->set((string) __($pageTitle)); 167 | 168 | return $this; 169 | } 170 | 171 | /** 172 | * Build breadcrumbs for the current page. 173 | * 174 | * @return $this 175 | * @throws LocalizedException 176 | * @throws NoSuchEntityException 177 | */ 178 | private function setBreadcrumbs() 179 | { 180 | /** @var Breadcrumbs $breadcrumbsBlock */ 181 | $breadcrumbsBlock = $this->getLayout()->getBlock('breadcrumbs'); 182 | $attributeSet = $this->getAttributeSet(); 183 | 184 | /** @var \Magento\Store\Model\Store $store */ 185 | $store = $this->_storeManager->getStore(); 186 | $homeUrl = $store->getBaseUrl(); 187 | 188 | $breadcrumbsBlock->addCrumb( 189 | 'home', 190 | ['label' => __('Home'), 'title' => __('Go to Home Page'), 'link' => $homeUrl] 191 | ); 192 | $breadcrumbsBlock->addCrumb( 193 | 'attribute_set', 194 | ['label' => $attributeSet->getAttributeSetName(), 'title' => $attributeSet->getAttributeSetName()] 195 | ); 196 | 197 | return $this; 198 | } 199 | 200 | /** 201 | * Return custom entity renderer. 202 | * 203 | * @param string|null $attributeSetCode Attribute set code. 204 | * @return bool|\Magento\Framework\View\Element\AbstractBlock 205 | */ 206 | private function getEntityRenderer(?string $attributeSetCode = null) 207 | { 208 | if ($attributeSetCode === null) { 209 | $attributeSetCode = 'default'; 210 | } 211 | /** @var RendererList $rendererList */ 212 | $rendererList = $this->getChildBlock('renderer.list'); 213 | 214 | return $rendererList->getRenderer($attributeSetCode, 'default'); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Attribute/Builder.php: -------------------------------------------------------------------------------- 1 | attributeFactory = $attributeFactory; 43 | $this->attributeRepository = $attributeRepository; 44 | } 45 | 46 | /** 47 | * @inheritdoc 48 | */ 49 | protected function getAttributeFactory() 50 | { 51 | return $this->attributeFactory; 52 | } 53 | 54 | /** 55 | * @inheritdoc 56 | */ 57 | protected function getAttributeRepository() 58 | { 59 | return $this->attributeRepository; 60 | } 61 | 62 | /** 63 | * @inheritdoc 64 | */ 65 | protected function getEntityTypeCode(): string 66 | { 67 | return CustomEntityAttributeInterface::ENTITY_TYPE_CODE; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Attribute/Delete.php: -------------------------------------------------------------------------------- 1 | customEntityFactory = $customEntityFactory; 46 | $this->storeManager = $storeManager; 47 | $this->registry = $registry; 48 | $this->wysiwygConfig = $wysiwygConfig; 49 | } 50 | 51 | /** 52 | * Build 53 | * 54 | * @return CustomEntityInterface|EntityInterface 55 | * @throws NoSuchEntityException 56 | */ 57 | // @codingStandardsIgnoreLine Move class into Model folder (MEQP2.Classes.PublicNonInterfaceMethods.PublicMethodFound) 58 | public function build(RequestInterface $request): ?EntityInterface 59 | { 60 | $entityId = (int) $request->getParam('id'); 61 | $entity = $this->customEntityFactory->create(); 62 | $store = $this->storeManager->getStore((int) $request->getParam('store', 0)); 63 | $entity->setStoreId($store->getId()); 64 | 65 | /** @var DataObject $entity */ 66 | $entity->setData('_edit_mode', true); 67 | 68 | if ($entityId) { 69 | // @phpstan-ignore-next-line 70 | $entity->load($entityId); 71 | } 72 | 73 | $setId = (int) $request->getParam('set'); 74 | 75 | if ($setId) { 76 | $entity->setAttributeSetId($setId); 77 | } 78 | 79 | $entity->setPrevAttributeSetId((int) $request->getParam('prev_set_id', 0)); 80 | 81 | $this->registry->register('entity', $entity); 82 | $this->registry->register('current_entity', $entity); 83 | $this->registry->register('current_store', $store); 84 | $this->wysiwygConfig->setStoreId($request->getParam('store')); 85 | 86 | /** @var EntityInterface $entity */ 87 | return $entity; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Entity/Delete.php: -------------------------------------------------------------------------------- 1 | createActionPage(__('Custom Entities')); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Entity/MassDelete.php: -------------------------------------------------------------------------------- 1 | filter = $filter; 29 | $this->collectionFactory = $collectionFactory; 30 | parent::__construct($context); 31 | } 32 | 33 | /** 34 | * @inheritdoc 35 | */ 36 | public function execute() 37 | { 38 | $collection = $this->filter->getCollection($this->collectionFactory->create()); 39 | $collectionSize = $collection->getSize(); 40 | 41 | foreach ($collection as $entity) { 42 | $entity->delete(); 43 | } 44 | 45 | $this->messageManager->addSuccessMessage( 46 | __('A total of %1 record(s) have been deleted.', $collectionSize) 47 | ); 48 | 49 | /** @var Redirect $resultRedirect */ 50 | $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); 51 | 52 | return $resultRedirect->setPath('*/*/'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Entity/NewAction.php: -------------------------------------------------------------------------------- 1 | customEntityRepository = $customEntityRepository; 59 | $this->registry = $registry; 60 | $this->resultPageFactory = $resultPageFactory; 61 | $this->resultForwardFactory = $resultForwardFactory; 62 | $this->filterManager = $filterManager; 63 | $this->attributeSetRepository = $attributeSetRepository; 64 | $this->request = $request; 65 | } 66 | 67 | /** 68 | * Execute action based on request and return result 69 | * 70 | * Note: Request will be added as operation argument in future 71 | * 72 | * @return ResultInterface|ResponseInterface 73 | * @throws NoSuchEntityException 74 | */ 75 | public function execute() 76 | { 77 | $entity = $this->initEntity(); 78 | if (!$entity || !$entity->getIsActive()) { 79 | return $this->resultForwardFactory->create()->forward('noroute'); 80 | } 81 | 82 | $page = $this->resultPageFactory->create(); 83 | $page->addPageLayoutHandles(['type' => $this->getAttributeSetCode($entity)], null, false); 84 | $page->addPageLayoutHandles(['id' => $entity->getId()]); 85 | 86 | return $page; 87 | } 88 | 89 | /** 90 | * Return custom entity and append it into register. 91 | * 92 | * @return bool|CustomEntityInterface 93 | */ 94 | private function initEntity() 95 | { 96 | $entityId = (int) $this->request->getParam('entity_id', false); 97 | if (!$entityId) { 98 | return false; 99 | } 100 | 101 | try { 102 | $customEntity = $this->customEntityRepository->get($entityId); 103 | $this->registry->register('current_custom_entity', $customEntity); 104 | } catch (NoSuchEntityException $e) { 105 | return false; 106 | } 107 | 108 | return $customEntity; 109 | } 110 | 111 | /** 112 | * Return attribute set code. 113 | * 114 | * @param CustomEntityInterface $entity Custom entity. 115 | */ 116 | private function getAttributeSetCode(CustomEntityInterface $entity): string 117 | { 118 | $attributeSet = $this->attributeSetRepository->get($entity->getAttributeSetId()); 119 | return $this->filterManager->translitUrl($attributeSet->getAttributeSetName()); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Controller/Router.php: -------------------------------------------------------------------------------- 1 | urlSetModel = $urlSetModel; 44 | $this->actionFactory = $actionFactory; 45 | $this->customEntity = $customEntity; 46 | } 47 | 48 | /** 49 | * Match application action by request 50 | * 51 | * @param RequestInterface|HttpRequest $request Request. 52 | * @return ActionInterface|null 53 | */ 54 | // @codingStandardsIgnoreLine Match function is allow in router (MEQP2.Classes.PublicNonInterfaceMethods.PublicMethodFound) 55 | public function match(RequestInterface $request) 56 | { 57 | /** @var HttpRequest $request */ 58 | $requestPath = trim($request->getPathInfo(), '/'); 59 | $requestPathArray = explode('/', $requestPath); 60 | if ( 61 | !$this->isValidPath($requestPathArray) 62 | || $request->getAlias(UrlInterface::REWRITE_REQUEST_PATH_ALIAS) 63 | ) { 64 | // Continuing with processing of this URL. 65 | return null; 66 | } 67 | 68 | try { 69 | $entityId = $this->matchCustomEntity($requestPathArray); 70 | $request->setAlias(UrlInterface::REWRITE_REQUEST_PATH_ALIAS, $requestPath) 71 | ->setModuleName('custom_entity') 72 | ->setControllerName($this->getControllerName($requestPathArray)) 73 | ->setActionName('view') 74 | ->setParam('entity_id', $entityId); 75 | } catch (Exception $e) { 76 | // Continuing with processing of this URL. 77 | return null; 78 | } 79 | 80 | return $this->actionFactory->create( 81 | Forward::class 82 | ); 83 | } 84 | 85 | /** 86 | * Match custom entity. 87 | * 88 | * @param array $requestPathArray Request path array 89 | * @return mixed 90 | * @throws NoSuchEntityException 91 | * @throws NotFoundException 92 | */ 93 | private function matchCustomEntity(array $requestPathArray) 94 | { 95 | $entityId = $customEntitySetId = $this->urlSetModel->checkIdentifier(array_shift($requestPathArray)); 96 | if (!empty($requestPathArray) && $customEntitySetId) { 97 | $entityId = $this->customEntity->checkIdentifier(current($requestPathArray), $entityId); 98 | } 99 | 100 | return $entityId; 101 | } 102 | 103 | /** 104 | * Return controller name. 105 | * 106 | * @param array $requestPathArray Request path array. 107 | */ 108 | private function getControllerName(array $requestPathArray): string 109 | { 110 | return $this->isCustomEntitySet($requestPathArray) ? 'set' : 'entity'; 111 | } 112 | 113 | /** 114 | * Return true if we want to see a set of custom entity. 115 | * 116 | * @param array $requestPathArray Request path array. 117 | */ 118 | private function isCustomEntitySet(array $requestPathArray): bool 119 | { 120 | return count($requestPathArray) == 1; 121 | } 122 | 123 | /** 124 | * Return true if current request is allow into this router. 125 | * 126 | * @param array $requestPathArray Request path array. 127 | */ 128 | private function isValidPath(array $requestPathArray): bool 129 | { 130 | return count($requestPathArray) > 0 && count($requestPathArray) <= 2; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Controller/Set/View.php: -------------------------------------------------------------------------------- 1 | attributeSetRepository = $attributeSetRepository; 54 | $this->registry = $registry; 55 | $this->resultPageFactory = $resultPageFactory; 56 | $this->resultForwardFactory = $resultForwardFactory; 57 | $this->filterManager = $filterManager; 58 | $this->request = $request; 59 | } 60 | 61 | /** 62 | * Execute action based on request and return result 63 | * 64 | * Note: Request will be added as operation argument in future 65 | * 66 | * @return ResultInterface|ResponseInterface 67 | */ 68 | public function execute() 69 | { 70 | $attributeSet = $this->initSet(); 71 | if (!$attributeSet) { 72 | return $this->resultForwardFactory->create()->forward('noroute'); 73 | } 74 | 75 | $page = $this->resultPageFactory->create(); 76 | $page->addPageLayoutHandles(['type' => $this->getAttributeSetCode($attributeSet)], null, false); 77 | $page->addPageLayoutHandles(['id' => $attributeSet->getAttributeSetId()]); 78 | 79 | return $page; 80 | } 81 | 82 | /** 83 | * Return attribute set and append it into register. 84 | * 85 | * @return bool|AttributeSetInterface 86 | */ 87 | private function initSet() 88 | { 89 | $attributeSetId = (int) $this->request->getParam('entity_id', false); 90 | if (!$attributeSetId) { 91 | return false; 92 | } 93 | 94 | try { 95 | $attributeSet = $this->attributeSetRepository->get($attributeSetId); 96 | $this->registry->register('current_attribute_set', $attributeSet); 97 | } catch (NoSuchEntityException $e) { 98 | return false; 99 | } 100 | 101 | return $attributeSet; 102 | } 103 | 104 | /** 105 | * Return attribute set code. 106 | * 107 | * @param AttributeSetInterface $attributeSet Current attribute set. 108 | */ 109 | private function getAttributeSetCode(AttributeSetInterface $attributeSet): string 110 | { 111 | return $this->filterManager->translitUrl($attributeSet->getAttributeSetName()); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Model/CustomEntity/Attribute.php: -------------------------------------------------------------------------------- 1 | eavConfig = $eavConfig; 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | public function toOptionArray() 31 | { 32 | $entityType = $this->eavConfig->getEntityType(CustomEntityInterface::ENTITY); 33 | $attributeSetCollection = $entityType->getAttributeSetCollection(); 34 | return $attributeSetCollection->toOptionArray(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Model/CustomEntity/AttributeSet/Url.php: -------------------------------------------------------------------------------- 1 | urlResourceModel = $urlResourceModel; 26 | } 27 | 28 | /** 29 | * Return attribute set id from url key. 30 | * 31 | * @param string $urlKey Attribute set url key. 32 | * @throws NotFoundException 33 | */ 34 | public function checkIdentifier(string $urlKey): ?int 35 | { 36 | return $this->urlResourceModel->checkIdentifier($urlKey); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Model/CustomEntityAttributeRepository.php: -------------------------------------------------------------------------------- 1 | eavAttributeRepository = $eavAttributeRepository; 33 | } 34 | 35 | /** 36 | * Retrieve specific attribute. 37 | * 38 | * @param string $attributeCode Attribute code. 39 | * @throws NoSuchEntityException 40 | */ 41 | public function get(string $attributeCode): ?CustomEntityAttributeInterface 42 | { 43 | /** @var CustomEntityAttributeInterface $customEntityAttribute */ 44 | $customEntityAttribute = $this->eavAttributeRepository->get($this->getEntityTypeCode(), $attributeCode); 45 | return $customEntityAttribute; 46 | } 47 | 48 | /** 49 | * Delete Attribute. 50 | * 51 | * @param CustomEntityAttributeInterface $attribute Attribute. 52 | * @return bool True if the entity was deleted (always true) 53 | * @throws StateException 54 | * @throws NoSuchEntityException 55 | */ 56 | public function delete(CustomEntityAttributeInterface $attribute): bool 57 | { 58 | return $this->eavAttributeRepository->delete($attribute); 59 | } 60 | 61 | /** 62 | * Delete Attribute by id 63 | * 64 | * @param string $attributeCode Attribute code. 65 | * @throws StateException 66 | * @throws NoSuchEntityException 67 | */ 68 | public function deleteById(string $attributeCode): bool 69 | { 70 | if (!is_numeric($attributeCode)) { 71 | $attributeCode = $this->eavAttributeRepository->get( 72 | $this->getEntityTypeCode(), 73 | $attributeCode 74 | )->getAttributeId(); 75 | } 76 | 77 | return $this->eavAttributeRepository->deleteById($attributeCode); 78 | } 79 | 80 | /** 81 | * Save attribute data. 82 | * 83 | * @param CustomEntityAttributeInterface $attribute Attribute. 84 | * @throws NoSuchEntityException 85 | * @throws InputExceptionAlias 86 | * @throws StateException 87 | */ 88 | public function save(CustomEntityAttributeInterface $attribute): ?CustomEntityAttributeInterface 89 | { 90 | /** @var CustomEntityAttributeInterface $customEntityAttribute */ 91 | $customEntityAttribute = $this->eavAttributeRepository->save($attribute); 92 | return $customEntityAttribute; 93 | } 94 | 95 | /** 96 | * Retrieve all attributes for entity type. 97 | * 98 | * @param SearchCriteriaInterface $searchCriteria Search criteria. 99 | */ 100 | public function getList(SearchCriteriaInterface $searchCriteria): ?CustomEntityAttributeSearchResultsInterface 101 | { 102 | // TODO: Implement getList() method. 103 | throw new BadMethodCallException('Not implemented'); 104 | } 105 | 106 | /** 107 | * @inheritdoc 108 | */ 109 | public function getCustomAttributesMetadata($dataObjectClassName = null) 110 | { 111 | // TODO: Implement getCustomAttributesMetadata() method. 112 | throw new BadMethodCallException('Not implemented'); 113 | } 114 | 115 | /** 116 | * Get the custom entity type code. 117 | */ 118 | private function getEntityTypeCode(): string 119 | { 120 | return CustomEntityAttributeInterface::ENTITY_TYPE_CODE; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Model/CustomEntityRepository.php: -------------------------------------------------------------------------------- 1 | customEntityFactory = $customEntityFactory; 84 | $this->customEntityResource = $customEntityResource; 85 | $this->storeManager = $storeManager; 86 | $this->metadataPool = $metadataPool; 87 | $this->extensibleDataObjectConverter = $extensibleDataObjectConverter; 88 | $this->customEntityCollectionFactory = $customEntityCollectionFactory; 89 | $this->collectionProcessor = $collectionProcessor; 90 | $this->joinProcessor = $joinProcessor; 91 | $this->customEntitySearchResultsFactory = $customEntitySearchResultsFactory; 92 | } 93 | 94 | /** 95 | * Save a custom entity. 96 | * 97 | * @param CustomEntityInterface|null $entity Saved entity. 98 | * @throws InputException 99 | * @throws StateException 100 | * @throws CouldNotSaveException 101 | */ 102 | public function save(?CustomEntityInterface $entity): ?CustomEntityInterface 103 | { 104 | $existingData = $this->extensibleDataObjectConverter->toNestedArray($entity, [], CustomEntityInterface::class); 105 | 106 | if (!isset($existingData['store_id'])) { 107 | $existingData['store_id'] = (int) $this->storeManager->getStore()->getId(); 108 | } 109 | 110 | $storeId = $existingData['store_id']; 111 | 112 | if ($entity->getId()) { 113 | $metadata = $this->metadataPool->getMetadata(CustomEntityInterface::class); 114 | 115 | /** @var DataObject $entity */ 116 | $entity = $this->get($entity->getId(), $storeId); 117 | $existingData[$metadata->getLinkField()] = $entity->getData($metadata->getLinkField()); 118 | } 119 | $entity->addData($existingData); 120 | 121 | try { 122 | /** @var AbstractModel $entity */ 123 | $this->customEntityResource->save($entity); 124 | } catch (CouldNotSaveException $e) { 125 | throw new CouldNotSaveException(__('Could not save entity: %1', $e->getMessage()), $e); 126 | } 127 | unset($this->instances[$entity->getId()]); 128 | 129 | return $this->get($entity->getId(), $storeId); 130 | } 131 | 132 | /** 133 | * Get custom entity by id. 134 | * 135 | * @param int|string $entityId Entity Id. 136 | * @param int|null $storeId Store Id. 137 | * @param bool $forceReload Force reload the entity.. 138 | * @throws NoSuchEntityException 139 | * @SuppressWarnings(PHPMD.BooleanArgumentFlag) 140 | * @SuppressWarnings(PHPMD.StaticAccess) 141 | */ 142 | public function get($entityId, ?int $storeId = null, bool $forceReload = false): ?CustomEntityInterface 143 | { 144 | $cacheKey = $storeId ?? 'all'; 145 | 146 | if (!isset($this->instances[$entityId][$cacheKey]) || $forceReload === true) { 147 | $entity = $this->customEntityFactory->create(); 148 | if (null !== $storeId) { 149 | $entity->setStoreId($storeId); 150 | } 151 | $entity->load($entityId); 152 | if (!$entity->getId()) { 153 | throw NoSuchEntityException::singleField('id', $entityId); 154 | } 155 | $this->instances[$entityId][$cacheKey] = $entity; 156 | } 157 | 158 | return $this->instances[$entityId][$cacheKey]; 159 | } 160 | 161 | /** 162 | * Delete custom entity. 163 | * 164 | * @param CustomEntityInterface|DataObject $entity Deleted entity. 165 | * @return bool Will returned True if deleted 166 | * @throws StateException 167 | */ 168 | public function delete($entity): bool 169 | { 170 | try { 171 | $this->customEntityResource->delete($entity); 172 | } catch (Exception $e) { 173 | throw new StateException(__('Cannot delete entity with id %1', $entity->getId()), $e); 174 | } 175 | 176 | unset($this->instances[$entity->getId()]); 177 | 178 | return true; 179 | } 180 | 181 | /** 182 | * Delete custom entity by id. 183 | * 184 | * @param int $entityId Deleted entity id. 185 | * @return bool Will returned True if deleted 186 | * @throws NoSuchEntityException 187 | * @throws StateException 188 | */ 189 | public function deleteById(int $entityId): bool 190 | { 191 | $entity = $this->get($entityId); 192 | 193 | return $this->delete($entity); 194 | } 195 | 196 | /** 197 | * Get custom entity list. 198 | * 199 | * @param SearchCriteriaInterface $searchCriteria Search criteria. 200 | * @return CustomEntitySearchResultsInterface|SearchResults 201 | */ 202 | public function getList(SearchCriteriaInterface $searchCriteria) 203 | { 204 | /** @var \Smile\CustomEntity\Model\ResourceModel\CustomEntity\Collection $collection */ 205 | $collection = $this->customEntityCollectionFactory->create(); 206 | $this->joinProcessor->process($collection); 207 | $collection->addAttributeToSelect('*'); 208 | $this->collectionProcessor->process($searchCriteria, $collection); 209 | 210 | /** @var CustomEntitySearchResultsInterface $searchResults */ 211 | $searchResults = $this->customEntitySearchResultsFactory->create(); 212 | $searchResults->setSearchCriteria($searchCriteria); 213 | /** @var CustomEntityInterfaceData[] $collectionItems */ 214 | $collectionItems = $collection->getItems(); 215 | $searchResults->setItems($collectionItems); 216 | $searchResults->setTotalCount($collection->getSize()); 217 | 218 | return $searchResults; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /Model/ResourceModel/CustomEntity.php: -------------------------------------------------------------------------------- 1 | storeManager = $storeManager; 54 | $this->customEntityWebsiteTable = CustomEntityInterface::ENTITY; 55 | $this->mediaImageDeleteProcessor = $mediaImageDeleteProcessor; 56 | } 57 | 58 | /** 59 | * @inheritdoc 60 | */ 61 | public function getEntityType() 62 | { 63 | $this->setType(CustomEntityInterface::ENTITY); 64 | return parent::getEntityType(); 65 | } 66 | 67 | /** 68 | * Custom entity website table name getter. 69 | */ 70 | public function getCustomEntityWebsiteTable(): ?string 71 | { 72 | if (!empty($this->customEntityWebsiteTable)) { 73 | $this->customEntityWebsiteTable = $this->getTable('smile_custom_entity_website'); 74 | } 75 | 76 | return $this->customEntityWebsiteTable; 77 | } 78 | 79 | /** 80 | * Retrieve custom entity website identifiers 81 | * 82 | * @param CustomEntityModel|int $entity Custom entity. 83 | * @return array|null 84 | */ 85 | public function getWebsiteIds($entity): ?array 86 | { 87 | $connection = $this->getConnection(); 88 | 89 | $entityId = $entity; 90 | 91 | if ($entity instanceof CustomEntityModel) { 92 | $entityId = $entity->getEntityId(); 93 | } 94 | 95 | $select = $connection->select()->from( 96 | $this->getCustomEntityWebsiteTable(), 97 | 'website_id' 98 | )->where( 99 | 'entity_id = ?', 100 | (int) $entityId 101 | ); 102 | 103 | return $connection->fetchCol($select); 104 | } 105 | 106 | /** 107 | * @inheritdoc 108 | */ 109 | protected function _afterSave(DataObject $entity) 110 | { 111 | /** @var CustomEntity $this */ 112 | /** @var CustomEntityModel $entity */ 113 | $this->saveWebsiteIds($entity); 114 | return parent::_afterSave($entity); 115 | } 116 | 117 | /** 118 | * Save entity website relations 119 | * 120 | * @param CustomEntityModel $entity Entity. 121 | * @return $this 122 | */ 123 | protected function saveWebsiteIds(CustomEntityModel $entity): self 124 | { 125 | if ($this->storeManager->isSingleStoreMode()) { 126 | $websiteId = $this->storeManager->getDefaultStoreView()->getWebsiteId(); 127 | $entity->setWebsiteIds([$websiteId]); 128 | } 129 | $websiteIds = $entity->getWebsiteIds(); 130 | 131 | $entity->setIsChangedWebsites(false); 132 | 133 | $connection = $this->getConnection(); 134 | 135 | $oldWebsiteIds = $this->getWebsiteIds($entity); 136 | 137 | $insert = array_diff($websiteIds, $oldWebsiteIds); 138 | $delete = array_diff($oldWebsiteIds, $websiteIds); 139 | 140 | if (!empty($insert)) { 141 | $data = []; 142 | foreach ($insert as $websiteId) { 143 | $data[] = ['entity_id' => (int) $entity->getEntityId(), 'website_id' => (int) $websiteId]; 144 | } 145 | $connection->insertMultiple($this->getCustomEntityWebsiteTable(), $data); 146 | } 147 | 148 | if (!empty($delete)) { 149 | $websiteIdsForDelete = []; 150 | foreach ($delete as $websiteId) { 151 | $websiteIdsForDelete[] = (int) $websiteId; 152 | } 153 | $condition = ['entity_id = ?' => (int) $entity->getEntityId(), 'website_id in (?)' => $websiteIdsForDelete]; 154 | $connection->delete($this->getCustomEntityWebsiteTable(), $condition); 155 | } 156 | 157 | if (!empty($insert) || !empty($delete)) { 158 | $entity->setIsChangedWebsites(true); 159 | } 160 | 161 | return $this; 162 | } 163 | 164 | /** 165 | * @inheritdoc 166 | */ 167 | protected function _afterDelete(DataObject $object) 168 | { 169 | $this->mediaImageDeleteProcessor->execute($object); 170 | 171 | return parent::_afterDelete($object); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Model/ResourceModel/CustomEntity/Attribute/Collection.php: -------------------------------------------------------------------------------- 1 | _init(CustomEntityAttribute::class, Attribute::class); 43 | } 44 | 45 | /** 46 | * @inheritdoc 47 | * @SuppressWarnings(PHPMD.CamelCaseMethodName) 48 | */ 49 | protected function _initSelect(): self 50 | { 51 | $entityTypeId = $this->eavConfig->getEntityType( 52 | CustomEntityAttribute::ENTITY_TYPE_CODE 53 | )->getEntityTypeId(); 54 | 55 | $columns = $this->getConnection()->describeTable($this->getResource()->getMainTable()); 56 | 57 | $retColumns = []; 58 | 59 | foreach ($columns as $labelColumn => $columnData) { 60 | $retColumns[$labelColumn] = $labelColumn; 61 | if ($columnData['DATA_TYPE'] == Table::TYPE_TEXT) { 62 | $retColumns[$labelColumn] = 'main_table.' . $labelColumn; 63 | } 64 | } 65 | $this->getSelect()->from( 66 | ['main_table' => $this->getResource()->getMainTable()], 67 | $retColumns 68 | )->join( 69 | ['additional_table' => $this->getTable('smile_custom_entity_eav_attribute')], 70 | 'additional_table.attribute_id = main_table.attribute_id' 71 | )->where( 72 | 'main_table.entity_type_id = ?', 73 | $entityTypeId 74 | ); 75 | 76 | return $this; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Model/ResourceModel/CustomEntity/Attribute/Grid/Collection.php: -------------------------------------------------------------------------------- 1 | _init( 30 | Document::class, 31 | Attribute::class 32 | ); 33 | } 34 | 35 | /** 36 | * @inheritDoc 37 | */ 38 | public function getAggregations(): AggregationInterface 39 | { 40 | return $this->aggregations; 41 | } 42 | 43 | /** 44 | * @inheritDoc 45 | */ 46 | public function getTotalCount() 47 | { 48 | return $this->getSize(); 49 | } 50 | 51 | /** 52 | * @inheritDoc 53 | */ 54 | public function setSearchCriteria(SearchCriteriaInterface $searchCriteria) 55 | { 56 | return $this; 57 | } 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public function setAggregations($aggregations): self 63 | { 64 | $this->aggregations = $aggregations; 65 | return $this; 66 | } 67 | 68 | /** 69 | * @inheritDoc 70 | */ 71 | public function setTotalCount($totalCount): self 72 | { 73 | return $this; 74 | } 75 | 76 | /** 77 | * @inheritDoc 78 | */ 79 | public function setItems(?array $items = null): self 80 | { 81 | return $this; 82 | } 83 | 84 | /** 85 | * @inheritDoc 86 | */ 87 | public function getSearchCriteria(): ?SearchCriteriaInterface 88 | { 89 | return null; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Model/ResourceModel/CustomEntity/AttributeSet/Url.php: -------------------------------------------------------------------------------- 1 | filterManager = $filterManager; 33 | } 34 | 35 | /** 36 | * Find attribute set id from url key. 37 | * 38 | * @param string $urlKey Url key 39 | * @throws NotFoundException 40 | */ 41 | public function checkIdentifier(string $urlKey): ?int 42 | { 43 | $urlKeyArray = explode('-', $urlKey); 44 | $select = $this->getConnection()->select(); 45 | $select 46 | ->from($this->getTable('eav_attribute_set'), ['attribute_set_id', 'attribute_set_name']) 47 | // @codingStandardsIgnoreLine use like (MEQP1.SQL.SlowQuery.FoundSlowRawSql) 48 | ->where('attribute_set_name like ?', '%'.current($urlKeyArray).'%'); 49 | $result = $this->getConnection()->fetchPairs($select); 50 | foreach ($result as $attributeSetId => $attributeSetName) { 51 | if ($this->filterManager->translitUrl($attributeSetName) == $urlKey) { 52 | return (int) $attributeSetId; 53 | } 54 | continue; 55 | } 56 | 57 | throw new NotFoundException(__('Not found attribute set')); 58 | } 59 | 60 | /** 61 | * Implementation of abstract construct 62 | */ 63 | // @codingStandardsIgnoreLine use like (MEQP1.CodeAnalysis.EmptyBlock.DetectedFunction) 64 | protected function _construct(): void 65 | { 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Model/ResourceModel/CustomEntity/Collection.php: -------------------------------------------------------------------------------- 1 | addAttributeToFilter('is_active', '1'); 32 | $this->_eventManager->dispatch($this->_eventPrefix . '_add_is_active_filter', [$this->_eventObject => $this]); 33 | 34 | return $this; 35 | } 36 | 37 | /** 38 | * Init collection and determine table names 39 | */ 40 | protected function _construct(): void 41 | { 42 | $this->_init(CustomEntity::class, CustomEntityResource::class); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Model/ResourceModel/CustomEntity/MediaImageDeleteProcessor.php: -------------------------------------------------------------------------------- 1 | resourceConnection = $resourceConnection; 32 | $this->logger = $logger; 33 | $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); 34 | } 35 | 36 | /** 37 | * Remove image attribute files. 38 | */ 39 | public function execute(DataObject $object): void 40 | { 41 | foreach ($this->getMediaAttributes() as $attributeCode) { 42 | $mediaFileName = $object->getData($attributeCode); 43 | 44 | if (!$mediaFileName) { 45 | continue; 46 | } 47 | 48 | $mediaFileName = ltrim($mediaFileName, '/media'); 49 | $filePath = $this->mediaDirectory->getAbsolutePath($mediaFileName); 50 | 51 | if (!$this->mediaDirectory->isFile($filePath)) { 52 | continue; 53 | } 54 | 55 | try { 56 | $this->deletePhysicalImage($filePath); 57 | } catch (Exception $e) { 58 | $this->logger->critical($e->getMessage()); 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * Delete the physical image. 65 | */ 66 | protected function deletePhysicalImage(string $filePath): void 67 | { 68 | $this->mediaDirectory->delete($filePath); 69 | } 70 | 71 | /** 72 | * Returns the media attribute codes of the "custom entity". 73 | */ 74 | protected function getMediaAttributes(): array 75 | { 76 | if (empty($this->mediaAttributes)) { 77 | $this->mediaAttributes = $this->loadMediaAttributes(); 78 | } 79 | 80 | return $this->mediaAttributes; 81 | } 82 | 83 | /** 84 | * Load media attribute codes. 85 | */ 86 | protected function loadMediaAttributes(): array 87 | { 88 | $connection = $this->resourceConnection->getConnection(); 89 | 90 | $select = $connection->select()->from( 91 | ['ea' => $connection->getTableName('eav_attribute')], 92 | ['attribute_code'] 93 | )->joinLeft( 94 | ['eet' => $connection->getTableName('eav_entity_type')], 95 | 'ea.entity_type_id = eet.entity_type_id' 96 | )->where( 97 | 'eet.entity_type_code = ?', 98 | CustomEntityInterface::ENTITY 99 | )->where( 100 | 'frontend_input IN (?)', 101 | $this->mediaAttributesFrontendType 102 | ); 103 | 104 | return $connection->fetchCol($select); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Model/Sitemap/ConfigReader.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 31 | } 32 | 33 | /** 34 | * Get is custom entity include into sitemap. 35 | */ 36 | public function isIncludeInSitemap(int $storeId): bool 37 | { 38 | return (bool) $this->scopeConfig->getValue( 39 | self::XML_PATH_INCLUDE_IN_SITEMAP, 40 | ScopeInterface::SCOPE_STORE, 41 | $storeId 42 | ); 43 | } 44 | 45 | /** 46 | * Get is image include into sitemap. 47 | */ 48 | public function isImageInclude(int $storeId): bool 49 | { 50 | return (bool) $this->scopeConfig->getValue( 51 | self::XML_PATH_INCLUDE_IMAGE_IN_SITEMAP, 52 | ScopeInterface::SCOPE_STORE, 53 | $storeId 54 | ); 55 | } 56 | 57 | /** 58 | * Get entity types to include into sitemap. 59 | */ 60 | public function getEntityTypes(int $storeId): array 61 | { 62 | $types = (string) $this->scopeConfig->getValue( 63 | self::XML_PATH_ENTITY_TYPES, 64 | ScopeInterface::SCOPE_STORE, 65 | $storeId 66 | ); 67 | 68 | return $types ? explode(',', $types) : []; 69 | } 70 | 71 | /** 72 | * Get change frequency. 73 | */ 74 | public function getChangeFrequency(int $storeId): string 75 | { 76 | return (string) $this->scopeConfig->getValue( 77 | self::XML_PATH_CHANGE_FREQUENCY, 78 | ScopeInterface::SCOPE_STORE, 79 | $storeId 80 | ); 81 | } 82 | 83 | /** 84 | * Get priority. 85 | */ 86 | public function getPriority(int $storeId): string 87 | { 88 | return (string) $this->scopeConfig->getValue( 89 | self::XML_PATH_PRIORITY, 90 | ScopeInterface::SCOPE_STORE, 91 | $storeId 92 | ); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Model/Sitemap/CustomEntityProvider.php: -------------------------------------------------------------------------------- 1 | itemFactory = $itemFactory; 40 | $this->configReader = $configReader; 41 | $this->customEntityRepository = $customEntityRepository; 42 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 43 | $this->urlBuilder = $urlBuilder; 44 | } 45 | 46 | /** 47 | * @inheritdoc 48 | */ 49 | public function getItems($storeId) 50 | { 51 | if (!$this->configReader->isIncludeInSitemap((int) $storeId)) { 52 | return []; 53 | } 54 | 55 | $entityTypes = $this->configReader->getEntityTypes((int) $storeId); 56 | 57 | $search = $this->searchCriteriaBuilder->addFilter(EntityInterface::IS_ACTIVE, '1') 58 | ->addFilter(EntityInterface::ATTRIBUTE_SET_ID, $entityTypes, 'in') 59 | ->create(); 60 | 61 | $collection = $this->customEntityRepository->getList($search); 62 | $isImageInclude = $this->configReader->isImageInclude((int) $storeId); 63 | $priority = $this->configReader->getPriority((int) $storeId); 64 | $changeFrequency = $this->configReader->getChangeFrequency((int) $storeId); 65 | 66 | $items = array_map(function ($item) use ($isImageInclude, $priority, $changeFrequency) { 67 | return $this->itemFactory->create([ 68 | 'url' => $item->getUrlPath(), 69 | 'updatedAt' => $item->getUpdatedAt(), 70 | 'images' => $isImageInclude ? $this->getImages($item) : null, 71 | 'priority' => $priority, 72 | 'changeFrequency' => $changeFrequency, 73 | ]); 74 | }, $collection->getItems()); 75 | 76 | return $items; 77 | } 78 | 79 | /** 80 | * Get images object for sitemap. 81 | */ 82 | protected function getImages(CustomEntityInterface $entity): ?DataObject 83 | { 84 | /** @var AbstractEntity $entity */ 85 | $image = $entity->getImageUrl(EntityInterface::IMAGE); 86 | 87 | if (!$image) { 88 | return null; 89 | } 90 | 91 | $imageUrl = $this->urlBuilder->getDirectUrl(ltrim($image, "/")); 92 | $imageCollection = [new DataObject(['url' => $imageUrl])]; 93 | 94 | return new DataObject([ 95 | 'collection' => $imageCollection, 96 | 'title' => $entity->getName(), 97 | 'thumbnail' => $imageUrl, 98 | ]); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Model/Source/Attribute/CustomEntity.php: -------------------------------------------------------------------------------- 1 | customEntityRepository = $customEntityRepository; 24 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | public function getAllOptions(): array 31 | { 32 | $customEntityTypeId = $this->getAttribute()->getData('custom_entity_attribute_set_id'); 33 | if (!$customEntityTypeId) { 34 | return []; 35 | } 36 | 37 | if ($this->_options === null) { 38 | $this->_options = []; 39 | $searchCriteria = $this->searchCriteriaBuilder->addFilter( 40 | 'attribute_set_id', 41 | $customEntityTypeId 42 | )->create(); 43 | $entities = $this->customEntityRepository->getList($searchCriteria); 44 | foreach ($entities->getItems() as $entity) { 45 | $this->_options[] = ['label' => $entity->getName(), 'value' => $entity->getId()]; 46 | } 47 | } 48 | 49 | return $this->_options; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Setup/CustomEntitySetup.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'entity_model' => CustomEntityModel::class, 30 | 'attribute_model' => Attribute::class, 31 | 'table' => 'smile_custom_entity', 32 | 'attributes' => $this->getDefaultAttributes(), 33 | 'additional_attribute_table' => 'smile_custom_entity_eav_attribute', 34 | 'entity_attribute_collection' => Collection::class, 35 | ], 36 | ]; 37 | } 38 | 39 | /** 40 | * List of default attributes. 41 | */ 42 | private function getDefaultAttributes(): array 43 | { 44 | return [ 45 | 'name' => [ 46 | 'type' => 'varchar', 47 | 'label' => 'Name', 48 | 'input' => 'text', 49 | 'sort_order' => 1, 50 | 'global' => ScopedAttributeInterface::SCOPE_STORE, 51 | 'group' => 'General', 52 | ], 53 | 'is_active' => [ 54 | 'type' => 'int', 55 | 'label' => 'Is Active', 56 | 'input' => 'select', 57 | 'source' => Boolean::class, 58 | 'sort_order' => 2, 59 | 'global' => ScopedAttributeInterface::SCOPE_STORE, 60 | 'group' => 'General', 61 | ], 62 | 'url_key' => [ 63 | 'type' => 'varchar', 64 | 'label' => 'URL Key', 65 | 'input' => 'text', 66 | 'required' => false, 67 | 'sort_order' => 3, 68 | 'global' => ScopedAttributeInterface::SCOPE_STORE, 69 | 'group' => 'General', 70 | ], 71 | 'description' => [ 72 | 'type' => 'text', 73 | 'label' => 'Description', 74 | 'input' => 'textarea', 75 | 'required' => false, 76 | 'sort_order' => 4, 77 | 'global' => ScopedAttributeInterface::SCOPE_STORE, 78 | 'wysiwyg_enabled' => true, 79 | 'is_html_allowed_on_front' => true, 80 | 'group' => 'General', 81 | ], 82 | 'image' => [ 83 | 'type' => 'varchar', 84 | 'label' => 'Image', 85 | 'input' => 'image', 86 | 'backend' => Image::class, 87 | 'required' => false, 88 | 'sort_order' => 5, 89 | 'global' => ScopedAttributeInterface::SCOPE_STORE, 90 | 'group' => 'General', 91 | ], 92 | ]; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Setup/Patch/Data/CustomEntityAttributeSetIdMigration.php: -------------------------------------------------------------------------------- 1 | resourceConnection = $resourceConnection; 32 | } 33 | 34 | /** 35 | * @inheritdoc 36 | */ 37 | public function apply() 38 | { 39 | $connection = $this->resourceConnection->getConnection(); 40 | 41 | $catalogEavTable = $connection->getTableName('catalog_eav_attribute'); 42 | $eavTable = $connection->getTableName('eav_attribute'); 43 | 44 | if ( 45 | $connection->tableColumnExists($catalogEavTable, self::ATTRIBUTE_SET_ID_COLUMN) && 46 | $connection->tableColumnExists($eavTable, self::ATTRIBUTE_SET_ID_COLUMN) 47 | ) { 48 | $select = $connection->select() 49 | ->from(['cea' => 'catalog_eav_attribute'], [self::ATTRIBUTE_SET_ID_COLUMN]) 50 | ->where('ea.attribute_id = cea.attribute_id'); 51 | 52 | $connection->query( 53 | $connection->updateFromSelect($select, ['ea' => 'eav_attribute']) 54 | ); 55 | } 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * @inheritDoc 62 | */ 63 | public static function getDependencies() 64 | { 65 | return []; 66 | } 67 | 68 | /** 69 | * @inheritDoc 70 | */ 71 | public function getAliases() 72 | { 73 | return []; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Setup/Patch/Data/PatchData.php: -------------------------------------------------------------------------------- 1 | customEntitySetupFactory = $customEntitySetupFactory; 29 | } 30 | 31 | /** 32 | * @inheritDoc 33 | */ 34 | public function apply() 35 | { 36 | /** @var CustomEntitySetup $customEntitySetup */ 37 | $customEntitySetup = $this->customEntitySetupFactory->create(); 38 | $customEntitySetup->installEntities(); 39 | return $this; 40 | } 41 | 42 | /** 43 | * @inheritDoc 44 | */ 45 | public static function getDependencies() 46 | { 47 | return []; 48 | } 49 | 50 | /** 51 | * @inheritDoc 52 | */ 53 | public function getAliases() 54 | { 55 | return []; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Setup/Patch/Schema/RemoveCatalogAttributeCustomEntitySetId.php: -------------------------------------------------------------------------------- 1 | resourceConnection = $resourceConnection; 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | public function apply() 31 | { 32 | $connection = $this->resourceConnection->getConnection(); 33 | 34 | $catalogEavTable = $connection->getTableName('catalog_eav_attribute'); 35 | $eavTable = $connection->getTableName('eav_attribute'); 36 | 37 | if ( 38 | $connection->tableColumnExists( 39 | $catalogEavTable, 40 | CustomEntityAttributeSetIdMigration::ATTRIBUTE_SET_ID_COLUMN 41 | ) && 42 | $connection->tableColumnExists( 43 | $eavTable, 44 | CustomEntityAttributeSetIdMigration::ATTRIBUTE_SET_ID_COLUMN 45 | ) 46 | ) { 47 | $connection->dropColumn( 48 | $catalogEavTable, 49 | CustomEntityAttributeSetIdMigration::ATTRIBUTE_SET_ID_COLUMN 50 | ); 51 | } 52 | 53 | return $this; 54 | } 55 | 56 | /** 57 | * @inheritDoc 58 | */ 59 | public static function getDependencies() 60 | { 61 | return [CustomEntityAttributeSetIdMigration::class]; 62 | } 63 | 64 | /** 65 | * @inheritDoc 66 | */ 67 | public function getAliases() 68 | { 69 | return []; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Ui/DataProvider/CustomEntity/Form/CustomEntityDataProvider.php: -------------------------------------------------------------------------------- 1 | create(); 42 | $this->collection = $collection; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Ui/DataProvider/CustomEntity/Form/Modifier/AttributeSet.php: -------------------------------------------------------------------------------- 1 | attributeSetOptions = $attributeSetOptions; 35 | $this->locator = $locator; 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | public function modifyMeta(array $meta) 42 | { 43 | $name = $this->getFirstPanelCode($meta); 44 | if ($name && $this->locator->getEntity()->getId() == null) { 45 | $meta[$name]['children']['attribute_set_id']['arguments']['data']['config'] = [ 46 | 'component' => 'Magento_Catalog/js/components/attribute-set-select', 47 | 'disableLabel' => true, 48 | 'filterOptions' => true, 49 | 'elementTmpl' => 'ui/grid/filters/elements/ui-select', 50 | 'formElement' => 'select', 51 | 'componentType' => Field::NAME, 52 | 'options' => $this->attributeSetOptions->toOptionArray(), 53 | 'visible' => 1, 54 | 'required' => 1, 55 | 'label' => __('Attribute Set'), 56 | 'source' => $name, 57 | 'dataScope' => 'attribute_set_id', 58 | 'multiple' => false, 59 | 'sortOrder' => $this->getNextAttributeSortOrder( 60 | $meta, 61 | [CustomEntityInterface::IS_ACTIVE], 62 | self::ATTRIBUTE_SET_FIELD_ORDER 63 | ), 64 | ]; 65 | } 66 | 67 | return $meta; 68 | } 69 | 70 | /** 71 | * @inheritdoc 72 | */ 73 | public function modifyData(array $data) 74 | { 75 | $entity = $this->locator->getEntity(); 76 | $data[$entity->getId()][self::DATA_SOURCE_DEFAULT]['attribute_set_id'] = $entity->getAttributeSetId(); 77 | 78 | return $data; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Ui/DataProvider/CustomEntity/Form/Modifier/CustomEntityAttribute.php: -------------------------------------------------------------------------------- 1 | locator = $locator; 24 | $this->eavHelper = $eavHelper; 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | * 30 | * Changed custom_entity attribute value type to array. 31 | */ 32 | public function modifyData(array $data): array 33 | { 34 | if (!$this->locator->getEntity()->getId()) { 35 | return $data; 36 | } 37 | 38 | $entityId = $this->locator->getEntity()->getId(); 39 | 40 | foreach (array_keys($this->getGroups()) as $groupCode) { 41 | $attributes = !empty($this->getAttributes()[$groupCode]) ? $this->getAttributes()[$groupCode] : []; 42 | 43 | foreach ($attributes as $attribute) { 44 | if ( 45 | $attribute->getFrontendInput() == 'smile_custom_entity_select' 46 | && key_exists($attribute->getAttributeCode(), $data[$entityId][self::DATA_SOURCE_DEFAULT]) 47 | ) { 48 | $value = $data[$entityId][self::DATA_SOURCE_DEFAULT][$attribute->getAttributeCode()]; 49 | $data[$entityId][self::DATA_SOURCE_DEFAULT][$attribute->getAttributeCode()] = 50 | $value ? explode(',', $value) : []; 51 | } 52 | } 53 | } 54 | return $data; 55 | } 56 | /** 57 | * @inheritdoc 58 | * 59 | * Added custom_entity field configuration. 60 | */ 61 | public function modifyMeta(array $meta): array 62 | { 63 | foreach ($meta as $groupCode => $groupConfig) { 64 | $meta[$groupCode] = $this->modifyMetaConfig($groupConfig); 65 | } 66 | 67 | return $meta; 68 | } 69 | 70 | /** 71 | * Modification of group config. 72 | */ 73 | protected function modifyMetaConfig(array $metaConfig): array 74 | { 75 | if (isset($metaConfig['children'])) { 76 | foreach ($metaConfig['children'] as $attributeCode => $attributeConfig) { 77 | if ($this->startsWith($attributeCode, self::CONTAINER_PREFIX)) { 78 | $metaConfig['children'][$attributeCode] = $this->modifyMetaConfig($attributeConfig); 79 | } elseif ( 80 | !empty($attributeConfig['arguments']['data']['config']['dataType']) && 81 | $attributeConfig['arguments']['data']['config']['dataType'] === 'smile_custom_entity_select' 82 | ) { 83 | $metaConfig['children'][$attributeCode] = $this->modifyAttributeConfig($attributeConfig); 84 | } 85 | } 86 | } 87 | 88 | return $metaConfig; 89 | } 90 | 91 | /** 92 | * Modification of attribute config. 93 | */ 94 | protected function modifyAttributeConfig(array $attributeConfig): array 95 | { 96 | return array_replace_recursive( 97 | $attributeConfig, 98 | [ 99 | 'arguments' => [ 100 | 'data' => [ 101 | 'config' => [ 102 | 'component' => 'Magento_Ui/js/form/element/ui-select', 103 | 'disableLabel' => true, 104 | 'elementTmpl' => 'ui/grid/filters/elements/ui-select', 105 | 'filterOptions' => true, 106 | 'multiple' => true, 107 | 'showCheckbox' => true, 108 | ], 109 | ], 110 | ], 111 | ] 112 | ); 113 | } 114 | 115 | /** 116 | * List of attribute groups of the form. 117 | */ 118 | protected function getGroups(): array 119 | { 120 | return $this->eavHelper->getGroups($this->getAttributeSetId()); 121 | } 122 | 123 | /** 124 | * List of attributes of the form. 125 | */ 126 | protected function getAttributes(): array 127 | { 128 | return $this->eavHelper->getAttributes($this->locator->getEntity(), $this->getAttributeSetId()); 129 | } 130 | 131 | /** 132 | * Return current attribute set id. 133 | */ 134 | protected function getAttributeSetId(): int 135 | { 136 | return (int) $this->locator->getEntity()->getAttributeSetId(); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Ui/DataProvider/CustomEntity/Listing/AddStoreFieldToCollection.php: -------------------------------------------------------------------------------- 1 | storeManager = $storeManager; 23 | } 24 | 25 | /** 26 | * @inheritdoc 27 | */ 28 | public function addFilter(Collection $collection, $field, $condition = null) 29 | { 30 | if (isset($condition['eq']) && $condition['eq']) { 31 | /** @var \Smile\CustomEntity\Model\ResourceModel\CustomEntity\Collection $collection */ 32 | /** @var Store $store */ 33 | $store = $this->storeManager->getStore($condition['eq']); 34 | $collection->setStore($store); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Ui/DataProvider/CustomEntity/Listing/CustomEntityDataProvider.php: -------------------------------------------------------------------------------- 1 | create(); 53 | $this->collection = $collectionFactory; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ViewModel/Attribute/Data.php: -------------------------------------------------------------------------------- 1 | _eavConfig->getAttribute(CustomEntityInterface::ENTITY, $attributeName); 32 | if ( 33 | $attribute->getId() && 34 | $attribute->getFrontendInput() != 'image' && 35 | (!$attribute->getIsHtmlAllowedOnFront() && 36 | !$attribute->getIsWysiwygEnabled()) 37 | ) { 38 | if ($attribute->getFrontendInput() == 'textarea') { 39 | $attributeHtml = nl2br($attributeHtml); 40 | } 41 | } 42 | if ( 43 | $attributeHtml !== null 44 | && $attribute->getIsHtmlAllowedOnFront() 45 | && $attribute->getIsWysiwygEnabled() 46 | && $this->isDirectivesExists($attributeHtml) 47 | ) { 48 | $attributeHtml = $this->_getTemplateProcessor()->filter($attributeHtml); 49 | } 50 | 51 | $attributeHtml = $this->process( 52 | 'customEntityAttribute', 53 | $attributeHtml, 54 | ['product' => $customEntity, 'attribute' => $attributeName] 55 | ); 56 | 57 | return $attributeHtml; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "smile/module-custom-entity", 3 | "type": "magento2-module", 4 | "description": "Smile - Custom Entity Module", 5 | "keywords": ["magento2", "custom", "entity"], 6 | "authors": [ 7 | { 8 | "name": "Aurélien FOUCRET", 9 | "email": "aurelien.foucret@smile.fr" 10 | }, 11 | { 12 | "name": "Maxime LECLERCQ", 13 | "email": "maxime.leclercq@smile.fr" 14 | }, 15 | { 16 | "name": "Cédric MAGREZ", 17 | "email": "cedric.magrez@smile.fr" 18 | } 19 | ], 20 | "license": "OSL-3.0", 21 | "config": { 22 | "allow-plugins": { 23 | "dealerdirect/phpcodesniffer-composer-installer": true, 24 | "magento/composer-dependency-version-audit-plugin": true, 25 | "magento/magento-composer-installer": false 26 | }, 27 | "sort-packages": true 28 | }, 29 | "repositories": [ 30 | { 31 | "type": "composer", 32 | "url": "https://repo.magento.com/" 33 | } 34 | ], 35 | "require": { 36 | "php": "^7.4 || ^8.1", 37 | "smile/module-scoped-eav": "^1.3", 38 | "magento/module-sitemap": ">=100.3.0" 39 | }, 40 | "require-dev": { 41 | "smile/magento2-smilelab-quality-suite": "^3.0" 42 | }, 43 | "autoload": { 44 | "files": [ 45 | "registration.php" 46 | ], 47 | "psr-4": { 48 | "Smile\\CustomEntity\\" : "" 49 | } 50 | }, 51 | "suggest": { 52 | "smile/module-custom-entity-product-link": "Possibility to add product attribute for link product to custom entities", 53 | "smile/module-custom-entity-import-export": "Possibility to import custom entities" 54 | }, 55 | "minimum-stability": "dev", 56 | "prefer-stable": true 57 | } 58 | -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /etc/adminhtml/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | custom_entity_entity_form.custom_entity_entity_form 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Smile\ScopedEav\Ui\DataProvider\Entity\Form\Modifier\Eav 15 | 10 16 | 17 | 18 | Smile\CustomEntity\Ui\DataProvider\CustomEntity\Form\Modifier\AttributeSet 19 | 20 20 | 21 | 22 | Smile\ScopedEav\Ui\DataProvider\Entity\Form\Modifier\System 23 | 30 24 | 25 | 26 | Smile\CustomEntity\Ui\DataProvider\CustomEntity\Form\Modifier\CustomEntityAttribute 27 | 40 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Smile\CustomEntity\Ui\DataProvider\CustomEntity\Form\Modifier\Pool 36 | 37 | 38 | 39 | 40 | 41 | 42 | Smile\CustomEntity\Ui\DataProvider\CustomEntity\Listing\AddStoreFieldToCollection 43 | 44 | 45 | 46 | 47 | 48 | 49 | Smile\CustomEntity\Controller\Adminhtml\Entity\Builder 50 | 51 | 52 | 53 | 54 | 55 | Smile\CustomEntity\Controller\Adminhtml\Entity\Builder 56 | 57 | 58 | 59 | 60 | 61 | Smile\CustomEntity\Controller\Adminhtml\Entity\Builder 62 | 63 | 64 | 65 | 66 | 67 | Smile\CustomEntity\Controller\Adminhtml\Entity\Builder 68 | 69 | 70 | 71 | 72 | 73 | Smile\CustomEntity\Controller\Adminhtml\Entity\Builder 74 | 75 | 76 | 77 | 78 | Smile\CustomEntity\Controller\Adminhtml\Entity\Builder 79 | 80 | 81 | 82 | 83 | 84 | input 85 | input 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | smile_custom_entity_select 94 | Сustom entity 95 | 96 | 97 | 98 | 99 | 100 | 101 | Smile\CustomEntity\Model\Adminhtml\System\Config\Source\Inputtype 102 | 103 | 104 | 105 | 106 | Smile\CustomEntity\Model\Adminhtml\System\Config\Source\InputtypeFactory 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | Magento\Config\Model\Config\Source\Yesno 10 | 11 | 12 | 13 | Smile\CustomEntity\Model\CustomEntity\AttributeSet\Options 14 | 1 15 | Select entity types to include into Sitemap 16 | 17 | 18 | 19 | Magento\Config\Model\Config\Source\Yesno 20 | 21 | 22 | 23 | Magento\Sitemap\Model\Config\Source\Frequency 24 | 25 | 26 | 27 | Magento\Sitemap\Model\Config\Backend\Priority 28 | Valid values range from 0.0 to 1.0. 29 | 30 | 31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | smile_custom_entity 8 | 9 | 10 | 11 | 12 | 13 | 0 14 | 0 15 | daily 16 | 0.5 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /etc/db_schema_whitelist.json: -------------------------------------------------------------------------------- 1 | { 2 | "smile_custom_entity_eav_attribute": { 3 | "column": { 4 | "attribute_id": true, 5 | "is_global": true, 6 | "is_wysiwyg_enabled": true, 7 | "is_html_allowed_on_front": true, 8 | "custom_entity_attribute_set_id": true 9 | }, 10 | "constraint": { 11 | "PRIMARY": true, 12 | "SMILE_CUSTOM_ENTT_EAV_ATTR_ATTR_ID_EAV_ATTR_ATTR_ID": true 13 | } 14 | }, 15 | "smile_custom_entity": { 16 | "column": { 17 | "entity_id": true, 18 | "attribute_set_id": true, 19 | "created_at": true, 20 | "updated_at": true 21 | }, 22 | "index": { 23 | "SMILE_CUSTOM_ENTITY_ATTRIBUTE_SET_ID": true 24 | }, 25 | "constraint": { 26 | "PRIMARY": true, 27 | "SMILE_CUSTOM_ENTT_ATTR_SET_ID_EAV_ATTR_SET_ATTR_SET_ID": true 28 | } 29 | }, 30 | "smile_custom_entity_int": { 31 | "column": { 32 | "value_id": true, 33 | "attribute_id": true, 34 | "store_id": true, 35 | "entity_id": true, 36 | "value": true 37 | }, 38 | "index": { 39 | "SMILE_CUSTOM_ENTITY_INT_ATTRIBUTE_ID": true, 40 | "SMILE_CUSTOM_ENTITY_INT_STORE_ID": true 41 | }, 42 | "constraint": { 43 | "PRIMARY": true, 44 | "SMILE_CUSTOM_ENTITY_INT_ATTRIBUTE_ID_EAV_ATTRIBUTE_ATTRIBUTE_ID": true, 45 | "SMILE_CUSTOM_ENTITY_INT_ENTITY_ID_SMILE_CUSTOM_ENTITY_ENTITY_ID": true, 46 | "SMILE_CUSTOM_ENTITY_INT_STORE_ID_STORE_STORE_ID": true, 47 | "SMILE_CUSTOM_ENTITY_INT_ENTITY_ID_ATTRIBUTE_ID_STORE_ID": true 48 | } 49 | }, 50 | "smile_custom_entity_decimal": { 51 | "column": { 52 | "value_id": true, 53 | "attribute_id": true, 54 | "store_id": true, 55 | "entity_id": true, 56 | "value": true 57 | }, 58 | "index": { 59 | "SMILE_CUSTOM_ENTITY_DECIMAL_ATTRIBUTE_ID": true, 60 | "SMILE_CUSTOM_ENTITY_DECIMAL_STORE_ID": true 61 | }, 62 | "constraint": { 63 | "PRIMARY": true, 64 | "SMILE_CUSTOM_ENTT_DEC_ATTR_ID_EAV_ATTR_ATTR_ID": true, 65 | "SMILE_CUSTOM_ENTT_DEC_ENTT_ID_SMILE_CUSTOM_ENTT_ENTT_ID": true, 66 | "SMILE_CUSTOM_ENTITY_DECIMAL_STORE_ID_STORE_STORE_ID": true, 67 | "SMILE_CUSTOM_ENTITY_DECIMAL_ENTITY_ID_ATTRIBUTE_ID_STORE_ID": true 68 | } 69 | }, 70 | "smile_custom_entity_varchar": { 71 | "column": { 72 | "value_id": true, 73 | "attribute_id": true, 74 | "store_id": true, 75 | "entity_id": true, 76 | "value": true 77 | }, 78 | "index": { 79 | "SMILE_CUSTOM_ENTITY_VARCHAR_ATTRIBUTE_ID": true, 80 | "SMILE_CUSTOM_ENTITY_VARCHAR_STORE_ID": true 81 | }, 82 | "constraint": { 83 | "PRIMARY": true, 84 | "SMILE_CUSTOM_ENTT_VCHR_ATTR_ID_EAV_ATTR_ATTR_ID": true, 85 | "SMILE_CUSTOM_ENTT_VCHR_ENTT_ID_SMILE_CUSTOM_ENTT_ENTT_ID": true, 86 | "SMILE_CUSTOM_ENTITY_VARCHAR_STORE_ID_STORE_STORE_ID": true, 87 | "SMILE_CUSTOM_ENTITY_VARCHAR_ENTITY_ID_ATTRIBUTE_ID_STORE_ID": true 88 | } 89 | }, 90 | "smile_custom_entity_text": { 91 | "column": { 92 | "value_id": true, 93 | "attribute_id": true, 94 | "store_id": true, 95 | "entity_id": true, 96 | "value": true 97 | }, 98 | "index": { 99 | "SMILE_CUSTOM_ENTITY_TEXT_ATTRIBUTE_ID": true, 100 | "SMILE_CUSTOM_ENTITY_TEXT_STORE_ID": true 101 | }, 102 | "constraint": { 103 | "PRIMARY": true, 104 | "SMILE_CUSTOM_ENTITY_TEXT_ATTRIBUTE_ID_EAV_ATTRIBUTE_ATTRIBUTE_ID": true, 105 | "SMILE_CUSTOM_ENTITY_TEXT_ENTITY_ID_SMILE_CUSTOM_ENTITY_ENTITY_ID": true, 106 | "SMILE_CUSTOM_ENTITY_TEXT_STORE_ID_STORE_STORE_ID": true, 107 | "SMILE_CUSTOM_ENTITY_TEXT_ENTITY_ID_ATTRIBUTE_ID_STORE_ID": true 108 | } 109 | }, 110 | "smile_custom_entity_datetime": { 111 | "column": { 112 | "value_id": true, 113 | "attribute_id": true, 114 | "store_id": true, 115 | "entity_id": true, 116 | "value": true 117 | }, 118 | "index": { 119 | "SMILE_CUSTOM_ENTITY_DATETIME_ATTRIBUTE_ID": true, 120 | "SMILE_CUSTOM_ENTITY_DATETIME_STORE_ID": true 121 | }, 122 | "constraint": { 123 | "PRIMARY": true, 124 | "SMILE_CUSTOM_ENTT_DTIME_ATTR_ID_EAV_ATTR_ATTR_ID": true, 125 | "SMILE_CUSTOM_ENTT_DTIME_ENTT_ID_SMILE_CUSTOM_ENTT_ENTT_ID": true, 126 | "SMILE_CUSTOM_ENTITY_DATETIME_STORE_ID_STORE_STORE_ID": true, 127 | "SMILE_CUSTOM_ENTITY_DATETIME_ENTITY_ID_ATTRIBUTE_ID_STORE_ID": true 128 | } 129 | }, 130 | "smile_custom_entity_website": { 131 | "column": { 132 | "entity_id": true, 133 | "website_id": true 134 | }, 135 | "index": { 136 | "SMILE_CUSTOM_ENTITY_WEBSITE_WEBSITE_ID": true 137 | }, 138 | "constraint": { 139 | "PRIMARY": true, 140 | "SMILE_CUSTOM_ENTITY_WEBSITE_WEBSITE_ID_STORE_WEBSITE_WEBSITE_ID": true, 141 | "SMILE_CUSTOM_ENTT_WS_ENTT_ID_SMILE_CUSTOM_ENTT_ENTT_ID": true 142 | } 143 | }, 144 | "eav_attribute": { 145 | "column": { 146 | "custom_entity_attribute_set_id": true 147 | }, 148 | "constraint": { 149 | "EAV_ATTR_CUSTOM_ENTT_ATTR_SET_ID_EAV_ATTR_SET_ATTR_SET_ID": true 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Smile\CustomEntity\Api\CustomEntityRepositoryInterface 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | smile_custom_entity 26 | smile_custom_entity 27 | entity_id 28 | 29 | Magento\Store\Model\StoreScopeProvider 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | Magento\Store\Model\StoreScopeProvider 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Smile\CustomEntity\EntityCreator\MetadataPool 51 | 52 | 53 | 54 | 55 | 56 | Smile\CustomEntity\EntityCreator\MetadataPool 57 | Smile\CustomEntity\Model\Entity\CreationScopeResolver 58 | 59 | 60 | 61 | 62 | 63 | Smile\ScopedEav\Model\ResourceModel\AttributePersistor 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Smile\CustomEntity\Model\ResourceModel\CreateHandler 73 | Smile\CustomEntity\Model\ResourceModel\UpdateHandler 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | Magento\Framework\EntityManager\AbstractModelHydrator 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Smile\CustomEntity\Model\ResourceModel\CustomEntity\Attribute\Grid\Collection 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | select 101 | smile_custom_entity 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor 111 | Magento\Framework\Api\SearchCriteria\CollectionProcessor\SortingProcessor 112 | Magento\Framework\Api\SearchCriteria\CollectionProcessor\PaginationProcessor 113 | 114 | 115 | 116 | 117 | 118 | Smile\CustomEntity\Model\Api\SearchCriteria\CustomEntityCollectionProcessor 119 | 120 | 121 | 122 | 123 | 124 | Smile\CustomEntity\Model\Sitemap\CustomEntityProvider 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /etc/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /etc/frontend/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Smile\CustomEntity\Controller\Router 8 | false 9 | 30 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 6 3 | phpVersion: 70400 4 | checkMissingIterableValueType: false 5 | treatPhpDocTypesAsCertain: false 6 | paths: 7 | - . 8 | excludePaths: 9 | - 'vendor/*' 10 | 11 | includes: 12 | - %currentWorkingDirectory%/vendor/smile/magento2-smilelab-phpstan/extension.neon 13 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Smile_CustomEntity::attributes_attributes 8 | 9 | 10 | 11 | 12 | 13 | complex 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_attribute_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_attribute_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_entity_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | complex 9 | 10 | 11 | 12 | 13 | 14 | 1 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_entity_form.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_entity_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_entity_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_entity_reload.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_set_add.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Smile_CustomEntity::attributes_set 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_set_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Smile_CustomEntity::attributes_set 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /view/adminhtml/layout/custom_entity_set_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Smile_CustomEntity::attributes_set 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/custom_entity_attribute_listing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | custom_entity_attribute_listing.custom_entity_attribute_listing_data_source 7 | custom_entity_attribute_listing.custom_entity_attribute_listing_data_source 8 | 9 | custom_entity_attribute_columns 10 | 11 | 12 | add 13 | Add New Attribute 14 | primary 15 | */*/new 16 | 17 | 18 | 19 | 20 | 21 | 22 | Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider 23 | custom_entity_attribute_listing_data_source 24 | attribute_id 25 | id 26 | 27 | 28 | Magento_Ui/js/grid/provider 29 | 30 | 31 | attribute_id 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | true 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Magento_Ui/js/form/element/ui-select 52 | ui/grid/filters/elements/ui-select 53 | 54 | 55 | 56 | 57 | 58 | column 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | custom_entity_attribute_listing.custom_entity_attribute_listing.custom_entity_attribute_columns.actions 73 | applyAction 74 | 75 | edit 76 | ${ $.$data.rowIndex } 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | text 86 | asc 87 | Attribute Code 88 | 89 | 90 | 91 | 92 | 93 | 94 | text 95 | Frontend Label 96 | 97 | 98 | 99 | 100 | 101 | 102 | attribute_id 103 | custom_entity/attribute/edit 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/custom_entity_entity_form.xml: -------------------------------------------------------------------------------- 1 | 2 |
4 | 5 | 6 | custom_entity_entity_form.custom_entity_entity_form_data_source 7 | custom_entity_entity_form.custom_entity_entity_form_data_source 8 | custom_entity_entity_form 9 | 10 | templates/form/collapsible 11 | true 12 | 13 | 14 | general.attribute_set_id:value 15 | 16 |