ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilCollectFilesJob.php
Go to the documentation of this file.
1<?php
2
25
33{
35
36 private ?ilLogger $logger;
42 private static array $targets = [];
43
47 public function __construct()
48 {
49 global $DIC;
50 $this->logger = $DIC->logger()->cal();
51 }
52
53
57 public function getInputTypes(): array
58 {
59 return
60 [
61 new SingleType(ilCopyDefinition::class),
62 new SingleType(BooleanValue::class),
63 ];
64 }
65
66
70 public function getOutputType(): Type
71 {
72 return new SingleType(ilCopyDefinition::class);
73 }
74
75
79 public function isStateless(): bool
80 {
81 return true;
82 }
83
84
89 public function run(array $input, Observer $observer): Value
90 {
91 $this->logger->debug('Start collecting files!');
92 $this->logger->dump($input);
93 $definition = $input[0];
94 $initiated_by_folder_action = $input[1]->getValue();
95 $object_ref_ids = $definition->getObjectRefIds();
96 $files = [];
97
98 foreach ($object_ref_ids as $object_ref_id) {
99 $object = ilObjectFactory::getInstanceByRefId($object_ref_id);
100 $object_type = $object->getType();
101 $object_name = $object->getTitle();
102 $object_temp_dir = ""; // empty as content will be added in recurseFolder and getFileDirs
103
104 if ($object_type === "fold" || $object_type === "crs") {
105 $num_recursions = 0;
106 $files_from_folder = $this->recurseFolder($object_ref_id, $object_name, $object_temp_dir, $num_recursions, $initiated_by_folder_action);
107 $files = array_merge($files, $files_from_folder);
108 } elseif (($object_type === "file") && (($file_dirs = $this->getFileDirs(
109 $object_ref_id,
110 $object_name,
111 $object_temp_dir
112 )) !== false)) {
113 $files[] = $file_dirs;
114 }
115 }
116 $this->logger->debug('Collected files:');
117 $this->logger->dump($files);
118
119 $num_files = 0;
120 foreach ($files as $file) {
121 $definition->addCopyDefinition($file['source_dir'], $file['target_dir']);
122 $this->logger->debug('Added new copy definition: ' . $file['source_dir'] . ' -> ' . $file['target_dir']);
123
124 // count files only (without empty directories)
125 $is_empty_folder = preg_match_all("/\/$/", (string) $file['target_dir']);
126 if (!$is_empty_folder) {
127 $num_files++;
128 }
129 }
130 $definition->setObjectRefIds($object_ref_ids);
131 $definition->setNumFiles($num_files);
132
133 return $definition;
134 }
135
136
143 private function getFileDirs($a_ref_id, string $a_file_name, string $a_temp_dir): false|array
144 {
145 global $DIC;
146
147 $user = $DIC->user();
148 $ilAccess = $DIC->access();
149 if ($ilAccess->checkAccessOfUser($user->getId(), "read", "", $a_ref_id)) {
150 $file = new ilObjFile($a_ref_id);
151 $source_dir = $file->getFile();
152
153 if (@!is_file($source_dir)) {
154 return false;
155 }
156
157 $filname_with_suffix = $this->ensureSuffix($a_file_name, $file->getFileExtension());
158
159 $target_dir = $a_temp_dir . '/' . $filname_with_suffix;
160
161 // #25025: allow duplicate filenames by appending an incrementing
162 // number per duplicate in brackets to the name.
163 // Example: test.txt, test (1).txt, test (2).txt, ...
164 if (isset(self::$targets[$target_dir])) {
165 $target_info = pathinfo($target_dir);
166 $filename = $target_info["filename"];
167 $extension = isset($target_info["extension"]) ? "." . $target_info["extension"] : "";
168 $target_dir = $a_temp_dir . $filename . " (" . ++self::$targets[$target_dir] . ")" . $extension;
169 } else {
170 self::$targets[$target_dir] = 0;
171 }
172
173 return [
174 "source_dir" => $source_dir,
175 "target_dir" => $target_dir,
176 ];
177 }
178
179 return false;
180 }
181
182
190 private function recurseFolder($a_ref_id, string $a_folder_name, string $a_temp_dir, int|float $a_num_recursions, $a_initiated_by_folder_action): array
191 {
192 global $DIC;
193
194 $num_recursions = $a_num_recursions + 1;
195 $tree = $DIC->repositoryTree();
196 $ilAccess = $DIC->access();
197 $files = [];
198
199 // Avoid the duplication of the uppermost folder when the download is initiated via a folder's action drop-down
200 // by not including said folders name in the temp_dir path.
201 if ($num_recursions <= 1 && $a_initiated_by_folder_action) {
202 $temp_dir = $a_temp_dir;
203 } else {
204 $temp_dir = $a_temp_dir . '/' . ilFileUtils::getASCIIFilename($a_folder_name);
205 }
206
207 $subtree = $tree->getChildsByTypeFilter($a_ref_id, ["fold", "file"]);
208
209 foreach ($subtree as $child) {
210 if (!$ilAccess->checkAccess("read", "", $child["ref_id"])) {
211 continue;
212 }
213 if (ilObject::_isInTrash($child["ref_id"])) {
214 continue;
215 }
216 if ($child["type"] == "fold") {
217 $files_from_folder = $this->recurseFolder($child["ref_id"], $child['title'], $temp_dir, $num_recursions, $a_initiated_by_folder_action);
218 $files = array_merge($files, $files_from_folder);
219 } elseif (($child["type"] === "file") && (($dirs = $this->getFileDirs($child["ref_id"], $child['title'], $temp_dir)) !== false)) {
220 $files[] = $dirs;
221 }
222 }
223 // ensure that empty folders are also contained in the downloaded zip
224 if (empty($subtree)) {
225 $files[] = [
226 "source_dir" => "",
227 "target_dir" => $temp_dir . '/',
228 ];
229 }
230
231 return $files;
232 }
233
234
239 {
240 return 30;
241 }
242}
$filename
Definition: buildRTE.php:78
Description of class class.
run(array $input, Observer $observer)
@inheritDoc
getExpectedTimeOfTaskInSeconds()
int the amount of seconds this task usually taskes. If your task-duration scales with the the amount ...
recurseFolder($a_ref_id, string $a_folder_name, string $a_temp_dir, int|float $a_num_recursions, $a_initiated_by_folder_action)
getFileDirs($a_ref_id, string $a_file_name, string $a_temp_dir)
static getASCIIFilename(string $a_filename)
Component logger with individual log levels by component id.
Class ilObjFile.
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
static _isInTrash(int $ref_id)
global $DIC
Definition: shib_login.php:26
trait ilObjFileSecureString
Trait ilObjFileSecureString.
ensureSuffix(string $title, ?string $suffix=null)