├── Api
├── AuthorRepositoryInterface.php
└── Data
│ ├── AuthorInterface.php
│ └── AuthorSearchResultsInterface.php
├── Block
├── Adminhtml
│ └── Author
│ │ └── Edit
│ │ └── Buttons
│ │ ├── Back.php
│ │ ├── Delete.php
│ │ ├── Generic.php
│ │ ├── Reset.php
│ │ ├── Save.php
│ │ └── SaveAndContinue.php
├── Author
│ ├── ListAuthor.php
│ ├── ListAuthor
│ │ ├── Rss.php
│ │ └── Rss
│ │ │ └── Link.php
│ └── ViewAuthor.php
├── Image.php
└── ImageBuilder.php
├── Controller
├── Adminhtml
│ ├── Author.php
│ └── Author
│ │ ├── Delete.php
│ │ ├── Edit.php
│ │ ├── File
│ │ └── Upload.php
│ │ ├── Image
│ │ └── Upload.php
│ │ ├── Index.php
│ │ ├── InlineEdit.php
│ │ ├── MassAction.php
│ │ ├── MassDelete.php
│ │ ├── MassDisable.php
│ │ ├── MassEnable.php
│ │ ├── NewAction.php
│ │ ├── Save.php
│ │ └── Upload.php
├── Author
│ ├── Index.php
│ ├── Rss.php
│ └── View.php
├── RegistryConstants.php
└── Router.php
├── Helper
└── Image.php
├── LICENSE
├── Model
├── Author.php
├── Author
│ ├── DataProvider.php
│ ├── Rss.php
│ └── Url.php
├── AuthorFactory.php
├── AuthorRepository.php
├── FactoryInterface.php
├── Image.php
├── Output.php
├── ResourceModel
│ ├── Author.php
│ └── Author
│ │ ├── Collection.php
│ │ └── Grid
│ │ ├── Collection.php
│ │ └── ServiceCollection.php
├── Routing
│ ├── Entity.php
│ └── RoutableInterface.php
├── Source
│ ├── AbstractSource.php
│ ├── Country.php
│ └── Options.php
├── Uploader.php
└── UploaderPool.php
├── Plugin
└── Block
│ └── Topmenu.php
├── README.md
├── Setup
├── InstallSchema.php
└── Uninstall.php
├── Test
└── Unit
│ ├── Model
│ ├── Author
│ │ ├── DataProviderTest.php
│ │ ├── RssTest.php
│ │ └── UrlTest.php
│ ├── AuthorTest.php
│ ├── Source
│ │ └── CountryTest.php
│ ├── UploaderPoolTest.php
│ └── UploaderTest.php
│ └── Ui
│ ├── Component
│ └── Listing
│ │ └── Column
│ │ ├── AuthorActionsTest.php
│ │ ├── AvatarTest.php
│ │ └── Store
│ │ └── OptionsTest.php
│ └── DataProvider
│ └── Author
│ └── Form
│ └── Modifier
│ └── AuthorDataTest.php
├── Ui
├── Component
│ └── Listing
│ │ └── Column
│ │ ├── AuthorActions.php
│ │ ├── Avatar.php
│ │ └── Store
│ │ └── Options.php
└── DataProvider
│ └── Author
│ └── Form
│ └── Modifier
│ └── AuthorData.php
├── composer.json
├── etc
├── acl.xml
├── adminhtml
│ ├── di.xml
│ ├── menu.xml
│ ├── routes.xml
│ └── system.xml
├── config.xml
├── di.xml
├── frontend
│ ├── di.xml
│ └── routes.xml
└── module.xml
├── i18l
└── en_US.csv
├── registration.php
└── view
├── adminhtml
├── layout
│ ├── sample_news_author_edit.xml
│ └── sample_news_author_index.xml
├── ui_component
│ ├── sample_news_author_form.xml
│ └── sample_news_author_listing.xml
└── web
│ └── template
│ ├── file-preview.html
│ └── image-preview.html
├── base
└── web
│ └── images
│ └── author
│ └── placeholder
│ └── avatar.jpg
└── frontend
├── layout
├── sample_news_author_index.xml
└── sample_news_author_view.xml
└── templates
├── author
├── list.phtml
└── view.phtml
├── image.phtml
├── image_with_borders.phtml
└── rss
└── link.phtml
/Api/AuthorRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | __('Back'),
33 | 'on_click' => sprintf("location.href = '%s';", $this->getBackUrl()),
34 | 'class' => 'back',
35 | 'sort_order' => 10
36 | ];
37 | }
38 |
39 | /**
40 | * Get URL for back (reset) button
41 | *
42 | * @return string
43 | */
44 | public function getBackUrl()
45 | {
46 | return $this->getUrl('*/*/');
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Author/Edit/Buttons/Delete.php:
--------------------------------------------------------------------------------
1 | getAuthorId()) {
33 | $data = [
34 | 'label' => __('Delete Author'),
35 | 'class' => 'delete',
36 | 'on_click' => 'deleteConfirm(\'' . __(
37 | 'Are you sure you want to do this?'
38 | ) . '\', \'' . $this->getDeleteUrl() . '\')',
39 | 'sort_order' => 20,
40 | ];
41 | }
42 | return $data;
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function getDeleteUrl()
49 | {
50 | return $this->getUrl('*/*/delete', ['author_id' => $this->getAuthorId()]);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Author/Edit/Buttons/Generic.php:
--------------------------------------------------------------------------------
1 | context = $context;
45 | $this->authorRepository = $authorRepository;
46 | }
47 |
48 | /**
49 | * Return Author page ID
50 | *
51 | * @return int|null
52 | */
53 | public function getAuthorId()
54 | {
55 | try {
56 | return $this->authorRepository->getById(
57 | $this->context->getRequest()->getParam('author_id')
58 | )->getId();
59 | } catch (NoSuchEntityException $e) {
60 | return null;
61 | }
62 | }
63 |
64 | /**
65 | * Generate url by route and parameters
66 | *
67 | * @param string $route
68 | * @param array $params
69 | * @return string
70 | */
71 | public function getUrl($route = '', $params = [])
72 | {
73 | return $this->context->getUrlBuilder()->getUrl($route, $params);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Author/Edit/Buttons/Reset.php:
--------------------------------------------------------------------------------
1 | __('Reset'),
33 | 'class' => 'reset',
34 | 'on_click' => 'location.reload();',
35 | 'sort_order' => 30
36 | ];
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Author/Edit/Buttons/Save.php:
--------------------------------------------------------------------------------
1 | __('Save Author'),
33 | 'class' => 'save primary',
34 | 'data_attribute' => [
35 | 'mage-init' => ['button' => ['event' => 'save']],
36 | 'form-role' => 'save',
37 | ],
38 | 'sort_order' => 90,
39 | ];
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Author/Edit/Buttons/SaveAndContinue.php:
--------------------------------------------------------------------------------
1 | __('Save and Continue Edit'),
34 | 'class' => 'save',
35 | 'data_attribute' => [
36 | 'mage-init' => [
37 | 'button' => ['event' => 'saveAndContinueEdit'],
38 | ],
39 | ],
40 | 'sort_order' => 80,
41 | ];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Block/Author/ListAuthor.php:
--------------------------------------------------------------------------------
1 | authorCollectionFactory = $authorCollectionFactory;
56 | $this->urlFactory = $urlFactory;
57 | parent::__construct($context, $data);
58 | }
59 |
60 | /**
61 | * @return \Sample\News\Model\ResourceModel\Author\Collection
62 | */
63 | public function getAuthors()
64 | {
65 | if (is_null($this->authors)) {
66 | $this->authors = $this->authorCollectionFactory->create()
67 | ->addFieldToSelect('*')
68 | ->addFieldToFilter('is_active', Author::STATUS_ENABLED)
69 | ->addStoreFilter($this->_storeManager->getStore()->getId())
70 | ->setOrder('name', 'ASC');
71 | }
72 | return $this->authors;
73 | }
74 |
75 | /**
76 | * @return $this
77 | */
78 | protected function _prepareLayout()
79 | {
80 | parent::_prepareLayout();
81 | /** @var \Magento\Theme\Block\Html\Pager $pager */
82 | $pager = $this->getLayout()->createBlock(Pager::class, 'sample_news.author.list.pager');
83 | $pager->setCollection($this->getAuthors());
84 | $this->setChild('pager', $pager);
85 | $this->getAuthors()->load();
86 | return $this;
87 | }
88 |
89 | /**
90 | * @return string
91 | */
92 | public function getPagerHtml()
93 | {
94 | return $this->getChildHtml('pager');
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Block/Author/ListAuthor/Rss.php:
--------------------------------------------------------------------------------
1 | rssModel = $rssModel;
74 | $this->urlModel = $urlModel;
75 | $this->authorCollectionFactory = $authorCollectionFactory;
76 | $this->storeManager = $storeManager;
77 | parent::__construct($context, $data);
78 | }
79 |
80 | /**
81 | * @return int
82 | */
83 | protected function getStoreId()
84 | {
85 | $storeId = (int)$this->getRequest()->getParam('store_id');
86 | if ($storeId == null) {
87 | $storeId = $this->storeManager->getStore()->getId();
88 | }
89 | return $storeId;
90 | }
91 |
92 | /**
93 | * @return array
94 | */
95 | public function getRssData()
96 | {
97 | $url = $this->urlModel->getListUrl();
98 | $data = [
99 | 'title' => __('Authors'),
100 | 'description' => __('Authors'),
101 | 'link' => $url,
102 | 'charset' => 'UTF-8'
103 | ];
104 | $collection = $this->authorCollectionFactory->create();
105 | $collection->addStoreFilter($this->getStoreId());
106 | $collection->addFieldToFilter('is_active', Author::STATUS_ENABLED);
107 | $collection->addFieldToFilter('in_rss', 1);
108 | foreach ($collection as $item) {
109 | /** @var \Sample\News\Model\Author $item */
110 | $description = '
';
111 | $description = sprintf($description, $item->getAuthorUrl(), $item->getName());
112 | $data['entries'][] = [
113 | 'title' => $item->getName(),
114 | 'link' => $item->getAuthorUrl(),
115 | 'description' => $description,
116 | ];
117 | }
118 | return $data;
119 | }
120 |
121 | /**
122 | * Check if RSS feed allowed
123 | *
124 | * @return mixed
125 | */
126 | public function isAllowed()
127 | {
128 | return $this->rssModel->isRssEnabled();
129 | }
130 |
131 | /**
132 | * Get information about all feeds this Data Provider is responsible for
133 | *
134 | * @return array
135 | */
136 | public function getFeeds()
137 | {
138 | $feeds = [];
139 | $feeds[] = [
140 | 'label' => __('Authors'),
141 | 'link' => $this->rssModel->getRssLink(),
142 | ];
143 | $result = ['group' => __('News'), 'feeds' => $feeds];
144 | return $result;
145 | }
146 |
147 | /**
148 | * @return bool
149 | */
150 | public function isAuthRequired()
151 | {
152 | return false;
153 | }
154 |
155 | /**
156 | * @return int
157 | */
158 | public function getCacheLifetime()
159 | {
160 | $lifetime = $this->_scopeConfig->getValue(
161 | self::CACHE_LIFETIME_CONFIG_PATH,
162 | ScopeInterface::SCOPE_STORE
163 | );
164 | return $lifetime ?: null;
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/Block/Author/ListAuthor/Rss/Link.php:
--------------------------------------------------------------------------------
1 | rssModel = $rssModel;
42 | parent::__construct($context, $data);
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function isRssEnabled()
49 | {
50 | return $this->rssModel->isRssEnabled();
51 | }
52 |
53 | /**
54 | * @return string
55 | */
56 | public function getLabel()
57 | {
58 | return __('Subscribe to RSS Feed');
59 | }
60 | /**
61 | * @return string
62 | */
63 | public function getLink()
64 | {
65 | return $this->rssModel->getRssLink();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Block/Author/ViewAuthor.php:
--------------------------------------------------------------------------------
1 | coreRegistry = $registry;
50 | $this->imageBuilder = $imageBuilder;
51 | parent::__construct($context, $data);
52 | }
53 |
54 | /**
55 | * get current author
56 | *
57 | * @return \Sample\News\Model\Author
58 | */
59 | public function getCurrentAuthor()
60 | {
61 | return $this->coreRegistry->registry('current_author');
62 | }
63 |
64 | /**
65 | * @param $entity
66 | * @param $imageId
67 | * @param array $attributes
68 | * @return \Sample\News\Block\Image
69 | */
70 | public function getImage($entity, $imageId, $attributes = [])
71 | {
72 | return $this->imageBuilder->setEntity($entity)
73 | ->setImageId($imageId)
74 | ->setAttributes($attributes)
75 | ->create();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Block/Image.php:
--------------------------------------------------------------------------------
1 | setTemplate($data['template']);
54 | unset($data['template']);
55 | }
56 | parent::__construct($context, $data);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Block/ImageBuilder.php:
--------------------------------------------------------------------------------
1 | helperFactory = $helperFactory;
67 | $this->imageFactory = $imageFactory;
68 | $this->entityCode = $entityCode;
69 | }
70 |
71 | /**
72 | * @param \Magento\Framework\Model\AbstractModel $entity
73 | * @return $this
74 | */
75 | public function setEntity(AbstractModel $entity)
76 | {
77 | $this->entity = $entity;
78 | return $this;
79 | }
80 |
81 | /**
82 | * Set image ID
83 | *
84 | * @param string $imageId
85 | * @return $this
86 | */
87 | public function setImageId($imageId)
88 | {
89 | $this->imageId = $imageId;
90 | return $this;
91 | }
92 |
93 | /**
94 | * Set custom attributes
95 | *
96 | * @param array $attributes
97 | * @return $this
98 | */
99 | public function setAttributes(array $attributes)
100 | {
101 | if ($attributes) {
102 | $this->attributes = $attributes;
103 | }
104 | return $this;
105 | }
106 |
107 | /**
108 | * Retrieve image custom attributes for HTML element
109 | *
110 | * @return string
111 | */
112 | protected function getCustomAttributes()
113 | {
114 | $result = [];
115 | foreach ($this->attributes as $name => $value) {
116 | $result[] = $name . '="' . $value . '"';
117 | }
118 | return !empty($result) ? implode(' ', $result) : '';
119 | }
120 |
121 | /**
122 | * Calculate image ratio
123 | *
124 | * @param ImageHelper $helper
125 | * @return float|int
126 | */
127 | protected function getRatio(ImageHelper $helper)
128 | {
129 | $width = $helper->getWidth();
130 | $height = $helper->getHeight();
131 | if ($width && $height) {
132 | return $height / $width;
133 | }
134 | return 1;
135 | }
136 |
137 | /**
138 | * Create image block
139 | *
140 | * @return \Sample\News\Block\Image
141 | */
142 | public function create()
143 | {
144 | /** @var ImageHelper $helper */
145 | $helper = $this->helperFactory
146 | ->create([
147 | 'entityCode' => $this->entityCode
148 | ])
149 | ->init(
150 | $this->entity,
151 | $this->imageId,
152 | $this->attributes
153 | );
154 |
155 | $template = $helper->getFrame()
156 | ? 'Sample_News::image.phtml'
157 | : 'Sample_News::image_with_borders.phtml';
158 |
159 | $imagesize = $helper->getResizedImageInfo();
160 |
161 | $data = [
162 | 'data' => [
163 | 'template' => $template,
164 | 'image_url' => $helper->getUrl(),
165 | 'width' => $helper->getWidth(),
166 | 'height' => $helper->getHeight(),
167 | 'label' => $helper->getLabel(),
168 | 'ratio' => $this->getRatio($helper),
169 | 'custom_attributes' => $this->getCustomAttributes(),
170 | 'resized_image_width' => !empty($imagesize[0]) ? $imagesize[0] : $helper->getWidth(),
171 | 'resized_image_height' => !empty($imagesize[1]) ? $imagesize[1] : $helper->getHeight(),
172 | ],
173 | ];
174 |
175 | return $this->imageFactory->create($data);
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author.php:
--------------------------------------------------------------------------------
1 | coreRegistry = $registry;
75 | $this->authorRepository = $authorRepository;
76 | $this->resultPageFactory = $resultPageFactory;
77 | $this->dateFilter = $dateFilter;
78 | parent::__construct($context);
79 | }
80 |
81 | /**
82 | * filter dates
83 | *
84 | * @param array $data
85 | * @return array
86 | */
87 | public function filterData($data)
88 | {
89 | $inputFilter = new \Zend_Filter_Input(
90 | ['dob' => $this->dateFilter],
91 | [],
92 | $data
93 | );
94 | $data = $inputFilter->getUnescaped();
95 | if (isset($data['awards'])) {
96 | if (is_array($data['awards'])) {
97 | $data['awards'] = implode(',', $data['awards']);
98 | }
99 | }
100 | return $data;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/Delete.php:
--------------------------------------------------------------------------------
1 | resultRedirectFactory->create();
32 | $id = $this->getRequest()->getParam('author_id');
33 | if ($id) {
34 | try {
35 | $this->authorRepository->deleteById($id);
36 | $this->messageManager->addSuccessMessage(__('The author has been deleted.'));
37 | $resultRedirect->setPath('sample_news/*/');
38 | return $resultRedirect;
39 | } catch (NoSuchEntityException $e) {
40 | $this->messageManager->addErrorMessage(__('The author no longer exists.'));
41 | return $resultRedirect->setPath('sample_news/*/');
42 | } catch (LocalizedException $e) {
43 | $this->messageManager->addErrorMessage($e->getMessage());
44 | return $resultRedirect->setPath('sample_news/author/edit', ['author_id' => $id]);
45 | } catch (\Exception $e) {
46 | $this->messageManager->addErrorMessage(__('There was a problem deleting the author'));
47 | return $resultRedirect->setPath('sample_news/author/edit', ['author_id' => $id]);
48 | }
49 | }
50 | $this->messageManager->addErrorMessage(__('We can\'t find a author to delete.'));
51 | $resultRedirect->setPath('sample_news/*/');
52 | return $resultRedirect;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/Edit.php:
--------------------------------------------------------------------------------
1 | getRequest()->getParam('author_id');
33 | $this->coreRegistry->register(RegistryConstants::CURRENT_AUTHOR_ID, $authorId);
34 |
35 | return $authorId;
36 | }
37 |
38 | /**
39 | * Edit or create author
40 | *
41 | * @return \Magento\Backend\Model\View\Result\Page
42 | */
43 | public function execute()
44 | {
45 | $authorId = $this->_initAuthor();
46 |
47 | /** @var \Magento\Backend\Model\View\Result\Page $resultPage */
48 | $resultPage = $this->resultPageFactory->create();
49 | $resultPage->setActiveMenu('Sample_News::author');
50 | $resultPage->getConfig()->getTitle()->prepend(__('Authors'));
51 | $resultPage->addBreadcrumb(__('News'), __('News'));
52 | $resultPage->addBreadcrumb(__('Authors'), __('Authors'), $this->getUrl('sample_news/author'));
53 |
54 | if ($authorId === null) {
55 | $resultPage->addBreadcrumb(__('New Author'), __('New Author'));
56 | $resultPage->getConfig()->getTitle()->prepend(__('New Author'));
57 | } else {
58 | $resultPage->addBreadcrumb(__('Edit Author'), __('Edit Author'));
59 | $resultPage->getConfig()->getTitle()->prepend(
60 | $this->authorRepository->getById($authorId)->getName()
61 | );
62 | }
63 | return $resultPage;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/File/Upload.php:
--------------------------------------------------------------------------------
1 | resultPageFactory->create();
33 | $resultPage->setActiveMenu('Sample_News::author');
34 | $resultPage->getConfig()->getTitle()->prepend(__('Authors'));
35 | $resultPage->addBreadcrumb(__('News'), __('News'));
36 | $resultPage->addBreadcrumb(__('Authors'), __('Authors'));
37 | return $resultPage;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/InlineEdit.php:
--------------------------------------------------------------------------------
1 | dataObjectProcessor = $dataObjectProcessor;
79 | $this->dataObjectHelper = $dataObjectHelper;
80 | $this->jsonFactory = $jsonFactory;
81 | $this->authorResourceModel = $authorResourceModel;
82 | parent::__construct($registry, $authorRepository, $resultPageFactory, $dateFilter, $context);
83 | }
84 |
85 | /**
86 | * @return \Magento\Framework\Controller\ResultInterface
87 | */
88 | public function execute()
89 | {
90 | /** @var \Magento\Framework\Controller\Result\Json $resultJson */
91 | $resultJson = $this->jsonFactory->create();
92 | $error = false;
93 | $messages = [];
94 |
95 | $postItems = $this->getRequest()->getParam('items', []);
96 | if (!($this->getRequest()->getParam('isAjax') && count($postItems))) {
97 | return $resultJson->setData([
98 | 'messages' => [__('Please correct the data sent.')],
99 | 'error' => true,
100 | ]);
101 | }
102 |
103 | foreach (array_keys($postItems) as $authorId) {
104 | /** @var \Sample\News\Model\Author|AuthorInterface $author */
105 | $author = $this->authorRepository->getById((int)$authorId);
106 | try {
107 | $authorData = $this->filterData($postItems[$authorId]);
108 | $this->dataObjectHelper->populateWithArray($author, $authorData , AuthorInterface::class);
109 | $this->authorResourceModel->saveAttribute($author, array_keys($authorData));
110 | } catch (LocalizedException $e) {
111 | $messages[] = $this->getErrorWithAuthorId($author, $e->getMessage());
112 | $error = true;
113 | } catch (\RuntimeException $e) {
114 | $messages[] = $this->getErrorWithAuthorId($author, $e->getMessage());
115 | $error = true;
116 | } catch (\Exception $e) {
117 | $messages[] = $this->getErrorWithAuthorId(
118 | $author,
119 | __('Something went wrong while saving the author.')
120 | );
121 | $error = true;
122 | }
123 | }
124 |
125 | return $resultJson->setData([
126 | 'messages' => $messages,
127 | 'error' => $error
128 | ]);
129 | }
130 |
131 | /**
132 | * Add author id to error message
133 | *
134 | * @param Author $author
135 | * @param string $errorText
136 | * @return string
137 | */
138 | protected function getErrorWithAuthorId(Author $author, $errorText)
139 | {
140 | return '[Author ID: ' . $author->getId() . '] ' . $errorText;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/MassAction.php:
--------------------------------------------------------------------------------
1 | filter = $filter;
74 | $this->collectionFactory = $collectionFactory;
75 | $this->successMessage = $successMessage;
76 | $this->errorMessage = $errorMessage;
77 | parent::__construct($registry, $authorRepository, $resultPageFactory, $dateFilter, $context);
78 | }
79 |
80 | /**
81 | * @param AuthorModel $author
82 | * @return mixed
83 | */
84 | protected abstract function massAction(AuthorModel $author);
85 |
86 | /**
87 | * execute action
88 | *
89 | * @return \Magento\Backend\Model\View\Result\Redirect
90 | */
91 | public function execute()
92 | {
93 | try {
94 | $collection = $this->filter->getCollection($this->collectionFactory->create());
95 | $collectionSize = $collection->getSize();
96 | foreach ($collection as $author) {
97 | $this->massAction($author);
98 | }
99 | $this->messageManager->addSuccessMessage(__($this->successMessage, $collectionSize));
100 | } catch (LocalizedException $e) {
101 | $this->messageManager->addErrorMessage($e->getMessage());
102 | } catch (\Exception $e) {
103 | $this->messageManager->addExceptionMessage($e, __($this->errorMessage));
104 | }
105 | $redirectResult = $this->resultRedirectFactory->create();
106 | $redirectResult->setPath('sample_news/*/index');
107 | return $redirectResult;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/MassDelete.php:
--------------------------------------------------------------------------------
1 | authorRepository->delete($author);
31 | return $this;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/MassDisable.php:
--------------------------------------------------------------------------------
1 | setIsActive($this->isActive);
36 | $this->authorRepository->save($author);
37 | return $this;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/MassEnable.php:
--------------------------------------------------------------------------------
1 | resultForwardFactory = $resultForwardFactory;
46 | parent::__construct($context);
47 | }
48 |
49 |
50 | /**
51 | * forward to edit
52 | *
53 | * @return \Magento\Backend\Model\View\Result\Forward
54 | */
55 | public function execute()
56 | {
57 | $resultForward = $this->resultForwardFactory->create();
58 | $resultForward->forward('edit');
59 | return $resultForward;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/Save.php:
--------------------------------------------------------------------------------
1 | authorFactory = $authorFactory;
76 | $this->dataObjectProcessor = $dataObjectProcessor;
77 | $this->dataObjectHelper = $dataObjectHelper;
78 | $this->uploaderPool = $uploaderPool;
79 | parent::__construct($registry, $authorRepository, $resultPageFactory, $dateFilter, $context);
80 | }
81 |
82 | /**
83 | * run the action
84 | *
85 | * @return \Magento\Backend\Model\View\Result\Redirect
86 | */
87 | public function execute()
88 | {
89 | /** @var \Sample\News\Api\Data\AuthorInterface $author */
90 | $author = null;
91 | $data = $this->getRequest()->getPostValue();
92 | $id = !empty($data['author_id']) ? $data['author_id'] : null;
93 | $resultRedirect = $this->resultRedirectFactory->create();
94 | try {
95 | if ($id) {
96 | $author = $this->authorRepository->getById((int)$id);
97 | } else {
98 | unset($data['author_id']);
99 | $author = $this->authorFactory->create();
100 | }
101 | $avatar = $this->getUploader('image')->uploadFileAndGetName('avatar', $data);
102 | $data['avatar'] = $avatar;
103 | $resume = $this->getUploader('file')->uploadFileAndGetName('resume', $data);
104 | $data['resume'] = $resume;
105 | $this->dataObjectHelper->populateWithArray($author, $data, AuthorInterface::class);
106 | $this->authorRepository->save($author);
107 | $this->messageManager->addSuccessMessage(__('You saved the author'));
108 | if ($this->getRequest()->getParam('back')) {
109 | $resultRedirect->setPath('sample_news/author/edit', ['author_id' => $author->getId()]);
110 | } else {
111 | $resultRedirect->setPath('sample_news/author');
112 | }
113 | } catch (LocalizedException $e) {
114 | $this->messageManager->addErrorMessage($e->getMessage());
115 | if ($author != null) {
116 | $this->storeAuthorDataToSession(
117 | $this->dataObjectProcessor->buildOutputDataArray(
118 | $author,
119 | AuthorInterface::class
120 | )
121 | );
122 | }
123 | $resultRedirect->setPath('sample_news/author/edit', ['author_id' => $id]);
124 | } catch (\Exception $e) {
125 | $this->messageManager->addErrorMessage(__('There was a problem saving the author'));
126 | if ($author != null) {
127 | $this->storeAuthorDataToSession(
128 | $this->dataObjectProcessor->buildOutputDataArray(
129 | $author,
130 | AuthorInterface::class
131 | )
132 | );
133 | }
134 | $resultRedirect->setPath('sample_news/author/edit', ['author_id' => $id]);
135 | }
136 | return $resultRedirect;
137 | }
138 |
139 | /**
140 | * @param $type
141 | * @return Uploader
142 | * @throws \Exception
143 | */
144 | protected function getUploader($type)
145 | {
146 | return $this->uploaderPool->getUploader($type);
147 | }
148 |
149 | /**
150 | * @param $authorData
151 | */
152 | protected function storeAuthorDataToSession($authorData)
153 | {
154 | $this->_getSession()->setSampleNewsAuthorData($authorData);
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Author/Upload.php:
--------------------------------------------------------------------------------
1 | uploader = $uploader;
49 | }
50 |
51 | /**
52 | * Upload file controller action
53 | *
54 | * @return \Magento\Framework\Controller\ResultInterface
55 | */
56 | public function execute()
57 | {
58 | try {
59 | $result = $this->uploader->saveFileToTmpDir($this->getFieldName());
60 |
61 | $result['cookie'] = [
62 | 'name' => $this->_getSession()->getName(),
63 | 'value' => $this->_getSession()->getSessionId(),
64 | 'lifetime' => $this->_getSession()->getCookieLifetime(),
65 | 'path' => $this->_getSession()->getCookiePath(),
66 | 'domain' => $this->_getSession()->getCookieDomain(),
67 | ];
68 | } catch (\Exception $e) {
69 | $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
70 | }
71 | return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result);
72 | }
73 |
74 | /**
75 | * @return string
76 | */
77 | protected function getFieldName()
78 | {
79 | return $this->_request->getParam('field');
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Controller/Author/Index.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
62 | $this->scopeConfig = $scopeConfig;
63 | }
64 |
65 | /**
66 | * @return \Magento\Framework\View\Result\Page
67 | */
68 | public function execute()
69 | {
70 | $resultPage = $this->resultPageFactory->create();
71 | $resultPage->getConfig()->getTitle()->set(
72 | $this->scopeConfig->getValue(self::META_TITLE_CONFIG_PATH, ScopeInterface::SCOPE_STORE)
73 | );
74 | $resultPage->getConfig()->setDescription(
75 | $this->scopeConfig->getValue(self::META_DESCRIPTION_CONFIG_PATH, ScopeInterface::SCOPE_STORE)
76 | );
77 | $resultPage->getConfig()->setKeywords(
78 | $this->scopeConfig->getValue(self::META_KEYWORDS_CONFIG_PATH, ScopeInterface::SCOPE_STORE)
79 | );
80 | if ($this->scopeConfig->isSetFlag(self::BREADCRUMBS_CONFIG_PATH, ScopeInterface::SCOPE_STORE)) {
81 | /** @var \Magento\Theme\Block\Html\Breadcrumbs $breadcrumbsBlock */
82 | $breadcrumbsBlock = $resultPage->getLayout()->getBlock('breadcrumbs');
83 | if ($breadcrumbsBlock) {
84 | $breadcrumbsBlock->addCrumb(
85 | 'home',
86 | [
87 | 'label' => __('Home'),
88 | 'link' => $this->_url->getUrl('')
89 | ]
90 | );
91 | $breadcrumbsBlock->addCrumb(
92 | 'authors',
93 | [
94 | 'label' => __('Authors'),
95 | ]
96 | );
97 | }
98 | }
99 | return $resultPage;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/Controller/Author/Rss.php:
--------------------------------------------------------------------------------
1 | getRequest()->setParam('type', 'authors');
31 | parent::execute();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Controller/Author/View.php:
--------------------------------------------------------------------------------
1 | resultForwardFactory = $resultForwardFactory;
85 | $this->authorRepository = $authorRepository;
86 | $this->resultPageFactory = $resultPageFactory;
87 | $this->coreRegistry = $coreRegistry;
88 | $this->urlModel = $urlModel;
89 | $this->scopeConfig = $scopeConfig;
90 | parent::__construct($context);
91 | }
92 |
93 | /**
94 | * @return \Magento\Framework\Controller\Result\Forward|\Magento\Framework\View\Result\Page
95 | */
96 | public function execute()
97 | {
98 | try {
99 | $authorId = (int)$this->getRequest()->getParam('id');
100 | $author = $this->authorRepository->getById($authorId);
101 |
102 | if (!$author->getIsActive()) {
103 | throw new \Exception();
104 | }
105 | } catch (\Exception $e){
106 | $resultForward = $this->resultForwardFactory->create();
107 | $resultForward->forward('noroute');
108 | return $resultForward;
109 | }
110 |
111 | $this->coreRegistry->register('current_author', $author);
112 |
113 | $resultPage = $this->resultPageFactory->create();
114 | //$title = ($author->getMetaTitle()) ?: $author->getName();
115 | $resultPage->getConfig()->getTitle()->set($author->getName());
116 | $resultPage->getConfig()->setDescription($author->getMetaDescription());
117 | $resultPage->getConfig()->setKeywords($author->getMetaKeywords());
118 | if ($this->scopeConfig->isSetFlag(self::BREADCRUMBS_CONFIG_PATH, ScopeInterface::SCOPE_STORE)) {
119 | /** @var \Magento\Theme\Block\Html\Breadcrumbs $breadcrumbsBlock */
120 | $breadcrumbsBlock = $resultPage->getLayout()->getBlock('breadcrumbs');
121 | if ($breadcrumbsBlock) {
122 | $breadcrumbsBlock->addCrumb(
123 | 'home',
124 | [
125 | 'label' => __('Home'),
126 | 'link' => $this->_url->getUrl('')
127 | ]
128 | );
129 | $breadcrumbsBlock->addCrumb(
130 | 'authors',
131 | [
132 | 'label' => __('Authors'),
133 | 'link' => $this->urlModel->getListUrl()
134 | ]
135 | );
136 | $breadcrumbsBlock->addCrumb(
137 | 'author-'.$author->getId(),
138 | [
139 | 'label' => $author->getName()
140 | ]
141 | );
142 | }
143 | }
144 |
145 | return $resultPage;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/Controller/RegistryConstants.php:
--------------------------------------------------------------------------------
1 | actionFactory = $actionFactory;
114 | $this->eventManager = $eventManager;
115 | $this->url = $url;
116 | $this->appState = $appState;
117 | $this->storeManager = $storeManager;
118 | $this->response = $response;
119 | $this->scopeConfig = $scopeConfig;
120 | $this->routingEntities = $routingEntities;
121 | }
122 |
123 | /**
124 | * Validate and Match News Author and modify request
125 | *
126 | * @param \Magento\Framework\App\RequestInterface|\Magento\Framework\HTTP\PhpEnvironment\Request $request
127 | * @return bool
128 | */
129 | public function match(RequestInterface $request)
130 | {
131 | if (!$this->dispatched) {
132 | $urlKey = trim($request->getPathInfo(), '/');
133 | $origUrlKey = $urlKey;
134 | /** @var Object $condition */
135 | $condition = new DataObject(['url_key' => $urlKey, 'continue' => true]);
136 | $this->eventManager->dispatch(
137 | 'sample_news_controller_router_match_before',
138 | ['router' => $this, 'condition' => $condition]
139 | );
140 | $urlKey = $condition->getUrlKey();
141 | if ($condition->getRedirectUrl()) {
142 | $this->response->setRedirect($condition->getRedirectUrl());
143 | $request->setDispatched(true);
144 | return $this->actionFactory->create(Redirect::class);
145 | }
146 | if (!$condition->getContinue()) {
147 | return null;
148 | }
149 | foreach ($this->routingEntities as $entityKey => $entity) {
150 | $match = $this->matchRoute($request, $entity, $urlKey, $origUrlKey);
151 | if ($match === false) {
152 | continue;
153 | }
154 | return $match;
155 | }
156 | }
157 | return null;
158 | }
159 |
160 | /**
161 | * @param RequestInterface|\Magento\Framework\HTTP\PhpEnvironment\Request $request
162 | * @param Entity $entity
163 | * @param $urlKey
164 | * @param $origUrlKey
165 | * @return bool|\Magento\Framework\App\ActionInterface|null
166 | */
167 | protected function matchRoute(RequestInterface $request, Entity $entity, $urlKey, $origUrlKey)
168 | {
169 | $listKey = $this->scopeConfig->getValue($entity->getListKeyConfigPath(), ScopeInterface::SCOPE_STORE);
170 | if ($listKey) {
171 | if ($urlKey == $listKey) {
172 | $request->setModuleName('sample_news');
173 | $request->setControllerName($entity->getController());
174 | $request->setActionName($entity->getListAction());
175 | $request->setAlias(Url::REWRITE_REQUEST_PATH_ALIAS, $urlKey);
176 | $this->dispatched = true;
177 | return $this->actionFactory->create(Forward::class);
178 | }
179 | }
180 | $prefix = $this->scopeConfig->getValue($entity->getPrefixConfigPath(), ScopeInterface::SCOPE_STORE);
181 | if ($prefix) {
182 | $parts = explode('/', $urlKey);
183 | if ($parts[0] != $prefix || count($parts) != 2) {
184 | return false;
185 | }
186 | $urlKey = $parts[1];
187 | }
188 | $configSuffix = $this->scopeConfig->getValue($entity->getSuffixConfigPath(), ScopeInterface::SCOPE_STORE);
189 | if ($configSuffix) {
190 | $suffix = substr($urlKey, -strlen($configSuffix) - 1);
191 | if ($suffix != '.'.$configSuffix) {
192 | return false;
193 | }
194 | $urlKey = substr($urlKey, 0, -strlen($configSuffix) - 1);
195 | }
196 | $instance = $entity->getFactory()->create();
197 | $id = $instance->checkUrlKey($urlKey, $this->storeManager->getStore()->getId());
198 | if (!$id) {
199 | return null;
200 | }
201 | $request->setModuleName('sample_news');
202 | $request->setControllerName($entity->getController());
203 | $request->setActionName($entity->getViewAction());
204 | $request->setParam($entity->getParam(), $id);
205 | $request->setAlias(Url::REWRITE_REQUEST_PATH_ALIAS, $origUrlKey);
206 | $request->setDispatched(true);
207 | $this->dispatched = true;
208 | return $this->actionFactory->create(Forward::class);
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Marius
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Model/Author/DataProvider.php:
--------------------------------------------------------------------------------
1 | collection = $authorCollectionFactory->create();
56 | $this->pool = $pool;
57 | parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
58 | $this->meta = $this->prepareMeta($this->meta);
59 | }
60 |
61 | /**
62 | * Prepares Meta
63 | *
64 | * @param array $meta
65 | * @return array
66 | */
67 | public function prepareMeta(array $meta)
68 | {
69 | $meta = parent::getMeta();
70 |
71 | /** @var ModifierInterface $modifier */
72 | foreach ($this->pool->getModifiersInstances() as $modifier) {
73 | $meta = $modifier->modifyMeta($meta);
74 | }
75 | return $meta;
76 | }
77 |
78 | /**
79 | * Get data
80 | *
81 | * @return array
82 | */
83 | public function getData()
84 | {
85 | /** @var ModifierInterface $modifier */
86 | foreach ($this->pool->getModifiersInstances() as $modifier) {
87 | $this->data = $modifier->modifyData($this->data);
88 | }
89 | return $this->data;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Model/Author/Rss.php:
--------------------------------------------------------------------------------
1 | urlBuilder = $urlBuilder;
63 | $this->scopeConfig = $scopeConfig;
64 | $this->storeManager = $storeManager;
65 | }
66 |
67 | /**
68 | * @return bool
69 | */
70 | public function isRssEnabled()
71 | {
72 | return
73 | $this->scopeConfig->getValue(self::GLOBAL_RSS_ACTIVE_CONFIG_PATH, ScopeInterface::SCOPE_STORE) &&
74 | $this->scopeConfig->getValue(self::AUTHOR_RSS_ACTIVE_CONFIG_PATH, ScopeInterface::SCOPE_STORE);
75 | }
76 |
77 | /**
78 | * @return string
79 | */
80 | public function getRssLink()
81 | {
82 | return $this->urlBuilder->getUrl(
83 | self::RSS_PAGE_URL,
84 | ['store' => $this->storeManager->getStore()->getId()]
85 | );
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Model/Author/Url.php:
--------------------------------------------------------------------------------
1 | urlBuilder = $urlBuilder;
60 | $this->scopeConfig = $scopeConfig;
61 | }
62 |
63 | /**
64 | * @return string
65 | */
66 | public function getListUrl()
67 | {
68 | $sefUrl = $this->scopeConfig->getValue(self::LIST_URL_CONFIG_PATH, ScopeInterface::SCOPE_STORE);
69 | if ($sefUrl) {
70 | return $this->urlBuilder->getUrl('', ['_direct' => $sefUrl]);
71 | }
72 | return $this->urlBuilder->getUrl('sample_news/author/index');
73 | }
74 |
75 | /**
76 | * @param Author $author
77 | * @return string
78 | */
79 | public function getAuthorUrl(Author $author)
80 | {
81 | if ($urlKey = $author->getUrlKey()) {
82 | $prefix = $this->scopeConfig->getValue(
83 | self::URL_PREFIX_CONFIG_PATH,
84 | ScopeInterface::SCOPE_STORE
85 | );
86 | $suffix = $this->scopeConfig->getValue(
87 | self::URL_SUFFIX_CONFIG_PATH,
88 | ScopeInterface::SCOPE_STORE
89 | );
90 | $path = (($prefix) ? $prefix . '/' : '').
91 | $urlKey .
92 | (($suffix) ? '.'. $suffix : '');
93 | return $this->urlBuilder->getUrl('', ['_direct'=>$path]);
94 | }
95 | return $this->urlBuilder->getUrl('sample_news/author/view', ['id' => $author->getId()]);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Model/AuthorFactory.php:
--------------------------------------------------------------------------------
1 | _objectManager = $objectManager;
48 | $this->_instanceName = $instanceName;
49 | }
50 |
51 | /**
52 | * Create class instance with specified parameters
53 | *
54 | * @param array $data
55 | * @return RoutableInterface|\Sample\News\Model\Author
56 | */
57 | public function create(array $data = array())
58 | {
59 | return $this->_objectManager->create($this->_instanceName, $data);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Model/FactoryInterface.php:
--------------------------------------------------------------------------------
1 | templateProcessor = $templateProcessor;
34 | }
35 |
36 | /**
37 | * @param $string
38 | * @return string
39 | */
40 | public function filterOutput($string)
41 | {
42 | return $this->templateProcessor->filter($string);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Model/ResourceModel/Author/Grid/Collection.php:
--------------------------------------------------------------------------------
1 | _eventPrefix = $eventPrefix;
80 | $this->_eventObject = $eventObject;
81 | $this->_init($model, $resourceModel);
82 | $this->setMainTable($mainTable);
83 | }
84 |
85 | /**
86 | * @return AggregationInterface
87 | */
88 | public function getAggregations()
89 | {
90 | return $this->aggregations;
91 | }
92 |
93 | /**
94 | * @param AggregationInterface $aggregations
95 | * @return $this
96 | */
97 | public function setAggregations($aggregations)
98 | {
99 | $this->aggregations = $aggregations;
100 | }
101 |
102 | /**
103 | * Get search criteria.
104 | *
105 | * @return \Magento\Framework\Api\SearchCriteriaInterface|null
106 | */
107 | public function getSearchCriteria()
108 | {
109 | return null;
110 | }
111 |
112 | /**
113 | * Set search criteria.
114 | *
115 | * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
116 | * @return $this
117 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
118 | */
119 | public function setSearchCriteria(SearchCriteriaInterface $searchCriteria = null)
120 | {
121 | return $this;
122 | }
123 |
124 | /**
125 | * Get total count.
126 | *
127 | * @return int
128 | */
129 | public function getTotalCount()
130 | {
131 | return $this->getSize();
132 | }
133 |
134 | /**
135 | * Set total count.
136 | *
137 | * @param int $totalCount
138 | * @return $this
139 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
140 | */
141 | public function setTotalCount($totalCount)
142 | {
143 | return $this;
144 | }
145 |
146 | /**
147 | * Set items list.
148 | *
149 | * @param \Magento\Framework\Api\ExtensibleDataInterface[] $items
150 | * @return $this
151 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
152 | */
153 | public function setItems(array $items = null)
154 | {
155 | return $this;
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/Model/ResourceModel/Author/Grid/ServiceCollection.php:
--------------------------------------------------------------------------------
1 | authorRepository = $authorRepository;
63 | $this->simpleDataObjectConverter = $simpleDataObjectConverter;
64 | parent::__construct($entityFactory, $filterBuilder, $searchCriteriaBuilder, $sortOrderBuilder);
65 | }
66 |
67 | /**
68 | * Load customer group collection data from service
69 | *
70 | * @param bool $printQuery
71 | * @param bool $logQuery
72 | * @return $this
73 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
74 | */
75 | public function loadData($printQuery = false, $logQuery = false)
76 | {
77 | if (!$this->isLoaded()) {
78 | $searchCriteria = $this->getSearchCriteria();
79 | $searchResults = $this->authorRepository->getList($searchCriteria);
80 | $this->_totalRecords = $searchResults->getTotalCount();
81 | /** @var AuthorInterface[] $authors */
82 | $authors = $searchResults->getItems();
83 | foreach ($authors as $author) {
84 | $authorItem = new DataObject();
85 | $authorItem->addData(
86 | $this->simpleDataObjectConverter->toFlatArray($author, AuthorInterface::class)
87 | );
88 | $this->_addItem($authorItem);
89 | }
90 | $this->_setIsLoaded();
91 | }
92 | return $this;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Model/Routing/Entity.php:
--------------------------------------------------------------------------------
1 | prefixConfigPath = $prefixConfigPath;
62 | $this->suffixConfigPath = $suffixConfigPath;
63 | $this->listKeyConfigPath = $listKeyConfigPath;
64 | $this->factory = $factory;
65 | $this->controller = $controller;
66 | $this->listAction = $listAction;
67 | $this->viewAction = $viewAction;
68 | $this->param = $param;
69 | }
70 |
71 | /**
72 | * @return string
73 | */
74 | public function getPrefixConfigPath()
75 | {
76 | return $this->prefixConfigPath;
77 | }
78 |
79 | /**
80 | * @return string
81 | */
82 | public function getSuffixConfigPath()
83 | {
84 | return $this->suffixConfigPath;
85 | }
86 |
87 | /**
88 | * @return string
89 | */
90 | public function getListKeyConfigPath()
91 | {
92 | return $this->listKeyConfigPath;
93 | }
94 |
95 | /**
96 | * @return string
97 | */
98 | public function getListAction()
99 | {
100 | return $this->listAction;
101 | }
102 |
103 | /**
104 | * @return FactoryInterface
105 | */
106 | public function getFactory()
107 | {
108 | return $this->factory;
109 | }
110 |
111 | /**
112 | * @return mixed
113 | */
114 | public function getController()
115 | {
116 | return $this->controller;
117 | }
118 |
119 | /**
120 | * @return string
121 | */
122 | public function getViewAction()
123 | {
124 | return $this->viewAction;
125 | }
126 |
127 | /**
128 | * @return string
129 | */
130 | public function getParam()
131 | {
132 | return $this->param;
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/Model/Routing/RoutableInterface.php:
--------------------------------------------------------------------------------
1 | options = $options;
36 | }
37 |
38 | /**
39 | * @return array
40 | */
41 | abstract public function toOptionArray();
42 |
43 | /**
44 | * @param $value
45 | * @return string
46 | */
47 | public function getOptionText($value)
48 | {
49 | $options = $this->getOptions();
50 | if (!is_array($value)) {
51 | $value = explode(',', $value);
52 | }
53 | $texts = [];
54 | foreach ($value as $v) {
55 | if (isset($options[$v])) {
56 | $texts[] = $options[$v];
57 | }
58 | }
59 | return implode(', ', $texts);
60 | }
61 | /**
62 | * get options as key value pair
63 | *
64 | * @return array
65 | */
66 | public function getOptions()
67 | {
68 | $options = [];
69 | foreach ($this->toOptionArray() as $values) {
70 | $options[$values['value']] = __($values['label']);
71 | }
72 | return $options;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Model/Source/Country.php:
--------------------------------------------------------------------------------
1 | countryCollectionFactory = $countryCollectionFactory;
40 | parent::__construct($options);
41 | }
42 |
43 | /**
44 | * get options as key value pair
45 | *
46 | * @return array
47 | */
48 | public function toOptionArray()
49 | {
50 | if (count($this->options) == 0) {
51 | $this->options = $this->countryCollectionFactory->create()->toOptionArray(' ');
52 | }
53 | return $this->options;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Model/Source/Options.php:
--------------------------------------------------------------------------------
1 | options as $values) {
33 | $options[] = [
34 | 'value' => $values['value'],
35 | 'label' => __($values['label'])
36 | ];
37 | }
38 | return $options;
39 |
40 | }
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Model/UploaderPool.php:
--------------------------------------------------------------------------------
1 | objectManager = $objectManager;
42 | $this->uploaders = $uploaders;
43 | }
44 |
45 | /**
46 | * @param $type
47 | * @return Uploader
48 | * @throws \Exception
49 | */
50 | public function getUploader($type)
51 | {
52 | if (!isset($this->uploaders[$type])) {
53 | throw new \Exception("Uploader not found for type: ".$type);
54 | }
55 | if (!is_object($this->uploaders[$type])) {
56 | $this->uploaders[$type] = $this->objectManager->create($this->uploaders[$type]);
57 |
58 | }
59 | $uploader = $this->uploaders[$type];
60 | if (!($uploader instanceof Uploader)) {
61 | throw new \Exception("Uploader for type {$type} not instance of ". Uploader::class);
62 | }
63 | return $uploader;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Plugin/Block/Topmenu.php:
--------------------------------------------------------------------------------
1 | url = $url;
45 | $this->request = $request;
46 | }
47 |
48 | /**
49 | * @param TopmenuBlock $subject
50 | * @param string $outermostClass
51 | * @param string $childrenWrapClass
52 | * @param int $limit
53 | * @SuppressWarnings("PMD.UnusedFormalParameter")
54 | */
55 | // @codingStandardsIgnoreStart
56 | public function beforeGetHtml(
57 | TopmenuBlock $subject,
58 | $outermostClass = '',
59 | $childrenWrapClass = '',
60 | $limit = 0
61 | ) {
62 | // @codingStandardsIgnoreEnd
63 | $node = new Node(
64 | $this->getNodeAsArray(),
65 | 'id',
66 | $subject->getMenu()->getTree(),
67 | $subject->getMenu()
68 | );
69 | $subject->getMenu()->addChild($node);
70 | }
71 |
72 | /**
73 | * @return array
74 | */
75 | protected function getNodeAsArray()
76 | {
77 | return [
78 | 'name' => __('Authors'),
79 | 'id' => 'authors-node',
80 | 'url' => $this->url->getListUrl(),
81 | 'has_active' => false,
82 | 'is_active' => in_array($this->request->getFullActionName(), $this->getActiveHandles())
83 | ];
84 | }
85 |
86 | /**
87 | * @return array
88 | */
89 | protected function getActiveHandles()
90 | {
91 | return [
92 | 'sample_news_author_index',
93 | 'sample_news_author_view'
94 | ];
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Magento 2.0 Sample Module
2 | ====================
3 |
4 | Last tested on Magento2 version 2.1
5 |
6 |
7 | 
8 |
9 | What I got so far:
10 | ----------
11 |
12 | - One custom entity Author. flat and related to store views
13 | - Backend section for the entity mentioned above
14 | - Frontend list and view for the entity mentioned above
15 | - List on Author view page on frontend
16 | - Rss feeds for author list.
17 | - Breadcrumbs support for list and view pages.
18 |
19 | The other types of entities and features listed in **the purpose** will follow.
20 | Don't put many hopes in this. Based on the comments on the magento 2 repo the grid system will be changed...A LOT.
21 |
22 | The purpose
23 | ----------
24 |
25 | ....of this repository is to hold a sample CRUD module for Magento 2.0.
26 | This module should contain the following:
27 |
28 | * 4 Entities.
29 | * 1 Flat - with a store selector. Similar to CMS pages
30 | * 1 Flat but behaving as a tree - with a store selector. Similar to categories but non EAV
31 | * 1 EAV - similar to products
32 | * 1 EAV but behaving as tree - Similar to categories.
33 | * Backend files for managing the entities mentioned above
34 | * Frontend files for list and view each of the entities mentioned above
35 | * RSS feeds for each entity mentioned above
36 | * SOAP & REST API files for the entities mentioned above
37 | * URL rewrites filed for frontend for the entities above
38 | * Files needed for a many to many relation between the entities above and products
39 | * Files needed for a many to many relation between the entities above and categories
40 | * Files needed for a many to many relation between the entities above (among themselves)
41 | * Each entity must support different attribute types:
42 | * Text
43 | * Textarea (with and without WYSIWYG editor)
44 | * Date
45 | * Yes/No
46 | * Dropdown (with different source models)
47 | * Multi-select (with different source models)
48 | * File
49 | * Image
50 | * Decimal
51 | * Integer (signed and unsigned)
52 | * Color
53 | * Each entity should have fronend links to the list page in one of the menu/link areas provided by the default theme
54 | * Each entity must have SEO attributes (meta-title, meta-description, meta-keywords)
55 | * Would be nice to have unit tests for every class in the code - but that's low priority.
56 | * Each entity type must have widgets for frontend (link, short view).
57 | * Each entity must support customer comments.
58 | * Each EAV entity must have a section for managing attributes (similar to product attributes).
59 |
60 | After this is complete (or almost) it will become the base source for the Ultimate Module Creator 2.0 which will be a version for Magento 2.0 of the [Ultimate Module Creator for Magento 1.7](https://github.com/tzyganu/UMC1.9).
61 |
62 | Any other ideas and pieces of code are welcomed even encouraged.
63 |
64 | Install
65 | -----
66 |
67 | Manually:
68 | To install this module copy the code from this repo to `app/code` folder of your Magento 2 instance,
69 | If you do this after installing Magento 2 you need to run `php bin/magento setup:upgrade`
70 |
71 | Via composer
72 |
73 | - composer config repositories.sample-module-news git git@github.com:tzyganu/Magento2SampleModule.git
74 | - sudo composer require sample/module-news:dev-master
75 | - php bin/magento setup:upgrade
76 |
77 |
78 | Uninstall
79 | --------
80 |
81 | If you installed it manually:
82 | - remove the folder `app/code/Sample/News`
83 | - drop the tables `sample_news_author_store` and `sample_news_author` (in this order)
84 | - remove the config settings. `DELETE FROM core_config_data WHERE path LIKE 'sample_news/%'`
85 | - remove the module `Sample_News` from `app/etc/config.php`
86 | - remove the module `Sample_News` from table `setup_module`: `DELETE FROM setup_module WHERE module='Sample_News'`
87 |
88 | If you installed it via composer:
89 | - run this in console `bin/magento module:uninstall -r Sample_News`. You might have some problems while uninstalling. See more [details here](http://magento.stackexchange.com/q/123544/146):
90 |
--------------------------------------------------------------------------------
/Setup/Uninstall.php:
--------------------------------------------------------------------------------
1 | collectionFactory = $collectionFactory;
52 | $this->configResource = $configResource;
53 | }
54 |
55 | /**
56 | * {@inheritdoc}
57 | * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
58 | * @SuppressWarnings(PHPMD.Generic.CodeAnalysis.UnusedFunctionParameter)
59 | */
60 | // @codingStandardsIgnoreStart
61 | public function uninstall(SchemaSetupInterface $setup, ModuleContextInterface $context)
62 | // @codingStandardsIgnoreEnd
63 | {
64 | //remove tables
65 | if ($setup->tableExists('sample_news_author_store')) {
66 | $setup->getConnection()->dropTable('sample_news_author_store');
67 | }
68 | if ($setup->tableExists('sample_news_author')) {
69 | $setup->getConnection()->dropTable('sample_news_author');
70 | }
71 | //remove config settings if any
72 | $collection = $this->collectionFactory->create()
73 | ->addPathFilter('sample_news');
74 | foreach ($collection as $config) {
75 | $this->deleteConfig($config);
76 | }
77 | }
78 |
79 | /**
80 | * @param AbstractModel $config
81 | * @throws \Exception
82 | */
83 | protected function deleteConfig(AbstractModel $config)
84 | {
85 | $this->configResource->delete($config);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Test/Unit/Model/Author/DataProviderTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(PoolInterface::class)
40 | ->disableOriginalConstructor()
41 | ->getMock();
42 | /** @var \PHPUnit_Framework_MockObject_MockObject|ModifierInterface $modifierMock */
43 | $modifierMock = $this->getMockBuilder(ModifierInterface::class)
44 | ->disableOriginalConstructor()
45 | ->getMock();
46 | $modifierMock->method('modifyMeta')->willReturn($this->getDummyMeta());
47 | $modifierMock->method('modifyData')->willReturn($this->getDummyData());
48 | $poolMock->method('getModifiersInstances')->willReturn([$modifierMock]);
49 |
50 | /** @var ModifierInterface|CollectionFactory $collectionFactoryMock */
51 | $collectionFactoryMock = $this->getMockBuilder(CollectionFactory::class)
52 | ->disableOriginalConstructor()
53 | ->getMock();
54 |
55 | $this->dataProvider = new DataProvider(
56 | 'dummy',
57 | 'dummy_id',
58 | 'dummy_id',
59 | $collectionFactoryMock,
60 | $poolMock,
61 | [],
62 | []
63 | );
64 | }
65 |
66 | /**
67 | * @return array
68 | */
69 | protected function getDummyMeta()
70 | {
71 | return ['dummy_meta_key'=>'dummy_meta_value'];
72 | }
73 |
74 | /**
75 | * @return array
76 | */
77 | protected function getDummyData()
78 | {
79 | return ['dummy_data_key'=>'dummy_data_value'];
80 | }
81 |
82 | /**
83 | * tests DataProvider::prepareMeta()
84 | */
85 | public function testPrepareMeta()
86 | {
87 | $this->assertEquals($this->getDummyMeta(), $this->dataProvider->prepareMeta([]));
88 | }
89 |
90 | /**
91 | * tests DataProvider::getData()
92 | */
93 | public function testGetData()
94 | {
95 | $this->assertEquals($this->getDummyData(), $this->dataProvider->getData());
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/Test/Unit/Model/Author/RssTest.php:
--------------------------------------------------------------------------------
1 | urlMockBuilder = $this->getMockBuilder(UrlInterface::class)
55 | ->disableOriginalConstructor()
56 | ->getMock();
57 | $this->urlMockBuilder
58 | ->expects($this->any())
59 | ->method('getUrl')
60 | ->willReturnMap(
61 | [
62 | [
63 | 'sample_news/author/rss',
64 | [
65 | 'store' => self::STORE_ID
66 | ],
67 | 'some/url/here'
68 | ]
69 | ]
70 | );
71 | $this->scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class)
72 | ->disableOriginalConstructor()
73 | ->getMock();
74 | $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
75 | ->disableOriginalConstructor()
76 | ->getMock();
77 |
78 | $storeMock = $this->getMockBuilder(StoreInterface::class)
79 | ->disableOriginalConstructor()
80 | ->getMock();
81 | $storeMock->expects($this->any())->method('getId')->willReturn(self::STORE_ID);
82 | $this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock);
83 |
84 | $this->rss = new Rss(
85 | $this->urlMockBuilder,
86 | $this->scopeConfigMock,
87 | $this->storeManagerMock
88 | );
89 | }
90 |
91 | /**
92 | * @test \Sample\News\Model\Author\Rss::isRssEnabled()
93 | *
94 | * with global rss setting disabled
95 | * and author rss disabled
96 | */
97 | public function testIsRssEnabledGlobalFalseAuthorFalse()
98 | {
99 | $this->scopeConfigMock->expects($this->any())
100 | ->method('getValue')
101 | ->willReturnMap(
102 | [
103 | [
104 | 'rss/config/active',
105 | ScopeInterface::SCOPE_STORE,
106 | null,
107 | false
108 | ],
109 | [
110 | 'sample_news/author/rss',
111 | ScopeInterface::SCOPE_STORE,
112 | null,
113 | false
114 | ],
115 | ]
116 | );
117 | $this->assertFalse($this->rss->isRssEnabled());
118 | }
119 |
120 | /**
121 | * @test \Sample\News\Model\Author\Rss::isRssEnabled()
122 | *
123 | * with global rss setting enabled
124 | * and author rss disabled
125 | */
126 | public function testIsRssEnabledGlobalTrueAuthorFalse()
127 | {
128 | $this->scopeConfigMock->expects($this->any())
129 | ->method('getValue')
130 | ->willReturnMap(
131 | [
132 | [
133 | 'rss/config/active',
134 | ScopeInterface::SCOPE_STORE,
135 | null,
136 | true
137 | ],
138 | [
139 | 'sample_news/author/rss',
140 | ScopeInterface::SCOPE_STORE,
141 | null,
142 | false
143 | ],
144 | ]
145 | );
146 | $this->assertFalse($this->rss->isRssEnabled());
147 | }
148 |
149 | /**
150 | * @test \Sample\News\Model\Author\Rss::isRssEnabled()
151 | *
152 | * with global rss setting disabled
153 | * and author rss enabled
154 | */
155 | public function testIsRssEnabledGlobalFalseAuthorTrue()
156 | {
157 | $this->scopeConfigMock->expects($this->any())
158 | ->method('getValue')
159 | ->willReturnMap(
160 | [
161 | [
162 | 'rss/config/active',
163 | ScopeInterface::SCOPE_STORE,
164 | null,
165 | false
166 | ],
167 | [
168 | 'sample_news/author/rss',
169 | ScopeInterface::SCOPE_STORE,
170 | null,
171 | true
172 | ],
173 | ]
174 | );
175 | $this->assertFalse($this->rss->isRssEnabled());
176 | }
177 |
178 | /**
179 | * @test \Sample\News\Model\Author\Rss::isRssEnabled()
180 | *
181 | * with global rss setting enabled
182 | * and author rss enabled
183 | */
184 | public function testIsRssEnabledGlobalTrueAuthorTrue()
185 | {
186 | $this->scopeConfigMock->expects($this->any())
187 | ->method('getValue')
188 | ->willReturnMap(
189 | [
190 | [
191 | 'rss/config/active',
192 | ScopeInterface::SCOPE_STORE,
193 | null,
194 | true
195 | ],
196 | [
197 | 'sample_news/author/rss',
198 | ScopeInterface::SCOPE_STORE,
199 | null,
200 | true
201 | ],
202 | ]
203 | );
204 | $this->assertTrue($this->rss->isRssEnabled());
205 | }
206 |
207 | /**
208 | * @test \Sample\News\Model\Author\Rss::isRssEnabled()
209 | */
210 | public function testGetRssLink()
211 | {
212 | $this->assertEquals('some/url/here', $this->rss->getRssLink());
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/Test/Unit/Model/Source/CountryTest.php:
--------------------------------------------------------------------------------
1 | objectManager = new ObjectManager($this);
52 | $this->countryCollectionFactoryMock = $this->getMockBuilder(CollectionFactory::class)
53 | ->disableOriginalConstructor()
54 | ->getMock();
55 | $countryMock = $this->getMockBuilder(CountryModel::class)
56 | ->disableOriginalConstructor()
57 | ->getMock();
58 | $this->countryCollection = $this->objectManager->getCollectionMock(Collection::class, [$countryMock]);
59 | $this->countryCollectionFactoryMock->method('create')->willReturn($this->countryCollection);
60 |
61 | $this->countryList = new Country($this->countryCollectionFactoryMock);
62 | }
63 |
64 | /**
65 | * @test \Sample\News\Model\Source\Country::toOptionArray result is memoized
66 | */
67 | public function testMemoizedOptionArray()
68 | {
69 | $this->countryCollection->method('toOptionArray')->willReturn(['baz' => 'qux']);
70 | $this->countryCollection->expects($this->once())->method('toOptionArray');
71 | $result1 = $this->countryList->toOptionArray();
72 | $result2 = $this->countryList->toOptionArray();
73 | $this->assertSame($result1, $result2);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Test/Unit/Model/UploaderPoolTest.php:
--------------------------------------------------------------------------------
1 | objectManager = new ObjectManager($this);
40 | /** @var \PHPUnit_Framework_MockObject_MockObject|ObjectManagerInterface $objectManagerMock */
41 | $objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class)
42 | ->disableOriginalConstructor()
43 | ->getMock();
44 | /** @var \PHPUnit_Framework_MockObject_MockObject|Uploader $uploaderMock */
45 | $uploaderMock = $this->getMockBuilder(Uploader::class)
46 | ->disableOriginalConstructor()
47 | ->getMock();
48 | $objectManagerMock->expects($this->any())->method('create')->willReturn($uploaderMock);
49 |
50 | $dataObject = new DataObject();
51 |
52 | $this->uploaderPool = new UploaderPool(
53 | $objectManagerMock,
54 | [
55 | 'uploader1' => Uploader::class,
56 | 'uploader2' => $uploaderMock,
57 | 'uploader3' => $dataObject
58 | ]
59 | );
60 | }
61 |
62 | /**
63 | * @test \Sample\News\Model\UploaderPool::getUploader() when uploader is not found
64 | * @throws \Exception
65 | */
66 | public function testGetUploaderNotFound()
67 | {
68 | $type = 'test';
69 | $this->setExpectedException('\Exception', "Uploader not found for type: ".$type);
70 | $this->uploaderPool->getUploader($type);
71 | }
72 |
73 | /**
74 | * @test \Sample\News\Model\UploaderPool::getUploader() when instantiation is needed
75 | * @throws \Exception
76 | */
77 | public function testGetUploaderInstantiationNeeded()
78 | {
79 | $type = 'uploader1';
80 | $this->assertInstanceOf(Uploader::class, $this->uploaderPool->getUploader($type));
81 | }
82 |
83 | /**
84 | * @test \Sample\News\Model\UploaderPool::getUploader() when instantiation is not needed
85 | * @throws \Exception
86 | */
87 | public function testGetUploaderInstantiationNotNeeded()
88 | {
89 | $type = 'uploader2';
90 | $this->assertInstanceOf(Uploader::class, $this->uploaderPool->getUploader($type));
91 | }
92 |
93 | /**
94 | * @test \Sample\News\Model\UploaderPool::getUploader() with wrong type returned
95 | * @throws \Exception
96 | */
97 | public function testGetUploaderWrongType()
98 | {
99 | $type = 'uploader3';
100 | $this->setExpectedException('\Exception', "Uploader for type {$type} not instance of ".Uploader::class);
101 | $this->uploaderPool->getUploader($type);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Test/Unit/Model/UploaderTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(Database::class)
59 | ->disableOriginalConstructor()
60 | ->getMock();
61 | $coreFileStorageDatabaseMock->method('copyFile')->willReturn($coreFileStorageDatabaseMock);
62 | /** @var \PHPUnit_Framework_MockObject_MockObject|Filesystem $fileSystemMock */
63 | $fileSystemMock = $this->getMockBuilder(Filesystem::class)
64 | ->disableOriginalConstructor()
65 | ->getMock();
66 | /** @var \PHPUnit_Framework_MockObject_MockObject|WriteInterface $writeInterfaceMock */
67 | $writeInterfaceMock = $this->getMockBuilder(WriteInterface::class)
68 | ->disableOriginalConstructor()
69 | ->getMock();
70 | $writeInterfaceMock->method('renameFile')->willReturn($writeInterfaceMock);
71 | $fileSystemMock->method('getDirectoryWrite')->willReturn($writeInterfaceMock);
72 | /** @var \PHPUnit_Framework_MockObject_MockObject|UploaderFactory $uploaderFactoryMock */
73 | $uploaderFactoryMock = $this->getMockBuilder(UploaderFactory::class)
74 | ->disableOriginalConstructor()
75 | ->getMock();
76 | /** @var \PHPUnit_Framework_MockObject_MockObject|Uploader $uploaderMock */
77 | $uploaderMock = $this->getMockBuilder(Uploader::class)
78 | ->disableOriginalConstructor()
79 | ->getMock();
80 | $uploaderMock->method('save')->willReturn([
81 | 'file' => 'file.ext',
82 | 'tmp_name' => 'file.ext',
83 | 'path' => 'path'
84 | ]);
85 |
86 | $uploaderFactoryMock->method('create')->willReturn($uploaderMock);
87 | /** @var \PHPUnit_Framework_MockObject_MockObject|StoreManagerInterface $storeManagerMock */
88 | $storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
89 | ->disableOriginalConstructor()
90 | ->getMock();
91 | /** @var \PHPUnit_Framework_MockObject_MockObject|Store $storeMock */
92 | $storeMock = $this->getMockBuilder(Store::class)
93 | ->disableOriginalConstructor()
94 | ->getMock();
95 | $storeMock->method('getBaseUrl')->willReturn('http://example.com/');
96 | $storeManagerMock->method('getStore')->willReturn($storeMock);
97 | /** @var \PHPUnit_Framework_MockObject_MockObject|LoggerInterface $loggerMock */
98 | $loggerMock = $this->getMockBuilder(LoggerInterface::class)
99 | ->disableOriginalConstructor()
100 | ->getMock();
101 |
102 | $this->uploader = new UploaderModel(
103 | $coreFileStorageDatabaseMock,
104 | $fileSystemMock,
105 | $uploaderFactoryMock,
106 | $storeManagerMock,
107 | $loggerMock,
108 | [],
109 | self::BASE_TMP_PATH,
110 | self::BASE_PATH
111 | );
112 | }
113 |
114 | /**
115 | * @test Sample\News\Model\Uploader::getBaseTmpPath()
116 | */
117 | public function testGetBaseTmpPath()
118 | {
119 | $this->assertEquals(self::BASE_TMP_PATH, $this->uploader->getBaseTmpPath());
120 | }
121 |
122 | /**
123 | * @test Sample\News\Model\Uploader::getBasePath
124 | */
125 | public function testGetBasePath()
126 | {
127 | $this->assertEquals(self::BASE_PATH, $this->uploader->getBasePath());
128 | }
129 |
130 | /**
131 | * @test Sample\News\Model\Uploader::getAllowedExtensions
132 | */
133 | public function testGetAllowedExtensions()
134 | {
135 | $this->assertEquals([], $this->uploader->getAllowedExtensions());
136 | $this->uploader->setAllowedExtensions(['ext']);
137 | $this->assertEquals(['ext'], $this->uploader->getAllowedExtensions());
138 | }
139 |
140 | /**
141 | * @test Sample\News\Model\Uploader::getFilePath
142 | */
143 | public function testGetFilePath()
144 | {
145 | $this->assertEquals('path/here/file.ext', $this->uploader->getFilePath('path/here/', '/file.ext'));
146 | $this->assertEquals('path/here/file.ext', $this->uploader->getFilePath('path/here', '/file.ext'));
147 | $this->assertEquals('path/here/file.ext', $this->uploader->getFilePath('path/here/', 'file.ext'));
148 | $this->assertEquals('path/here/file.ext', $this->uploader->getFilePath('path/here', 'file.ext'));
149 | }
150 |
151 | /**
152 | * @test Sample\News\Model\Uploader::moveFileFromTmp
153 | */
154 | public function testMoveFileFromTmp()
155 | {
156 | $this->assertEquals('dummy', $this->uploader->moveFileFromTmp('dummy'));
157 | }
158 |
159 | /**
160 | * @test Sample\News\Model\Uploader::saveFileToTmpDir
161 | */
162 | public function testSaveFileToTmpDir()
163 | {
164 | $expected = [
165 | 'file' => 'file.ext',
166 | 'tmp_name' => 'file.ext',
167 | 'path' => 'path',
168 | 'url' => 'http://example.com/base/tmp/path/file.ext'
169 | ];
170 | $this->assertEquals($expected, $this->uploader->saveFileToTmpDir('dummy'));
171 | }
172 |
173 | /**
174 | * @test Sample\News\Model\Uploader::uploadFileAndGetName
175 | */
176 | public function testUploadFileAndGetName()
177 | {
178 | $data = [];
179 | $this->assertEmpty($this->uploader->uploadFileAndGetName('dummy', $data));
180 | $data = [
181 | 'dummy' => [
182 | 'delete' => 1,
183 | 'dummy1' => [
184 | 'data1', 'data2'
185 | ]
186 | ]
187 | ];
188 | $this->assertEmpty($this->uploader->uploadFileAndGetName('dummy', $data));
189 | $data = [
190 | 'dummy' => [
191 | [
192 | 'name' => 'file.ext',
193 | 'tmp_name' => 'dummy',
194 | 'file' => 'file.ext'
195 | ]
196 | ]
197 | ];
198 | $this->assertEquals('file.ext', $this->uploader->uploadFileAndGetName('dummy', $data));
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/Test/Unit/Ui/Component/Listing/Column/AuthorActionsTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(UrlInterface::class)
36 | ->disableOriginalConstructor()
37 | ->getMock();
38 | /** @var \PHPUnit_Framework_MockObject_MockObject|ContextInterface $contextMock */
39 | $contextMock = $this->getMockBuilder(ContextInterface::class)
40 | ->getMockForAbstractClass();
41 | /** @var \PHPUnit_Framework_MockObject_MockObject|Processor $processor */
42 | $processor = $this->getMockBuilder(Processor::class)
43 | ->disableOriginalConstructor()
44 | ->getMock();
45 | $contextMock->expects($this->any())->method('getProcessor')->willReturn($processor);
46 | /** @var \PHPUnit_Framework_MockObject_MockObject|UiComponentFactory $uiComponentFactoryMock */
47 | $uiComponentFactoryMock = $this->getMockBuilder(UiComponentFactory::class)
48 | ->disableOriginalConstructor()
49 | ->getMock();
50 |
51 | /** @var \Sample\News\Ui\Component\Listing\Column\AuthorActions $actions */
52 | $actions = new AuthorActions($contextMock, $uiComponentFactoryMock, $urlBuilderMock);
53 | // Define test input and expectations
54 | $items = [
55 | 'data' => [
56 | 'items' => [
57 | [
58 | 'author_id' => $authorId
59 | ]
60 | ]
61 | ]
62 | ];
63 | $name = 'item_name';
64 | $expectedItems = [
65 | [
66 | 'author_id' => $authorId,
67 | $name => [
68 | 'edit' => [
69 | 'href' => 'some/url/edit',
70 | 'label' => __('Edit'),
71 | ],
72 | 'delete' => [
73 | 'href' => 'some/url/delete',
74 | 'label' => __('Delete'),
75 | 'confirm' => [
76 | 'title' => __('Delete "${ $.$data.name }"'),
77 | 'message' => __('Are you sure you wan\'t to delete the Author "${ $.$data.name }" ?')
78 | ],
79 | ]
80 | ],
81 | ]
82 | ];
83 |
84 | // Configure mocks and object data
85 | $urlBuilderMock->expects($this->any())
86 | ->method('getUrl')
87 | ->willReturnMap(
88 | [
89 | [
90 | AuthorActions::URL_PATH_EDIT,
91 | [
92 | 'author_id' => $authorId
93 | ],
94 | 'some/url/edit',
95 | ],
96 | [
97 | AuthorActions::URL_PATH_DELETE,
98 | [
99 | 'author_id' => $authorId
100 | ],
101 | 'some/url/delete',
102 | ],
103 | ]
104 | );
105 |
106 | $actions->setName($name);
107 | $items = $actions->prepareDataSource($items);
108 | // Run test
109 | $this->assertEquals($expectedItems, $items['data']['items']);
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Test/Unit/Ui/Component/Listing/Column/AvatarTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(ContextInterface::class)
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 | /** @var \PHPUnit_Framework_MockObject_MockObject|UiComponentFactory $uiComponentFactoryMock */
41 | $uiComponentFactoryMock = $this->getMockBuilder(UiComponentFactory::class)
42 | ->disableOriginalConstructor()
43 | ->getMock();
44 | /** @var \PHPUnit_Framework_MockObject_MockObject|UrlInterface $urlBuilderMock */
45 | $urlBuilderMock = $this->getMockBuilder(UrlInterface::class)
46 | ->disableOriginalConstructor()
47 | ->getMock();
48 | /** @var \PHPUnit_Framework_MockObject_MockObject|Uploader $uploaderMock */
49 | $uploaderMock = $this->getMockBuilder(Uploader::class)
50 | ->disableOriginalConstructor()
51 | ->getMock();
52 | $uploaderMock->method('getBasePath')->willReturn('/base/path');
53 | $uploaderMock->method('getBaseUrl')->willReturn('http://example.com');
54 | $processor = $this->getMockBuilder(Processor::class)
55 | ->disableOriginalConstructor()
56 | ->getMock();
57 | $contextMock->expects($this->any())->method('getProcessor')->willReturn($processor);
58 |
59 | /** @var \Sample\News\Ui\Component\Listing\Column\Avatar $avatarModel */
60 | $avatarModel = new Avatar($contextMock, $uiComponentFactoryMock, $urlBuilderMock, $uploaderMock, [], []);
61 | $authorId = 1;
62 | $urlBuilderMock
63 | ->method('getUrl')
64 | ->willReturnMap(
65 | [
66 | [
67 | AuthorActions::URL_PATH_EDIT,
68 | [
69 | 'author_id' => $authorId
70 | ],
71 | 'some/url/here',
72 | ],
73 | ]
74 | );
75 | $fieldName = 'avatar';
76 | $avatarModel->setName($fieldName);
77 | $items = [
78 | 'data' => [
79 | 'items' => [
80 | [
81 | 'author_id' => $authorId,
82 | $fieldName => '/some/image.jpg',
83 | 'name' => 'test name',
84 | ]
85 | ]
86 | ]
87 | ];
88 | $expectedResult = [
89 | 'data' => [
90 | 'items' => [
91 | [
92 | 'author_id' => $authorId,
93 | $fieldName => '/some/image.jpg',
94 | 'name' => 'test name',
95 | $fieldName . '_src' => 'http://example.com/base/path/some/image.jpg',
96 | $fieldName . '_alt' => 'test name',
97 | $fieldName . '_link' => 'some/url/here',
98 | $fieldName . '_orig_src' => 'http://example.com/base/path/some/image.jpg'
99 | ]
100 | ]
101 | ]
102 | ];
103 | $items = $avatarModel->prepareDataSource($items);
104 | $this->assertEquals($expectedResult, $items);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Test/Unit/Ui/Component/Listing/Column/Store/OptionsTest.php:
--------------------------------------------------------------------------------
1 | systemStoreMock = $this->getMockBuilder(Store::class)
66 | ->disableOriginalConstructor()
67 | ->getMock();
68 | $this->websiteMock = $this->getMock(
69 | Website::class,
70 | ['getId', 'getName'],
71 | [],
72 | '',
73 | false
74 | );
75 | $this->groupMock = $this->getMock(Group::class, [], [], '', false);
76 | $this->storeMock = $this->getMock(StoreModel::class, [], [], '', false);
77 | $this->escaperMock = $this->getMock(Escaper::class, [], [], '', false);
78 | $this->options = new Options($this->systemStoreMock, $this->escaperMock);
79 | }
80 |
81 | /**
82 | * @test Sample\News\Ui\Component\Listing\Column\Store\Options::toOptionArray()
83 | */
84 | public function testToOptionArray()
85 | {
86 | $websiteCollection = [$this->websiteMock];
87 | $groupCollection = [$this->groupMock];
88 | $storeCollection = [$this->storeMock];
89 |
90 | $expectedOptions = [
91 | [
92 | 'label' => __('All Store Views'),
93 | 'value' => '0'
94 | ],
95 | [
96 | 'label' => 'Main Website',
97 | 'value' => [
98 | [
99 | 'label' => ' Main Website Store',
100 | 'value' => [
101 | [
102 | 'label' => ' Default Store View',
103 | 'value' => '1'
104 | ]
105 | ]
106 | ]
107 | ]
108 | ]
109 | ];
110 |
111 | $this->systemStoreMock->expects($this->once())->method('getWebsiteCollection')->willReturn($websiteCollection);
112 | $this->systemStoreMock->expects($this->once())->method('getGroupCollection')->willReturn($groupCollection);
113 | $this->systemStoreMock->expects($this->once())->method('getStoreCollection')->willReturn($storeCollection);
114 |
115 | $this->websiteMock->expects($this->atLeastOnce())->method('getId')->willReturn('1');
116 | $this->websiteMock->expects($this->any())->method('getName')->willReturn('Main Website');
117 |
118 | $this->groupMock->expects($this->atLeastOnce())->method('getWebsiteId')->willReturn('1');
119 | $this->groupMock->expects($this->atLeastOnce())->method('getId')->willReturn('1');
120 | $this->groupMock->expects($this->atLeastOnce())->method('getName')->willReturn('Main Website Store');
121 |
122 | $this->storeMock->expects($this->atLeastOnce())->method('getGroupId')->willReturn('1');
123 | $this->storeMock->expects($this->atLeastOnce())->method('getName')->willReturn('Default Store View');
124 | $this->storeMock->expects($this->atLeastOnce())->method('getId')->willReturn('1');
125 |
126 | $this->escaperMock->expects($this->atLeastOnce())->method('escapeHtml')->willReturnMap(
127 | [
128 | ['Default Store View', null, 'Default Store View'],
129 | ['Main Website Store', null, 'Main Website Store'],
130 | ['Main Website', null, 'Main Website']
131 | ]
132 | );
133 |
134 | $this->assertEquals($expectedOptions, $this->options->toOptionArray());
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Test/Unit/Ui/DataProvider/Author/Form/Modifier/AuthorDataTest.php:
--------------------------------------------------------------------------------
1 | objectManager = new ObjectManager($this);
47 | $this->collectionFactoryMock = $this->getMockBuilder(CollectionFactory::class)
48 | ->disableOriginalConstructor()
49 | ->getMock();
50 |
51 | $authorData = [
52 | 'author_id' => 1,
53 | 'name' => 'test',
54 | 'avatar' => '/some/image.jpg',
55 | 'resume' => '/some/file.txt'
56 | ];
57 |
58 | $mockAuthor = $this->getMock(
59 | Author::class,
60 | [],
61 | [],
62 | '',
63 | false
64 | );
65 | $mockAuthor->method('getData')->willReturn($authorData);
66 | $mockAuthor->method('getId')->willReturn($authorData['author_id']);
67 | $mockAuthor->method('getAvatarUrl')->willReturn('http://example.com'.$authorData['avatar']);
68 | $mockAuthor->method('getAvatar')->willReturn($authorData['avatar']);
69 | $mockAuthor->method('getResumeUrl')->willReturn('http://example.com'.$authorData['resume']);
70 | $mockAuthor->method('getResume')->willReturn($authorData['resume']);
71 |
72 | $collectionMock = $this->objectManager->getCollectionMock(
73 | Collection::class,
74 | [$mockAuthor]
75 | );
76 | $collectionMock->method('getItems')->willReturn([$mockAuthor]);
77 | $this->collectionFactoryMock->method('create')->willReturn($collectionMock);
78 | $this->authorDataModifier = new AuthorData($this->collectionFactoryMock);
79 | }
80 |
81 | /**
82 | * @test Sample\News\Ui\DataProvider\Author\Form\Modifier\AuthorData::AuthorData::modfyMeta()
83 | */
84 | public function testModifyMeta()
85 | {
86 | $this->assertEquals(
87 | $this->getSampleData(),
88 | $this->authorDataModifier->modifyMeta($this->getSampleData())
89 | );
90 | }
91 |
92 | /**
93 | * @test modifyData method
94 | */
95 | public function testModifiyData()
96 | {
97 | $expected = [
98 | 'key' => 'value',
99 | '1' => [
100 | 'author_id' => 1,
101 | 'name' => 'test',
102 | 'avatar' => [
103 | 0 => [
104 | 'name' => '/some/image.jpg',
105 | 'url' => 'http://example.com/some/image.jpg'
106 | ]
107 | ],
108 | 'resume' => [
109 | 0 => [
110 | 'name' => '/some/file.txt',
111 | 'url' => 'http://example.com/some/file.txt'
112 | ]
113 | ]
114 | ]
115 | ];
116 | $data = $this->authorDataModifier->modifyData($this->getSampleData());
117 | $this->assertEquals($expected, $data);
118 | }
119 |
120 | /**
121 | * @return array
122 | */
123 | protected function getSampleData()
124 | {
125 | return ['key' => 'value'];
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/Ui/Component/Listing/Column/AuthorActions.php:
--------------------------------------------------------------------------------
1 | _urlBuilder = $urlBuilder;
65 | parent::__construct($context, $uiComponentFactory, $components, $data);
66 | }
67 |
68 |
69 | /**
70 | * Prepare Data Source
71 | *
72 | * @param array $dataSource
73 | * @return array
74 | */
75 | public function prepareDataSource(array $dataSource)
76 | {
77 | if (isset($dataSource['data']['items'])) {
78 | foreach ($dataSource['data']['items'] as & $item) {
79 | if (isset($item['author_id'])) {
80 | $item[$this->getData('name')] = [
81 | 'edit' => [
82 | 'href' => $this->_urlBuilder->getUrl(
83 | static::URL_PATH_EDIT,
84 | [
85 | 'author_id' => $item['author_id']
86 | ]
87 | ),
88 | 'label' => __('Edit')
89 | ],
90 | 'delete' => [
91 | 'href' => $this->_urlBuilder->getUrl(
92 | static::URL_PATH_DELETE,
93 | [
94 | 'author_id' => $item['author_id']
95 | ]
96 | ),
97 | 'label' => __('Delete'),
98 | 'confirm' => [
99 | 'title' => __('Delete "${ $.$data.name }"'),
100 | 'message' => __('Are you sure you wan\'t to delete the Author "${ $.$data.name }" ?')
101 | ]
102 | ]
103 | ];
104 | }
105 | }
106 | }
107 | return $dataSource;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Ui/Component/Listing/Column/Avatar.php:
--------------------------------------------------------------------------------
1 | imageModel = $imageModel;
45 | $this->urlBuilder = $urlBuilder;
46 | parent::__construct($context, $uiComponentFactory, $components, $data);
47 | }
48 |
49 | /**
50 | * Prepare Data Source
51 | *
52 | * @param array $dataSource
53 | * @return array
54 | */
55 | public function prepareDataSource(array $dataSource)
56 | {
57 | if(isset($dataSource['data']['items'])) {
58 | $fieldName = $this->getData('name');
59 | foreach($dataSource['data']['items'] as & $item) {
60 | $url = '';
61 | if($item[$fieldName] != '') {
62 | $url = $this->imageModel->getBaseUrl().$this->imageModel->getBasePath().$item[$fieldName];
63 | }
64 | $item[$fieldName . '_src'] = $url;
65 | $item[$fieldName . '_alt'] = $this->getAlt($item) ?: '';
66 | $item[$fieldName . '_link'] = $this->urlBuilder->getUrl(
67 | 'sample_news/author/edit',
68 | ['author_id' => $item['author_id']]
69 | );
70 | $item[$fieldName . '_orig_src'] = $url;
71 | }
72 | }
73 |
74 | return $dataSource;
75 | }
76 |
77 | /**
78 | * @param array $row
79 | *
80 | * @return null|string
81 | */
82 | protected function getAlt($row)
83 | {
84 | $altField = $this->getData('config/altField') ?: self::ALT_FIELD;
85 | return isset($row[$altField]) ? $row[$altField] : null;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Ui/Component/Listing/Column/Store/Options.php:
--------------------------------------------------------------------------------
1 | options !== null) {
37 | return $this->options;
38 | }
39 |
40 | $this->currentOptions['All Store Views']['label'] = __('All Store Views');
41 | $this->currentOptions['All Store Views']['value'] = self::ALL_STORE_VIEWS;
42 |
43 | $this->generateCurrentOptions();
44 |
45 | $this->options = array_values($this->currentOptions);
46 |
47 | return $this->options;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Ui/DataProvider/Author/Form/Modifier/AuthorData.php:
--------------------------------------------------------------------------------
1 | collection = $authorCollectionFactory->create();
38 | }
39 |
40 | /**
41 | * @param array $meta
42 | * @return array
43 | */
44 | public function modifyMeta(array $meta)
45 | {
46 | return $meta;
47 | }
48 |
49 | /**
50 | * @param array $data
51 | * @return array|mixed
52 | * @throws \Magento\Framework\Exception\LocalizedException
53 | */
54 | public function modifyData(array $data)
55 | {
56 | $items = $this->collection->getItems();
57 | /** @var $author \Sample\News\Model\Author */
58 | foreach ($items as $author) {
59 | $_data = $author->getData();
60 | if (isset($_data['avatar'])) {
61 | $avatar = [];
62 | $avatar[0]['name'] = $author->getAvatar();
63 | $avatar[0]['url'] = $author->getAvatarUrl();
64 | $_data['avatar'] = $avatar;
65 | }
66 | if (isset($_data['resume'])) {
67 | $resume = [];
68 | $resume[0]['name'] = $author->getResume();
69 | $resume[0]['url'] = $author->getResumeUrl();
70 | $_data['resume'] = $resume;
71 | }
72 | $author->setData($_data);
73 | $data[$author->getId()] = $_data;
74 | }
75 | return $data;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sample/module-news",
3 | "description": "Magento 2 Sample crud module",
4 | "version": "2.0.0",
5 | "license": "MIT",
6 | "require": {
7 | "php": "~5.6.0|7.0.2|~7.0.6",
8 | "magento/module-backend": "100.1.*",
9 | "magento/module-cms": "101.0.*",
10 | "magento/module-ui": "100.1.*",
11 | "magento/module-store": "100.1.*",
12 | "magento/framework": "100.1.*",
13 | "magento/module-media-storage": "100.1.*",
14 | "magento/module-directory": "100.1.*",
15 | "magento/module-customer": "100.1.*",
16 | "magento/module-rss": "100.1.*"
17 | },
18 | "type": "magento2-module",
19 | "repositories": [
20 | {
21 | "type": "git",
22 | "url": "https://github.com/tzyganu/Magento2SampleModule"
23 | }
24 | ],
25 | "autoload": {
26 | "files": [
27 | "registration.php"
28 | ],
29 | "psr-4": {
30 | "Sample\\News\\": ""
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/etc/adminhtml/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 | -
25 |
- Sample\News\Ui\DataProvider\Author\Form\Modifier\AuthorData
26 | - 10
27 |
28 |
29 |
30 |
31 |
32 |
33 | SampleNewsUiDataProviderAuthorFormModifierPool
34 |
35 |
36 |
37 |
38 | A total of %1 record(s) have been deleted.
39 | An error occurred while deleting record(s).
40 |
41 |
42 |
43 |
44 | A total of %1 authors have been disabled.
45 | An error occurred while disabling authors.
46 |
47 |
48 |
49 |
50 | A total of %1 authors have been enabled.
51 | An error occurred while enabling authors.
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/etc/adminhtml/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
26 |
27 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | sample_news
28 | Sample_News::news
29 |
30 |
31 |
32 |
33 | Magento\Config\Model\Config\Source\Yesno
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 | 1
25 | Authors
26 | Authors Description Here
27 | Authors Keywords Here
28 | authors.html
29 | author
30 | html
31 | 1
32 | 600
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/etc/frontend/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 | -
25 |
- Sample\News\Controller\Router
26 | - false
27 | - 10
28 |
29 |
30 |
31 |
32 |
33 |
34 | Sample\News\Model\Author\Url::URL_PREFIX_CONFIG_PATH
35 | Sample\News\Model\Author\Url::URL_SUFFIX_CONFIG_PATH
36 | Sample\News\Model\Author\Url::LIST_URL_CONFIG_PATH
37 | Sample\News\Model\AuthorFactory
38 | author
39 |
40 |
41 |
42 |
43 |
44 | - SampleNewsRoutingEntityAuthor
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/etc/frontend/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/i18l/en_US.csv:
--------------------------------------------------------------------------------
1 | "A total of %1 authors have been disabled.","A total of %1 authors have been disabled."
2 | "A total of %1 record(s) have been deleted.","A total of %1 record(s) have been deleted."
3 | "A total of %1 authors have been enabled.","A total of %1 authors have been enabled."
4 | "Add New Author","Add New Author"
5 | "All Store Views","All Store Views"
6 | "An error occurred while deleting record(s).","An error occurred while deleting record(s)."
7 | "An error occurred while disabling authors.","An error occurred while disabling authors."
8 | "An error occurred while enabling authors.","An error occurred while enabling authors."
9 | "Are you sure you want to delete selected items?","Are you sure you want to delete selected items?"
10 | "Are you sure you want to delete the Author ""${ $.$data.name }"" ?","Are you sure you want to delete the Author ""${ $.$data.name }"" ?"
11 | "Are you sure you want to do this?","Are you sure you want to do this?"
12 | "Author in Store views","Author in Store views"
13 | "Author Information","Author Information"
14 | Authors,Authors
15 | Avatar,Avatar
16 | "Award 1","Award 1"
17 | "Award 2","Award 2"
18 | "Award 3","Award 3"
19 | Awards,Awards
20 | Back,Back
21 | Biography,Biography
22 | Collaborator,Collaborator
23 | "Could not save the author: %1","Could not save the author: %1"
24 | Country,Country
25 | "Created At","Created At"
26 | "Date of birth","Date of birth"
27 | Delete,Delete
28 | "Delete Author","Delete Author"
29 | "Delete items","Delete items"
30 | "Delete ""${ $.$data.name }""","Delete ""${ $.$data.name }"""
31 | Disable,Disable
32 | DOB,DOB
33 | Edit,Edit
34 | "Edit Author","Edit Author"
35 | Employee,Employee
36 | Enable,Enable
37 | "Enter full name here","Enter full name here"
38 | "File can not be saved to the destination folder.","File can not be saved to the destination folder."
39 | Home,Home
40 | ID,ID
41 | "In RSS","In RSS"
42 | "Is Active","Is Active"
43 | label,label
44 | "Meta Description","Meta Description"
45 | "Meta Keywords","Meta Keywords"
46 | "Meta Title","Meta Title"
47 | Name,Name
48 | "New Author","New Author"
49 | News,News
50 | No,No
51 | "Please correct the data sent.","Please correct the data sent."
52 | "Requested author doesn't exist","Requested author doesn't exist"
53 | Reset,Reset
54 | Resume,Resume
55 | "Save Author","Save Author"
56 | "Save and Continue Edit","Save and Continue Edit"
57 | "Show In RSS","Show In RSS"
58 | "Something went wrong while getting the avatar url.","Something went wrong while getting the avatar url."
59 | "Something went wrong while getting the resume url.","Something went wrong while getting the resume url."
60 | "Something went wrong while saving the author.","Something went wrong while saving the author."
61 | "Something went wrong while saving the file(s).","Something went wrong while saving the file(s)."
62 | "Store View","Store View"
63 | "Subscribe to RSS Feed","Subscribe to RSS Feed"
64 | "There are no authors at this moment","There are no authors at this moment"
65 | "The author has been deleted.","The author has been deleted."
66 | "The author no longer exists.","The author no longer exists."
67 | "There was a problem deleting the author","There was a problem deleting the author"
68 | "There was a problem saving the author","There was a problem saving the author"
69 | Type,Type
70 | "Unable to remove author %1","Unable to remove author %1"
71 | "Updated At","Updated At"
72 | "URL Key","URL Key"
73 | "Url Key","Url Key"
74 | "We can't find a author to delete.","We can't find a author to delete."
75 | Yes,Yes
76 | "You saved the author","You saved the author"
77 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/view/adminhtml/layout/sample_news_author_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
24 |
25 |
26 | Sample_News::authors
27 |
28 |
29 |
30 |
31 | complex
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/view/adminhtml/web/template/file-preview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/view/adminhtml/web/template/image-preview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 | x
28 |
29 |
30 |
--------------------------------------------------------------------------------
/view/base/web/images/author/placeholder/avatar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzyganu/Magento2SampleModule/1047ae6ab3b5f607e3896521ff6b7a7ab47eb41a/view/base/web/images/author/placeholder/avatar.jpg
--------------------------------------------------------------------------------
/view/frontend/layout/sample_news_author_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/view/frontend/layout/sample_news_author_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/view/frontend/templates/author/list.phtml:
--------------------------------------------------------------------------------
1 |
19 |
20 | getAuthors(); ?>
21 |
22 | getSize() > 0) :?>
23 |
getPagerHtml(); ?>
24 |
34 |
getPagerHtml(); ?>
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/view/frontend/templates/author/view.phtml:
--------------------------------------------------------------------------------
1 |
19 |
20 | getCurrentAuthor();?>
21 |
22 |
23 | : getName();?>
24 |
25 | getAttributeText('type')) :?>
26 |
27 | :
28 |
29 |
30 | getProcessedBiography()) :?>
31 |
32 | :
33 |
34 |
35 | getDob()) :?>
36 |
37 | : formatDate($dob, \IntlDateFormatter::LONG);?>
38 |
39 |
40 | getAttributeText('awards')) :?>
41 |
42 | :
43 |
44 |
45 | getAttributeText('country')) :?>
46 |
47 | :
48 |
49 |
50 | getResume()) :?>
51 |
54 |
55 |
56 | getImage($_author, 'author_view', ['width' => 100, 'height' => 100, 'type' => 'avatar'])->toHtml(); ?>
57 |
58 |
59 |
--------------------------------------------------------------------------------
/view/frontend/templates/image.phtml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
getCustomAttributes(); ?>
23 | src="getImageUrl(); ?>"
24 | width="getWidth(); ?>"
25 | height="getHeight(); ?>"
26 | alt="stripTags($block->getLabel(), null, true); ?>" />
27 |
--------------------------------------------------------------------------------
/view/frontend/templates/image_with_borders.phtml:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
23 |
25 |
getCustomAttributes(); ?>
27 | src="getImageUrl(); ?>"
28 | width="getResizedImageWidth(); ?>"
29 | height="getResizedImageHeight(); ?>"
30 | alt="stripTags($block->getLabel(), null, true); ?>"/>
31 |
32 |
--------------------------------------------------------------------------------
/view/frontend/templates/rss/link.phtml:
--------------------------------------------------------------------------------
1 |
19 |
20 | isRssEnabled()) : ?>
21 |
24 |
25 |
--------------------------------------------------------------------------------