PageRenderTime 51ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/app/Widget/FileUploadMany/FileUploadMany.php

https://gitlab.com/dram1008/galaxysss
PHP | 401 lines | 230 code | 39 blank | 132 comment | 9 complexity | 45359081a72505d37d96d03668b0fc94 MD5 | raw file
  1. <?php
  2. namespace cs\Widget\FileUploadMany;
  3. use Yii;
  4. use yii\base\InvalidConfigException;
  5. use yii\base\Model;
  6. use yii\db\Query;
  7. use yii\helpers\ArrayHelper;
  8. use yii\helpers\StringHelper;
  9. use yii\helpers\Url;
  10. use yii\helpers\Html;
  11. use yii\helpers\Json;
  12. use yii\helpers\VarDumper;
  13. use yii\web\UploadedFile;
  14. use yii\imagine\Image;
  15. use yii\web\JsExpression;
  16. use Imagine\Image\ManipulatorInterface;
  17. use cs\base\BaseForm;
  18. use cs\Widget\FileUploadMany\ModelFiles;
  19. use cs\services\UploadFolderDispatcher;
  20. use cs\services\SitePath;
  21. use yii\jui\InputWidget;
  22. /**
  23. * Класс FileUploadMany
  24. *
  25. * Виджет который загружает файлы по несколько штук
  26. *
  27. * Максимальный размер загружаемого файла по умолчанию устанавливается равный тому который указан в параметре ini.php upload_max_filesize
  28. *
  29. $field->widget('cs\Widget\FileUploadMany\FileUploadMany', [
  30. ]);
  31. $options = [
  32. 'serverName'
  33. ];
  34. $model->$fieldName = [
  35. ['file_path', 'file_name'],
  36. ];
  37. */
  38. class FileUploadMany extends InputWidget
  39. {
  40. const MODE_THUMBNAIL_INSET = ManipulatorInterface::THUMBNAIL_INSET;
  41. const MODE_THUMBNAIL_OUTBOUND = ManipulatorInterface::THUMBNAIL_OUTBOUND;
  42. public static $uploadDirectory = '@runtime/uploads/FileUploadMany';
  43. public static $tableNameFiles = 'widget_uploader_many';
  44. public static $tableNameFields = 'widget_uploader_many_fields';
  45. /**
  46. * @var string the template for arranging the CAPTCHA image tag and the text input tag.
  47. * In this template, the token `{image}` will be replaced with the actual image tag,
  48. * while `{input}` will be replaced with the text input tag.
  49. */
  50. public $template = "<div class='upload'>\n{image}\n{checkbox}\n{input}\n</div>";
  51. /**
  52. * @var array the HTML attributes for the input tag.
  53. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
  54. */
  55. public $options = [];
  56. private $tableName;
  57. private $fieldId;
  58. private $fieldName;
  59. private $hiddenId;
  60. private $hiddenName;
  61. /**
  62. * Initializes the widget.
  63. */
  64. public function init()
  65. {
  66. parent::init();
  67. $this->fieldId = strtolower($this->model->formName() . '-' . $this->attribute);
  68. $this->fieldName = $this->model->formName() . '[' . $this->attribute . ']';
  69. $this->hiddenId = strtolower($this->model->formName() . '-' . $this->attribute . '-files');
  70. $this->hiddenName = $this->model->formName() . '[' . $this->attribute . '-files' . ']';
  71. }
  72. /**
  73. * рисует виджет
  74. */
  75. public function run()
  76. {
  77. $this->registerClientScript();
  78. if ($this->hasModel()) {
  79. $attribute = $this->attribute;
  80. $files = $this->model->$attribute;
  81. if (is_null($files)) $files = [];
  82. $this->clientOptions['files'] = $files;
  83. $c1 = Html::hiddenInput($this->hiddenName, json_encode($this->clientOptions['files'], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), ['id' => $this->hiddenId]);
  84. $c2 = Html::fileInput($this->fieldName, null, ['id' => $this->fieldId]);
  85. return Html::tag('div', $c1 . $c2, ['class' => 'multifile_upload']);
  86. }
  87. }
  88. private function renderTemplate($params)
  89. {
  90. $t = $this->template;
  91. foreach ($params as $key => $value) {
  92. $t = str_replace('{' . $key . '}', $value, $t);
  93. }
  94. return $t;
  95. }
  96. /**
  97. * Registers the needed JavaScript.
  98. */
  99. public function registerClientScript()
  100. {
  101. Asset::register($this->view);
  102. $this->clientOptions = ArrayHelper::merge($this->getClientOptions(), $this->clientOptions);
  103. $options = Json::encode($this->clientOptions);
  104. $js = <<<JSSSS
  105. FileUploadMany.init('#{$this->fieldId}', {$options});
  106. JSSSS;
  107. $this->getView()->registerJs($js);
  108. }
  109. /**
  110. * Возвращает опции для виджета
  111. *
  112. * @return array the options
  113. */
  114. protected function getClientOptions()
  115. {
  116. return [
  117. 'url' => '/upload/upload',
  118. 'maxFileSize' => self::getUploadMaxFileSize(),
  119. ];
  120. }
  121. /**
  122. * Возвращает максимально возможно загружаемый файл который установлен в настройках PHP
  123. *
  124. * @return int в байтах
  125. */
  126. private static function getUploadMaxFileSize()
  127. {
  128. $maxFileSize = ini_get('upload_max_filesize');
  129. return (int)substr($maxFileSize, 0, strlen($maxFileSize) - 1) * 1024 * 1024;
  130. }
  131. /**
  132. * @param array $field
  133. * @param \yii\base\Model $model
  134. *
  135. * @return array поля для обновления в БД
  136. */
  137. public static function onLoad($field, $model)
  138. {
  139. $fieldName = $field[ BaseForm::POS_DB_NAME ];
  140. $post = Yii::$app->request->post();
  141. $query = $model->formName() . '.' . $fieldName . '-files';
  142. $filesString = ArrayHelper::getValue($post, $query, '');
  143. $model->$fieldName = json_decode($filesString);
  144. }
  145. /**
  146. *
  147. *
  148. * @param array $field
  149. * @param \cs\base\BaseForm $model
  150. *
  151. * @return array поля для обновления в БД
  152. */
  153. public static function onLoadDb($field, $model)
  154. {
  155. $fieldName = $field[ BaseForm::POS_DB_NAME ];
  156. $files = (new Query())
  157. ->select('w.file_path, w.file_name')
  158. ->from('widget_uploader_many w')
  159. ->innerJoin('widget_uploader_many_fields wf', 'w.field_id = wf.id')
  160. ->where([
  161. 'w.row_id' => $model->id,
  162. 'wf.table_name' => $model->getTableName(),
  163. 'wf.field_name' => $fieldName
  164. ])
  165. ->all();
  166. $rows = [];
  167. foreach($files as $file) {
  168. $rows[] = [$file['file_path'],$file['file_name']];
  169. }
  170. $model->$fieldName = $rows;
  171. }
  172. /**
  173. * @param array $field
  174. * @param \cs\base\BaseForm $model
  175. *
  176. * @return array поля для обновления в БД
  177. */
  178. public static function onUpdate($field, $model)
  179. {
  180. $fieldName = $field[ BaseForm::POS_DB_NAME ];
  181. $files = $model->$fieldName;
  182. $tableName = $model->getTableName();
  183. $fieldDb = ModelFields::insertOne([
  184. 'table_name' => $tableName,
  185. 'field_name' => $fieldName,
  186. ]);
  187. ModelFiles::deleteByCondition([
  188. 'row_id' => $fieldDb->getId(),
  189. ]);
  190. $folder = \cs\services\UploadFolderDispatcher::createFolder('FileUploadMany', $fieldDb->getId(), $model->id);
  191. $allFiles = [];
  192. foreach ($files as $file) {
  193. $allFiles[] = $file[0];
  194. }
  195. $currentFiles = (new Query())
  196. ->select('w.file_path, w.id')
  197. ->from('widget_uploader_many w')
  198. ->innerJoin('widget_uploader_many_fields wf', 'w.field_id = wf.id')
  199. ->where([
  200. 'w.row_id' => $model->id,
  201. 'wf.table_name' => $model->getTableName(),
  202. 'wf.field_name' => $fieldName
  203. ])
  204. ->all();
  205. foreach ($currentFiles as $currentFile) {
  206. if (!in_array($currentFile['file_path'], $allFiles)) {
  207. (new SitePath($currentFile['file_path']))->deleteFile();
  208. $id = (int)$currentFile['id'];
  209. ModelFiles::deleteByCondition(['id' => $id]);
  210. }
  211. }
  212. foreach ($files as $file) {
  213. if (StringHelper::startsWith($file[0], '/')) {
  214. continue;
  215. }
  216. $sourcePathFull = Yii::getAlias(self::$uploadDirectory . '/' . $file[0]);
  217. $destinationFile = $folder->cloneObject($file[0]);
  218. copy($sourcePathFull, $destinationFile->getPathFull());
  219. ModelFiles::insert([
  220. 'file_path' => $destinationFile->getPath(),
  221. 'file_name' => $file[1],
  222. 'row_id' => $model->id,
  223. 'field_id' => $fieldDb->getId(),
  224. 'datetime' => gmdate('YmdHis'),
  225. ]);
  226. }
  227. return [
  228. $fieldName => count($files),
  229. ];
  230. }
  231. /**
  232. * Возвращает ссылку для скачивания файла
  233. *
  234. * @return string
  235. */
  236. public static function getDownloadLink($id)
  237. {
  238. return 'upload/download/' . $id;
  239. }
  240. /**
  241. * Рисует просмотр файла для детального просмотра
  242. *
  243. * @param \yii\base\Model $model
  244. * @param array $field
  245. *
  246. * @return string
  247. *
  248. */
  249. public static function drawDetailView($model, $field)
  250. {
  251. return self::onDetailView($model, $field);
  252. }
  253. /**
  254. * Рисует просмотр файла для детального просмотра
  255. *
  256. * @param \yii\base\Model $model
  257. * @param array $field
  258. *
  259. * @return string
  260. *
  261. */
  262. public static function onDetailView($model, $field)
  263. {
  264. return 'FileUploadMany';
  265. }
  266. /**
  267. * Удаляет
  268. *
  269. * @param \cs\base\BaseForm | \cs\models\DbRecord $model
  270. * @param array $field
  271. *
  272. * @return string
  273. */
  274. public static function onDelete($field, $model)
  275. {
  276. $fieldName = $field[ BaseForm::POS_DB_NAME ];
  277. $fieldId = self::getFieldId($model->getTableName(), $fieldName);
  278. $files = (new Query())->select('file_path, id')->from(self::$tableNameFiles)->where([
  279. 'row_id' => $model->id,
  280. 'field_id' => $fieldId,
  281. ])->all();
  282. foreach ($files as $file) {
  283. (new SitePath($file))->deleteFile();
  284. }
  285. }
  286. /**
  287. * Рисует просмотр файла для детального просмотра
  288. *
  289. * @param \cs\base\BaseForm | \cs\base\DbRecord $model
  290. * @param array $field
  291. *
  292. * @return string
  293. */
  294. public static function onDraw($field, $model)
  295. {
  296. $html = [];
  297. $serverName = ArrayHelper::getValue($field, 'widget.1.options.serverName', '');
  298. $rows = self::getFiles($model->getTableName(), $field[ \cs\base\BaseForm::POS_DB_NAME ], $model->getId());
  299. foreach ($rows as $row) {
  300. $href = $row['file_path'];
  301. if ($serverName != '') $href = '//' . $serverName . $href;
  302. $html[] = Html::a($row['file_name'], $href, ['target' => '_blank']);
  303. $html[] = Html::tag('br');
  304. }
  305. return join("\r", $html);
  306. }
  307. /**
  308. * Выдает список файлов в поле
  309. *
  310. * @param string $tableName название таблицы
  311. * @param string $fieldName название поля
  312. * @param int $rowId идентификатор строки
  313. * @param string $serverName имя сервера для ссылок файлов, если задано то оно будет прибавлено к именам в формате "//{$serverName}/ss/..."
  314. *
  315. * @return array
  316. * [[
  317. * 'id' => int
  318. * 'file_path' => str
  319. * 'file_name' => str
  320. * 'datetime' => str
  321. * ], ...]
  322. */
  323. public static function getFiles($tableName, $fieldName, $rowId, $serverName = null)
  324. {
  325. $fieldId = self::getFieldId($tableName, $fieldName);
  326. if ($fieldId === false) return [];
  327. $select = [
  328. 'id',
  329. 'file_name',
  330. 'UNIX_TIMESTAMP(datetime) as datetime'
  331. ];
  332. if (is_null($serverName)) {
  333. $select[] = 'file_path';
  334. } else {
  335. $select[] = "concat('//{$serverName}',`file_path`) as file_path";
  336. }
  337. return (new Query())->select($select)->from(self::$tableNameFiles)->where([
  338. 'row_id' => $rowId,
  339. 'field_id' => $fieldId,
  340. ])->orderBy('datetime DESC')->all();
  341. }
  342. /**
  343. * Возвращает FieldId
  344. *
  345. * @param $tableName
  346. * @param $fieldName
  347. *
  348. * @return false|int
  349. */
  350. public static function getFieldId($tableName, $fieldName)
  351. {
  352. return (new Query())->select('id')->from(self::$tableNameFields)->where([
  353. 'table_name' => $tableName,
  354. 'field_name' => $fieldName,
  355. ])->scalar();
  356. }
  357. }