Skip to content

Commit 360e381

Browse files
committed
MAGETWO-57989: Unable to create custom image attribute in category
2 parents 63bd96e + 06034a1 commit 360e381

File tree

10 files changed

+783
-144
lines changed

10 files changed

+783
-144
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ protected function _isAllowed()
5050
*/
5151
public function execute()
5252
{
53+
$imageId = $this->_request->getParam('param_name', 'image');
54+
5355
try {
54-
$result = $this->imageUploader->saveFileToTmpDir('image');
56+
$result = $this->imageUploader->saveFileToTmpDir($imageId);
5557

5658
$result['cookie'] = [
5759
'name' => $this->_getSession()->getName(),

app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Catalog\Controller\Adminhtml\Category;
77

88
use Magento\Store\Model\StoreManagerInterface;
9+
use Magento\Catalog\Api\Data\CategoryAttributeInterface;
910

1011
/**
1112
* Class Save
@@ -48,6 +49,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
4849
*/
4950
private $storeManager;
5051

52+
/**
53+
* @var \Magento\Eav\Model\Config
54+
*/
55+
private $eavConfig;
56+
5157
/**
5258
* Constructor
5359
*
@@ -56,43 +62,23 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
5662
* @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
5763
* @param \Magento\Framework\View\LayoutFactory $layoutFactory
5864
* @param StoreManagerInterface $storeManager
65+
* @param \Magento\Eav\Model\Config $eavConfig
5966
*/
6067
public function __construct(
6168
\Magento\Backend\App\Action\Context $context,
6269
\Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
6370
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
6471
\Magento\Framework\View\LayoutFactory $layoutFactory,
65-
StoreManagerInterface $storeManager
72+
StoreManagerInterface $storeManager,
73+
\Magento\Eav\Model\Config $eavConfig = null
6674
) {
6775
parent::__construct($context);
6876
$this->resultRawFactory = $resultRawFactory;
6977
$this->resultJsonFactory = $resultJsonFactory;
7078
$this->layoutFactory = $layoutFactory;
7179
$this->storeManager = $storeManager;
72-
}
73-
74-
/**
75-
* Filter category data
76-
*
77-
* @param array $rawData
78-
* @return array
79-
*/
80-
protected function _filterCategoryPostData(array $rawData)
81-
{
82-
$data = $rawData;
83-
// @todo It is a workaround to prevent saving this data in category model and it has to be refactored in future
84-
if (isset($data['image']) && is_array($data['image'])) {
85-
if (!empty($data['image']['delete'])) {
86-
$data['image'] = null;
87-
} else {
88-
if (isset($data['image'][0]['name']) && isset($data['image'][0]['tmp_name'])) {
89-
$data['image'] = $data['image'][0]['name'];
90-
} else {
91-
unset($data['image']);
92-
}
93-
}
94-
}
95-
return $data;
80+
$this->eavConfig = $eavConfig
81+
?: \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class);
9682
}
9783

9884
/**
@@ -126,7 +112,7 @@ public function execute()
126112
$this->storeManager->setCurrentStore($store->getCode());
127113
$parentId = isset($categoryPostData['parent']) ? $categoryPostData['parent'] : null;
128114
if ($categoryPostData) {
129-
$category->addData($this->_filterCategoryPostData($categoryPostData));
115+
$category->addData($categoryPostData);
130116
if ($isNewCategory) {
131117
$parentCategory = $this->getParentCategory($parentId, $storeId);
132118
$category->setPath($parentCategory->getPath());
@@ -248,18 +234,30 @@ public function execute()
248234
}
249235

250236
/**
251-
* Image data preprocessing
237+
* Sets image attribute data to false if image was removed
252238
*
253239
* @param array $data
254-
*
255240
* @return array
256241
*/
257-
public function imagePreprocessing($data)
242+
public function imagePreprocessing(array $data)
258243
{
259-
if (empty($data['image'])) {
260-
unset($data['image']);
261-
$data['image']['delete'] = true;
244+
$entityType = $this->eavConfig->getEntityType(CategoryAttributeInterface::ENTITY_TYPE_CODE);
245+
246+
foreach ($entityType->getAttributeCollection() as $attributeModel) {
247+
$attributeCode = $attributeModel->getAttributeCode();
248+
$backendModel = $attributeModel->getBackend();
249+
250+
if (isset($data[$attributeCode])) {
251+
continue;
252+
}
253+
254+
if (!$backendModel instanceof \Magento\Catalog\Model\Category\Attribute\Backend\Image) {
255+
continue;
256+
}
257+
258+
$data[$attributeCode] = false;
262259
}
260+
263261
return $data;
264262
}
265263

app/code/Magento/Catalog/Model/Category.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -652,14 +652,14 @@ public function formatUrlKey($str)
652652
}
653653

654654
/**
655-
* Retrieve image URL
656-
*
657-
* @return string
655+
* @param string $attributeCode
656+
* @return bool|string
657+
* @throws \Magento\Framework\Exception\LocalizedException
658658
*/
659-
public function getImageUrl()
659+
public function getImageUrl($attributeCode = 'image')
660660
{
661661
$url = false;
662-
$image = $this->getImage();
662+
$image = $this->getData($attributeCode);
663663
if ($image) {
664664
if (is_string($image)) {
665665
$url = $this->_storeManager->getStore()->getBaseUrl(

app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
1515
{
16+
const ADDITIONAL_DATA_PREFIX = '_additional_data_';
17+
1618
/**
1719
* @var \Magento\MediaStorage\Model\File\UploaderFactory
1820
*
@@ -21,17 +23,13 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
2123
protected $_uploaderFactory;
2224

2325
/**
24-
* Filesystem facade
25-
*
2626
* @var \Magento\Framework\Filesystem
2727
*
2828
* @deprecated
2929
*/
3030
protected $_filesystem;
3131

3232
/**
33-
* File Uploader factory
34-
*
3533
* @var \Magento\MediaStorage\Model\File\UploaderFactory
3634
*
3735
* @deprecated
@@ -46,15 +44,11 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
4644
protected $_logger;
4745

4846
/**
49-
* Image uploader
50-
*
5147
* @var \Magento\Catalog\Model\ImageUploader
5248
*/
5349
private $imageUploader;
5450

5551
/**
56-
* Image constructor.
57-
*
5852
* @param \Psr\Log\LoggerInterface $logger
5953
* @param \Magento\Framework\Filesystem $filesystem
6054
* @param \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory
@@ -70,19 +64,55 @@ public function __construct(
7064
}
7165

7266
/**
73-
* Get image uploader
67+
* Gets image name from $value array.
68+
* Will return empty string in a case when $value is not an array
69+
*
70+
* @param array $value Attribute value
71+
* @return string
72+
*/
73+
private function getUploadedImageName($value)
74+
{
75+
if (is_array($value) && isset($value[0]['name'])) {
76+
return $value[0]['name'];
77+
}
78+
79+
return '';
80+
}
81+
82+
/**
83+
* Avoiding saving potential upload data to DB
84+
* Will set empty image attribute value if image was not uploaded
7485
*
86+
* @param \Magento\Framework\DataObject $object
87+
* @return $this
88+
*/
89+
public function beforeSave($object)
90+
{
91+
$attributeName = $this->getAttribute()->getName();
92+
$value = $object->getData($attributeName);
93+
94+
if ($imageName = $this->getUploadedImageName($value)) {
95+
$object->setData(self::ADDITIONAL_DATA_PREFIX . $attributeName, $value);
96+
$object->setData($attributeName, $imageName);
97+
} else if (!is_string($value)) {
98+
$object->setData($attributeName, '');
99+
}
100+
101+
return parent::beforeSave($object);
102+
}
103+
104+
/**
75105
* @return \Magento\Catalog\Model\ImageUploader
76106
*
77107
* @deprecated
78108
*/
79109
private function getImageUploader()
80110
{
81111
if ($this->imageUploader === null) {
82-
$this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()->get(
83-
\Magento\Catalog\CategoryImageUpload::class
84-
);
112+
$this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()
113+
->get(\Magento\Catalog\CategoryImageUpload::class);
85114
}
115+
86116
return $this->imageUploader;
87117
}
88118

@@ -94,15 +124,16 @@ private function getImageUploader()
94124
*/
95125
public function afterSave($object)
96126
{
97-
$image = $object->getData($this->getAttribute()->getName(), null);
127+
$value = $object->getData(self::ADDITIONAL_DATA_PREFIX . $this->getAttribute()->getName());
98128

99-
if ($image !== null) {
129+
if ($imageName = $this->getUploadedImageName($value)) {
100130
try {
101-
$this->getImageUploader()->moveFileFromTmp($image);
131+
$this->getImageUploader()->moveFileFromTmp($imageName);
102132
} catch (\Exception $e) {
103133
$this->_logger->critical($e);
104134
}
105135
}
136+
106137
return $this;
107138
}
108139
}

app/code/Magento/Catalog/Model/Category/DataProvider.php

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Magento\Ui\DataProvider\EavValidationRules;
1818
use Magento\Catalog\Model\CategoryFactory;
1919
use Magento\Framework\Exception\NoSuchEntityException;
20+
use Magento\Catalog\Model\Category\Attribute\Backend\Image as ImageBackendModel;
2021

2122
/**
2223
* Class DataProvider
@@ -206,11 +207,8 @@ public function getData()
206207
$categoryData = $this->addUseDefaultSettings($category, $categoryData);
207208
$categoryData = $this->addUseConfigSettings($categoryData);
208209
$categoryData = $this->filterFields($categoryData);
209-
if (isset($categoryData['image'])) {
210-
unset($categoryData['image']);
211-
$categoryData['image'][0]['name'] = $category->getData('image');
212-
$categoryData['image'][0]['url'] = $category->getImageUrl();
213-
}
210+
$categoryData = $this->convertValues($category, $categoryData);
211+
214212
$this->loadedData[$category->getId()] = $categoryData;
215213
}
216214
return $this->loadedData;
@@ -371,6 +369,31 @@ protected function filterFields($categoryData)
371369
return array_diff_key($categoryData, array_flip($this->ignoreFields));
372370
}
373371

372+
/**
373+
* Converts category image data to acceptable for rendering format
374+
*
375+
* @param \Magento\Catalog\Model\Category $category
376+
* @param array $categoryData
377+
* @return array
378+
*/
379+
private function convertValues($category, $categoryData)
380+
{
381+
foreach ($category->getAttributes() as $attributeCode => $attribute) {
382+
if (!isset($categoryData[$attributeCode])) {
383+
continue;
384+
}
385+
386+
if ($attribute->getBackend() instanceof ImageBackendModel) {
387+
unset($categoryData[$attributeCode]);
388+
389+
$categoryData[$attributeCode][0]['name'] = $category->getData($attributeCode);
390+
$categoryData[$attributeCode][0]['url'] = $category->getImageUrl($attributeCode);
391+
}
392+
}
393+
394+
return $categoryData;
395+
}
396+
374397
/**
375398
* Category's fields default values
376399
*
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Category\Image;
7+
8+
use Magento\Catalog\Controller\Adminhtml\Category\Image\Upload as Model;
9+
use Magento\Framework\App\Request\Http as Request;
10+
use Magento\Catalog\Model\ImageUploader;
11+
use Magento\Framework\Controller\ResultFactory;
12+
use Magento\Framework\DataObject;
13+
use Magento\Backend\App\Action\Context;
14+
15+
/**
16+
* Class UploadTest
17+
*/
18+
class UploadTest extends \PHPUnit_Framework_TestCase
19+
{
20+
private $objectManager;
21+
22+
protected function setUp()
23+
{
24+
$this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
25+
}
26+
27+
public function executeDataProvider()
28+
{
29+
return [
30+
['image1', 'image1'],
31+
['image2', 'image2'],
32+
[null, 'image'],
33+
];
34+
}
35+
36+
/**
37+
* @param string $name
38+
* @param string $savedName
39+
*
40+
* @dataProvider executeDataProvider
41+
*/
42+
public function testExecute($name, $savedName)
43+
{
44+
$request = $this->objectManager->getObject(Request::class);
45+
46+
$uploader = $this->getMock(ImageUploader::class, ['saveFileToTmpDir'], [], '', false);
47+
48+
$resultFactory = $this->getMock(ResultFactory::class, ['create'], [], '', false);
49+
50+
$resultFactory->expects($this->once())
51+
->method('create')
52+
->will($this->returnValue(new DataObject()));
53+
54+
$model = $this->objectManager->getObject(Model::class, [
55+
'context' => $this->objectManager->getObject(Context::class, [
56+
'request' => $request,
57+
'resultFactory' => $resultFactory
58+
]),
59+
'imageUploader' => $uploader
60+
]);
61+
62+
$uploader->expects($this->once())
63+
->method('saveFileToTmpDir')
64+
->with($savedName)
65+
->will($this->returnValue([]));
66+
67+
$request->setParam('param_name', $name);
68+
69+
$model->execute();
70+
}
71+
}

0 commit comments

Comments
 (0)