File.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Config\Model\Config\Backend;
  7. use Magento\Framework\App\Config\ScopeConfigInterface;
  8. use Magento\Framework\App\Filesystem\DirectoryList;
  9. use Magento\Framework\Filesystem;
  10. use Magento\MediaStorage\Model\File\Uploader;
  11. /**
  12. * System config file field backend model
  13. *
  14. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  15. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  16. * @api
  17. * @since 100.0.2
  18. */
  19. class File extends \Magento\Framework\App\Config\Value
  20. {
  21. /**
  22. * @var \Magento\Config\Model\Config\Backend\File\RequestData\RequestDataInterface
  23. */
  24. protected $_requestData;
  25. /**
  26. * Upload max file size in kilobytes
  27. *
  28. * @var int
  29. */
  30. protected $_maxFileSize = 0;
  31. /**
  32. * @var Filesystem
  33. */
  34. protected $_filesystem;
  35. /**
  36. * @var \Magento\Framework\Filesystem\Directory\WriteInterface
  37. */
  38. protected $_mediaDirectory;
  39. /**
  40. * @var \Magento\MediaStorage\Model\File\UploaderFactory
  41. */
  42. protected $_uploaderFactory;
  43. /**
  44. * @param \Magento\Framework\Model\Context $context
  45. * @param \Magento\Framework\Registry $registry
  46. * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
  47. * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList
  48. * @param \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory
  49. * @param \Magento\Config\Model\Config\Backend\File\RequestData\RequestDataInterface $requestData
  50. * @param Filesystem $filesystem
  51. * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
  52. * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
  53. * @param array $data
  54. */
  55. public function __construct(
  56. \Magento\Framework\Model\Context $context,
  57. \Magento\Framework\Registry $registry,
  58. \Magento\Framework\App\Config\ScopeConfigInterface $config,
  59. \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
  60. \Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
  61. \Magento\Config\Model\Config\Backend\File\RequestData\RequestDataInterface $requestData,
  62. Filesystem $filesystem,
  63. \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
  64. \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
  65. array $data = []
  66. ) {
  67. $this->_uploaderFactory = $uploaderFactory;
  68. $this->_requestData = $requestData;
  69. $this->_filesystem = $filesystem;
  70. $this->_mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
  71. parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
  72. }
  73. /**
  74. * Save uploaded file before saving config value
  75. *
  76. * @return $this
  77. * @throws \Magento\Framework\Exception\LocalizedException
  78. */
  79. public function beforeSave()
  80. {
  81. $value = $this->getValue();
  82. $file = $this->getFileData();
  83. if (!empty($file)) {
  84. $uploadDir = $this->_getUploadDir();
  85. try {
  86. /** @var Uploader $uploader */
  87. $uploader = $this->_uploaderFactory->create(['fileId' => $file]);
  88. $uploader->setAllowedExtensions($this->_getAllowedExtensions());
  89. $uploader->setAllowRenameFiles(true);
  90. $uploader->addValidateCallback('size', $this, 'validateMaxSize');
  91. $result = $uploader->save($uploadDir);
  92. } catch (\Exception $e) {
  93. throw new \Magento\Framework\Exception\LocalizedException(__('%1', $e->getMessage()));
  94. }
  95. $filename = $result['file'];
  96. if ($filename) {
  97. if ($this->_addWhetherScopeInfo()) {
  98. $filename = $this->_prependScopeInfo($filename);
  99. }
  100. $this->setValue($filename);
  101. }
  102. } else {
  103. if (is_array($value) && !empty($value['delete'])) {
  104. $this->setValue('');
  105. } elseif (is_array($value) && !empty($value['value'])) {
  106. $this->setValue($value['value']);
  107. } else {
  108. $this->unsValue();
  109. }
  110. }
  111. return $this;
  112. }
  113. /**
  114. * Receiving uploaded file data
  115. *
  116. * @return array
  117. * @since 100.1.0
  118. */
  119. protected function getFileData()
  120. {
  121. $file = [];
  122. $value = $this->getValue();
  123. $tmpName = $this->_requestData->getTmpName($this->getPath());
  124. if ($tmpName) {
  125. $file['tmp_name'] = $tmpName;
  126. $file['name'] = $this->_requestData->getName($this->getPath());
  127. } elseif (!empty($value['tmp_name'])) {
  128. $file['tmp_name'] = $value['tmp_name'];
  129. $file['name'] = isset($value['value']) ? $value['value'] : $value['name'];
  130. }
  131. return $file;
  132. }
  133. /**
  134. * Validation callback for checking max file size
  135. *
  136. * @param string $filePath Path to temporary uploaded file
  137. * @return void
  138. * @throws \Magento\Framework\Exception\LocalizedException
  139. */
  140. public function validateMaxSize($filePath)
  141. {
  142. $directory = $this->_filesystem->getDirectoryRead(DirectoryList::SYS_TMP);
  143. if ($this->_maxFileSize > 0 && $directory->stat(
  144. $directory->getRelativePath($filePath)
  145. )['size'] > $this->_maxFileSize * 1024
  146. ) {
  147. throw new \Magento\Framework\Exception\LocalizedException(
  148. __('The file you\'re uploading exceeds the server size limit of %1 kilobytes.', $this->_maxFileSize)
  149. );
  150. }
  151. }
  152. /**
  153. * Makes a decision about whether to add info about the scope.
  154. *
  155. * @return boolean
  156. */
  157. protected function _addWhetherScopeInfo()
  158. {
  159. $fieldConfig = $this->getFieldConfig();
  160. $dirParams = array_key_exists('upload_dir', $fieldConfig) ? $fieldConfig['upload_dir'] : [];
  161. return is_array($dirParams) && array_key_exists('scope_info', $dirParams) && $dirParams['scope_info'];
  162. }
  163. /**
  164. * Return path to directory for upload file
  165. *
  166. * @return string
  167. * @throws \Magento\Framework\Exception\LocalizedException
  168. */
  169. protected function _getUploadDir()
  170. {
  171. $fieldConfig = $this->getFieldConfig();
  172. if (!array_key_exists('upload_dir', $fieldConfig)) {
  173. throw new \Magento\Framework\Exception\LocalizedException(
  174. __('The base directory to upload file is not specified.')
  175. );
  176. }
  177. if (is_array($fieldConfig['upload_dir'])) {
  178. $uploadDir = $fieldConfig['upload_dir']['value'];
  179. if (array_key_exists('scope_info', $fieldConfig['upload_dir'])
  180. && $fieldConfig['upload_dir']['scope_info']
  181. ) {
  182. $uploadDir = $this->_appendScopeInfo($uploadDir);
  183. }
  184. if (array_key_exists('config', $fieldConfig['upload_dir'])) {
  185. $uploadDir = $this->getUploadDirPath($uploadDir);
  186. }
  187. } else {
  188. $uploadDir = (string)$fieldConfig['upload_dir'];
  189. }
  190. return $uploadDir;
  191. }
  192. /**
  193. * Retrieve upload directory path
  194. *
  195. * @param string $uploadDir
  196. * @return string
  197. * @since 100.1.0
  198. */
  199. protected function getUploadDirPath($uploadDir)
  200. {
  201. return $this->_mediaDirectory->getAbsolutePath($uploadDir);
  202. }
  203. /**
  204. * Prepend path with scope info
  205. *
  206. * E.g. 'stores/2/path' , 'websites/3/path', 'default/path'
  207. *
  208. * @param string $path
  209. * @return string
  210. */
  211. protected function _prependScopeInfo($path)
  212. {
  213. $scopeInfo = $this->getScope();
  214. if (ScopeConfigInterface::SCOPE_TYPE_DEFAULT != $this->getScope()) {
  215. $scopeInfo .= '/' . $this->getScopeId();
  216. }
  217. return $scopeInfo . '/' . $path;
  218. }
  219. /**
  220. * Add scope info to path
  221. *
  222. * E.g. 'path/stores/2' , 'path/websites/3', 'path/default'
  223. *
  224. * @param string $path
  225. * @return string
  226. */
  227. protected function _appendScopeInfo($path)
  228. {
  229. $path .= '/' . $this->getScope();
  230. if (ScopeConfigInterface::SCOPE_TYPE_DEFAULT != $this->getScope()) {
  231. $path .= '/' . $this->getScopeId();
  232. }
  233. return $path;
  234. }
  235. /**
  236. * Getter for allowed extensions of uploaded files
  237. *
  238. * @return array
  239. */
  240. protected function _getAllowedExtensions()
  241. {
  242. return [];
  243. }
  244. }