- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Product: custom attribute file upload
Hello,
I was trying to create a new custom product attribute to upload a KML file. Although the file upload field is displayed when I save the product the field is not part of the POST data. The content type seem fine:
Content-Type:multipart/form-data;
Here is the code to create the attribute:
$eavSetup->addAttribute( \Magento\Catalog\Model\Product::ENTITY, 'starting_point_kml', [ 'type' => 'varchar', 'label' => 'Starting point kml', 'input' => 'file', 'backend' => 'My\Module\Model\Product\Attribute\Backend\Kml', 'frontend' => 'My\Module\Model\Product\Attribute\Frontend\Kml', 'class' => '', 'source' => '', 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, 'visible' => true, 'required' => false, 'user_defined' => true, 'default' => '', 'searchable' => false, 'filterable' => false, 'comparable' => false, 'visible_on_front' => true, 'unique' => false, 'apply_to' => 'customProductType', 'used_in_product_listing' => false ] );
The backend and frontend model are based on magento/module-catalog/Model/Category/Attribute/Backend/Image.php
Here is my backend model:
app/code/My/Module/Model/Product/Attribute/Backend/Kml.php
<?php namespace My\Module\Model\Product\Attribute\Backend; use Magento\Framework\App\Filesystem\DirectoryList; class Kml extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend { protected $_uploaderFactory; protected $_filesystem; protected $_fileUploaderFactory; protected $_logger; /** * Construct * * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory */ public function __construct( \Psr\Log\LoggerInterface $logger, \Magento\Framework\Filesystem $filesystem, \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory ) { $this->_filesystem = $filesystem; $this->_fileUploaderFactory = $fileUploaderFactory; $this->_logger = $logger; } public function afterSave($object) { $value = $object->getData($this->getAttribute()->getName() . '_additional_data'); // if no image was set - nothing to do if (empty($value) && empty($_FILES)) { return $this; } if (is_array($value) && !empty($value['delete'])) { $object->setData($this->getAttribute()->getName(), ''); $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName()); return $this; } $path = $this->_filesystem->getDirectoryRead( DirectoryList::MEDIA )->getAbsolutePath( 'catalog/product/kml/' ); $this->_logger->debug($path); try { /** @var $uploader \Magento\MediaStorage\Model\File\Uploader */ $uploader = $this->_fileUploaderFactory->create(['fileId' => $this->getAttribute()->getName()]); $uploader->setAllowedExtensions(['kml']); $uploader->setAllowRenameFiles(true); $result = $uploader->save($path); $object->setData($this->getAttribute()->getName(), $result['file']); $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName()); } catch (\Exception $e) { if ($e->getCode() != \Magento\MediaStorage\Model\File\Uploader::TMP_NAME_EMPTY) { $this->_logger->critical($e); } } return $this; } }
And here is the frontend model:
app/code/My/Module/Model/Product/Attribute/Frontend/Kml.php
<?php namespace My\Module\Model\Product\Attribute\Frontend; class Kml extends \Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend { /** * Store manager * * @var \Magento\Store\Model\StoreManagerInterface */ protected $_storeManager; /** * Construct * * @param \Magento\Store\Model\StoreManagerInterface $storeManager */ public function __construct(\Magento\Store\Model\StoreManagerInterface $storeManager) { $this->_storeManager = $storeManager; } /** * Returns url to product image * * @param \Magento\Catalog\Model\Product $product * * @return string|false */ public function getUrl($product) { $kml = $product->getData($this->getAttribute()->getAttributeCode()); $url = false; if (!empty($kml)) { $url = $this->_storeManager->getStore($product->getStore()) ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) . 'catalog/product/kml/' . $kml; } return $url; } }
Am I missing something about the input field of type file ? Why is the file not sent to the server ? is there something with the AJAX maybe ?
Thank you.
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
Hello, did you already find a solution for this?
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
Hi fperrin, perhaps you already found a solution but just leaving my solution here for the internet..
After a lot of debugging I found out the data will be sended to the server (the $_FILES var) but it contains the wrong format.
A normal formatted $_FILES in Magento 2 looks like (took an image as example):
Array ( [myattribute] => Array ( [name] => myimage.jpg [type] => image/jpeg [tmp_name] => C:\Users\user\AppData\Local\Temp\php7B9A.tmp [error] => 0 [size] => 455590 ) )
But the code below outputs the $_FILES into this format:
Array ( [product] => Array ( [name] => Array ( [myattribute] => myimage.jpg ) [type] => Array ( [myattribute] => image/jpeg ) [tmp_name] => Array ( [myattribute] => C:\Users\user\AppData\Local\Temp\php6A5D.tmp ) [error] => Array ( [myattribute] => 0 ) [size] => Array ( [myattribute] => 455590 ) ) )
As you see the custom attribute (starting_point_kml) is inserted in each key of the sended data.
My workaround is to manipulate and transform the $_FILES variable using following code:
$attributeCode = $this->getAttribute()->getAttributeCode(); foreach($_FILES['product'] as $value => $key) { $_FILES[$attributeCode][$value] = $key[$attributeCode]; } unset($_FILES['product']);
And upload it with a little modification to your code:
$path = $this->_filesystem->getDirectoryRead( DirectoryList::MEDIA )->getAbsolutePath( 'my/path' ); try { $uploader = $this->uploaderFactory->create(['fileId' => $attributeCode]); $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(true); $uploader->setAllowCreateFolders(true); $result = $uploader->save($path); $object->setData($attributeCode, $result['file']); return parent::beforeSave($object); } catch (\Exception $e) { if ($e->getCode() != \Magento\Framework\File\Uploader::TMP_NAME_EMPTY) { throw new FrameworkException($e->getMessage()); } else { echo 'TMP NAME EMPTY ERROR'; return false; } }
I have not worked with the frontend model yet, but now at least the file is saved and inserted to the db. Hope this helped.
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
another way is to specify $attributeCode as product[myattribute]
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
Thanks for your solution suiteseven_nl. I've tried implementing it but I'm getting some errors. Could you please show the full code for the backend model so I can see the complete code. Thanks in advance for your help!
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
Your code definitely work. But I need to change afterSave method to beforeSave.
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
Hi tried to follow this article to create the attachment for the products. I was able to upload the file as well as update the database. However, in the edit screen, it does not show the file that was uploaded. Can you please suggest.
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
hi can u send whole code as i am unable to make it work
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Re: Product: custom attribute file upload
Can you please share code of file upload.
Thank you