1<?php 2/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4include_once("./Modules/Cloud/exceptions/class.ilCloudException.php"); 5include_once("class.ilCloudFileNode.php"); 6include_once("class.ilCloudConnector.php"); 7include_once("class.ilCloudUtil.php"); 8 9/** 10 * ilCloudFileTree class 11 * 12 * Representation of the structure of all files and folders so far. Not really a tree but a list simulating a tree 13 * (for faster access on the nodes). This class also calls the functions of a service to update the tree (addToFileTree, 14 * deleteItem, etc.) 15 * 16 * @author Timon Amstutz <timon.amstutz@ilub.unibe.ch> 17 * @version $Id$ 18 * @ingroup ModulesCloud 19 */ 20class ilCloudFileTree 21{ 22 23 /** 24 * id of the ilCloudFileTree, equals the object_id of the calling object or gui_class 25 * @var int id 26 */ 27 protected $id = 0; 28 29 /** 30 * @var ilCloudFileNode 31 */ 32 protected $root_node = null; 33 34 /** 35 * Path to $root_node ($root_node has always path "/", root_path is the path which can be changed in the settings) 36 * @var string 37 */ 38 protected $root_path = ""; 39 /** 40 * @var array 41 */ 42 protected $item_list = array(); 43 44 /** 45 * Only for better performance 46 */ 47 protected $id_to_path_map = array(); 48 49 /** 50 * @var string $service_name 51 */ 52 protected $service_name = ""; 53 54 /** 55 * @var bool 56 */ 57 protected $case_sensitive = false; 58 59 /** 60 * @param string $root_path 61 * @param string $root_id 62 * @param int $id 63 * @param string $service_name 64 * @param bool $case_sensitive 65 */ 66 public function __construct($root_path = "/", $root_id = "root", $id, $service_name) 67 { 68 $this->setId($id); 69 $this->root_node = $this->createNode($root_path, $root_id, true); 70 $this->setServiceName($service_name); 71 $service = ilCloudConnector::getServiceClass($service_name, $id); 72 $this->setCaseSensitive($service->isCaseSensitive()); 73 } 74 75 /** 76 * @param int $id 77 */ 78 protected function setId($id) 79 { 80 $this->id = $id; 81 } 82 83 /** 84 * @return int 85 */ 86 public function getId() 87 { 88 return $this->id; 89 } 90 91 92 /** 93 * @param string $path 94 */ 95 protected function setRootPath($path = "/") 96 { 97 $this->root_path = ilCloudUtil::normalizePath($path); 98 } 99 100 /** 101 * @return string 102 */ 103 public function getRootPath() 104 { 105 return $this->root_path; 106 } 107 108 /** 109 * @param string $service_name 110 */ 111 protected function setServiceName($service_name) 112 { 113 $this->service_name = $service_name; 114 } 115 116 /** 117 * @return string 118 */ 119 public function getServiceName() 120 { 121 return $this->service_name; 122 } 123 124 /** 125 * @return boolean 126 */ 127 public function isCaseSensitive() 128 { 129 return $this->case_sensitive; 130 } 131 132 /** 133 * @param boolean $case_sensitive 134 */ 135 public function setCaseSensitive($case_sensitive) 136 { 137 $this->case_sensitive = $case_sensitive; 138 } 139 140 /** 141 * @return ilCloudFileNode|null 142 */ 143 public function getRootNode() 144 { 145 return $this->root_node; 146 } 147 148 /** 149 * @param string $path 150 * @param bool $is_dir 151 * @return ilCloudFileNode 152 */ 153 protected function createNode($path = "/", $id, $is_dir = false) 154 { 155 $node = new ilCloudFileNode(ilCloudUtil::normalizePath($path), $id); 156 $this->item_list[$node->getPath()] = $node; 157 $this->id_to_path_map[$node->getId()] = $node->getPath(); 158 $node->setIsDir($is_dir); 159 return $node; 160 } 161 162 /** 163 * @param $path 164 * @param $is_Dir 165 * @param null $modified 166 * @param int $size 167 * @return ilCloudFileNode 168 */ 169 public function addNode($path, $id, $is_Dir, $modified = null, $size = 0) 170 { 171 $path = ilCloudUtil::normalizePath($path); 172 $node = $this->getNodeFromPath($path); 173 174 //node does not yet exist 175 if (!$node) { 176 if ($this->getNodeFromId($id)) { 177 throw new ilCloudException(ilCloudException::ID_ALREADY_EXISTS_IN_FILE_TREE_IN_SESSION); 178 } 179 $path_of_parent = ilCloudUtil::normalizePath(dirname($path)); 180 $node_parent = $this->getNodeFromPath($path_of_parent); 181 if (!$node_parent) { 182 throw new ilCloudException(ilCloudException::PATH_DOES_NOT_EXIST_IN_FILE_TREE_IN_SESSION, "Parent: " . $path_of_parent); 183 } 184 $node = $this->createNode($path, $id, $is_Dir); 185 $node->setParentId($node_parent->getId()); 186 $node_parent->addChild($node->getPath()); 187 } 188 189 $node->setSize($size); 190 $node->setModified($modified); 191 192 return $node; 193 } 194 195 196 /** 197 * Add node that relies on id's 198 * 199 * @param $path 200 * @param $id 201 * @param $parent_id 202 * @param $is_Dir 203 * @param null $modified 204 * @param int $size 205 * 206 * @return ilCloudFileNode 207 * @throws ilCloudException 208 */ 209 public function addIdBasedNode($path, $id, $parent_id, $is_Dir, $modified = null, $size = 0) 210 { 211 $path = ilCloudUtil::normalizePath($path); 212 $node = $this->getNodeFromPath($path); 213 214 //node does not yet exist 215 if (!$node) { 216 $nodeFromId = $this->getNodeFromId($id); 217 // If path isn't found but id is there -> Path got changed 218 if ($nodeFromId) { 219 // Adjust path 220 $nodeFromId->setPath($path); 221 } 222 223 $node_parent = $this->getNodeFromId($parent_id); 224 if (!$node_parent) { 225 throw new ilCloudException(ilCloudException::PATH_DOES_NOT_EXIST_IN_FILE_TREE_IN_SESSION, "Parent: " . $parent_id); 226 } 227 $node = $this->createNode($path, $id, $is_Dir); 228 $node->setParentId($node_parent->getId()); 229 $node_parent->addChild($node->getPath()); 230 } 231 232 $node->setSize($size); 233 $node->setModified($modified); 234 235 return $node; 236 } 237 238 239 /** 240 * @param $path 241 */ 242 public function removeNode($path) 243 { 244 $node = $this->getNodeFromPath($path); 245 $parent = $this->getNodeFromId($node->getParentId()); 246 $parent->removeChild($path); 247 unset($this->item_list[$node->getPath()]); 248 unset($this->id_to_path_map[$node->getId()]); 249 } 250 251 /** 252 * @return array 253 */ 254 public function getItemList() 255 { 256 return $this->item_list; 257 } 258 259 /** 260 * @param string $path 261 * @return ilCloudFileNode node; 262 */ 263 public function getNodeFromPath($path = "/") 264 { 265 if (!$this->isCaseSensitive() || $this->item_list[$path]) { 266 return $this->item_list[$path]; 267 } 268 269 foreach (array_keys($this->item_list) as $item) { 270 if (strtolower($item) == strtolower($path)) { 271 return $this->item_list[$item]; 272 } 273 } 274 275 return null; 276 } 277 278 /** 279 * @param $id 280 * @return bool|ilCloudFileNode 281 */ 282 public function getNodeFromId($id) 283 { 284 return $this->item_list[$this->id_to_path_map[$id]]; 285 } 286 287 /** 288 * @param $path 289 * @throws ilCloudException 290 */ 291 public function setLoadingOfFolderComplete($path) 292 { 293 $node = $this->getNodeFromPath($path); 294 if (!$node) { 295 throw new ilCloudException(ilCloudException::PATH_DOES_NOT_EXIST_IN_FILE_TREE_IN_SESSION, $path); 296 } 297 $node->setLoadingComplete(true); 298 } 299 300 /** 301 * @param $current_path 302 */ 303 public function updateFileTree($current_path) 304 { 305 $node = $this->getNodeFromPath($current_path); 306 307 if (!$node) { 308 $this->updateFileTree(dirname($current_path)); 309 $node = $this->getNodeFromPath($current_path); 310 } 311 if (!$node->getLoadingComplete()) { 312 $this->addItemsFromService($node->getId()); 313 } 314 $this->storeFileTreeToSession(); 315 } 316 317 318 /** 319 * @param $folder_id 320 * 321 * @throws ilCloudException 322 */ 323 public function addItemsFromService($folder_id) 324 { 325 try { 326 $node = $this->getNodeFromId($folder_id); 327 if (!$node) { 328 throw new ilCloudException(ilCloudException::ID_DOES_NOT_EXIST_IN_FILE_TREE_IN_SESSION, $folder_id); 329 } 330 $service = ilCloudConnector::getServiceClass($this->getServiceName(), $this->getId()); 331 if (!$service->addToFileTreeWithId($this, $node->getId())) { 332 $service->addToFileTree($this, $node->getPath()); 333 } 334 } catch (Exception $e) { 335 if ($e instanceof ilCloudException) { 336 throw $e; 337 } 338 throw new ilCloudException(ilCloudException::ADD_ITEMS_FROM_SERVICE_FAILED, $e->getMessage()); 339 } 340 } 341 342 343 /** 344 * @param $id 345 * @param $folder_name 346 * 347 * @return bool|ilCloudFileNode|null 348 * @throws ilCloudException 349 */ 350 public function addFolderToService($id, $folder_name) 351 { 352 try { 353 if ($folder_name == null) { 354 throw new ilCloudException(ilCloudException::INVALID_INPUT, $folder_name); 355 } 356 $current_node = $this->getNodeFromId($id); 357 $path = ilCloudUtil::joinPaths($current_node->getPath(), ilCloudUtil::normalizePath($folder_name)); 358 359 if ($this->getNodeFromPath($path) != null) { 360 throw new ilCloudException(ilCloudException::FOLDER_ALREADY_EXISTING_ON_SERVICE, $folder_name); 361 } 362 363 364 $current_node->setLoadingComplete(false); 365 $this->storeFileTreeToSession(); 366 367 $service = ilCloudConnector::getServiceClass($this->getServiceName(), $this->getId()); 368 369 $new_folder_id = $service->createFolderById($id, $folder_name); 370 $new_node = null; 371 372 if (is_null($new_folder_id) || !$new_folder_id) { 373 // Use path 374 $service->createFolder($path, $this); 375 $this->addItemsFromService($current_node->getId()); 376 $new_path = ilCloudUtil::joinPaths($current_node->getPath(), $folder_name); 377 $new_node = $this->getNodeFromPath($new_path); 378 } else { 379 // Use id 380 $this->addItemsFromService($current_node->getId()); 381 $new_node = $this->getNodeFromId($new_folder_id); 382 } 383 384 return $new_node; 385 } catch (Exception $e) { 386 if ($e instanceof ilCloudException) { 387 throw $e; 388 } 389 throw new ilCloudException(ilCloudException::FOLDER_CREATION_FAILED, $e->getMessage()); 390 } 391 } 392 393 394 /** 395 * @param $current_id 396 * @param $tmp_name 397 * @param $file_name 398 * 399 * @throws ilCloudException 400 */ 401 public function uploadFileToService($current_id, $tmp_name, $file_name) 402 { 403 $plugin = ilCloudConnector::getPluginClass($this->getServiceName(), $this->getId()); 404 $max_file_size = $plugin->getMaxFileSize(); 405 406 if ($max_file_size >= filesize($tmp_name) / (1024 * 1024)) { 407 $current_node = $this->getNodeFromId($current_id); 408 409 $current_node->setLoadingComplete(false); 410 $this->storeFileTreeToSession(); 411 412 try { 413 $service = ilCloudConnector::getServiceClass($this->getServiceName(), $this->getId()); 414 if (!$service->putFileById($tmp_name, $file_name, $current_node->getId(), $this)) { 415 $service->putFile($tmp_name, $file_name, $current_node->getPath(), $this); 416 } 417 } catch (Exception $e) { 418 if ($e instanceof ilCloudException) { 419 throw $e; 420 } 421 throw new ilCloudException(ilCloudException::UPLOAD_FAILED, $e->getMessage()); 422 } 423 } else { 424 throw new ilCloudException(ilCloudException::UPLOAD_FAILED_MAX_FILESIZE, filesize($tmp_name) / (1024 * 1024) . " MB"); 425 } 426 } 427 428 /** 429 * @param $id 430 * @throws ilCloudException 431 */ 432 public function deleteFromService($id) 433 { 434 $item_node = $this->getNodeFromId($id); 435 436 try { 437 $service = ilCloudConnector::getServiceClass($this->getServiceName(), $this->getId()); 438 439 if (!$service->deleteItemById($item_node->getId())) { 440 $service->deleteItem($item_node->getPath(), $this); 441 } 442 443 $this->removeNode($item_node->getPath()); 444 $this->storeFileTreeToSession(); 445 } catch (Exception $e) { 446 if ($e instanceof ilCloudException) { 447 throw $e; 448 } 449 throw new ilCloudException(ilCloudException::DELETE_FAILED, $e->getMessage()); 450 } 451 } 452 453 /** 454 * @param $id 455 * @throws ilCloudException 456 */ 457 public function downloadFromService($id) 458 { 459 try { 460 $service = ilCloudConnector::getServiceClass($this->getServiceName(), $this->getId()); 461 $node = $this->getNodeFromId($id); 462 463 if (!$service->getFileById($node->getId())) { 464 $service->getFile($node->getPath(), $this); 465 } 466 } catch (Exception $e) { 467 if ($e instanceof ilCloudException) { 468 throw $e; 469 } 470 throw new ilCloudException(ilCloudException::DOWNLOAD_FAILED, $e->getMessage()); 471 } 472 } 473 474 public function storeFileTreeToSession() 475 { 476 $_SESSION['ilCloudFileTree'] = null; 477 $_SESSION['ilCloudFileTree'] = serialize($this); 478 } 479 480 /** 481 * @return ilCloudFileTree fileTree; 482 */ 483 public static function getFileTreeFromSession() 484 { 485 if (isset($_SESSION['ilCloudFileTree'])) { 486 return unserialize($_SESSION['ilCloudFileTree']); 487 } else { 488 return false; 489 } 490 } 491 492 493 public static function clearFileTreeSession() 494 { 495 $_SESSION['ilCloudFileTree'] = null; 496 } 497 498 /** 499 * @param $path1 500 * @param $path2 501 * @return int 502 */ 503 public function orderListAlphabet($path1, $path2) 504 { 505 $node1 = $this->getNodeFromPath($path1); 506 $node2 = $this->getNodeFromPath($path2); 507 if ($node1->getIsDir() != $node2->getIsDir()) { 508 return $node2->getIsDir() ? +1 : -1; 509 } 510 $nameNode1 = strtolower(basename($node1->getPath())); 511 $nameNode2 = strtolower(basename($node2->getPath())); 512 return ($nameNode1 > $nameNode2) ? +1 : -1; 513 } 514 515 /** 516 * @param ilCloudFileNode $node 517 * @return array|null 518 */ 519 public function getSortedListOfChildren(ilCloudFileNode $node) 520 { 521 $children = $node->getChildrenPathes(); 522 usort($children, array("ilCloudFileTree", "orderListAlphabet")); 523 return $children; 524 } 525 526 /** 527 * @return array 528 */ 529 public function getListForJSONEncode() 530 { 531 $list = array(); 532 foreach ($this->getItemList() as $path => $node) { 533 $list[$node->getId()] = $node->getJSONEncode(); 534 } 535 return $list; 536 } 537} 538