Folder.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. namespace Typemill\Models;
  3. use \URLify;
  4. class Folder
  5. {
  6. /*
  7. * scans content of a folder recursively
  8. * vars: folder path as string
  9. * returns: multi-dimensional array with names of folders and files
  10. */
  11. public static function scanFolder($folderPath, $draft = false)
  12. {
  13. $folderItems = scandir($folderPath);
  14. $folderContent = array();
  15. foreach ($folderItems as $key => $item)
  16. {
  17. if (!in_array($item, array(".","..")))
  18. {
  19. if (is_dir($folderPath . DIRECTORY_SEPARATOR . $item))
  20. {
  21. /* TODO: if folder is empty or folder has only txt files, continue */
  22. $subFolder = $item;
  23. $folderContent[$subFolder] = self::scanFolder($folderPath . DIRECTORY_SEPARATOR . $subFolder, $draft);
  24. }
  25. else
  26. {
  27. $nameParts = self::getStringParts($item);
  28. $fileType = array_pop($nameParts);
  29. if($fileType == 'md')
  30. {
  31. $folderContent[] = $item;
  32. }
  33. if($draft === true && $fileType == 'txt')
  34. {
  35. if(isset($last) && ($last == implode($nameParts)) )
  36. {
  37. array_pop($folderContent);
  38. }
  39. $folderContent[] = $item;
  40. }
  41. /* store the name of the last file */
  42. $last = implode($nameParts);
  43. }
  44. }
  45. }
  46. return $folderContent;
  47. }
  48. /*
  49. * Transforms array of folder item into an array of item-objects with additional information for each item
  50. * vars: multidimensional array with folder- and file-names
  51. * returns: array of objects. Each object contains information about an item (file or folder).
  52. */
  53. public static function getFolderContentDetails(array $folderContent, $baseUrl, $fullSlugWithFolder = NULL, $fullSlugWithoutFolder = NULL, $fullPath = NULL, $keyPath = NULL, $chapter = NULL)
  54. {
  55. $contentDetails = [];
  56. $iteration = 0;
  57. $chapternr = 1;
  58. foreach($folderContent as $key => $name)
  59. {
  60. $item = new \stdClass();
  61. if(is_array($name))
  62. {
  63. $nameParts = self::getStringParts($key);
  64. $item->originalName = $key;
  65. $item->elementType = 'folder';
  66. $item->index = array_search('index.md', $name) === false ? false : true;
  67. $item->order = count($nameParts) > 1 ? array_shift($nameParts) : NULL;
  68. $item->name = implode(" ",$nameParts);
  69. $item->name = iconv(mb_detect_encoding($item->name, mb_detect_order(), true), "UTF-8", $item->name);
  70. $item->slug = implode("-",$nameParts);
  71. $item->slug = URLify::filter(iconv(mb_detect_encoding($item->slug, mb_detect_order(), true), "UTF-8", $item->slug));
  72. $item->path = $fullPath . DIRECTORY_SEPARATOR . $key;
  73. $item->urlRelWoF = $fullSlugWithoutFolder . '/' . $item->slug;
  74. $item->urlRel = $fullSlugWithFolder . '/' . $item->slug;
  75. $item->urlAbs = $baseUrl . $fullSlugWithoutFolder . '/' . $item->slug;
  76. $item->key = $iteration;
  77. $item->keyPath = isset($keyPath) ? $keyPath . '.' . $iteration : $iteration;
  78. $item->keyPathArray = explode('.', $item->keyPath);
  79. $item->chapter = $chapter ? $chapter . '.' . $chapternr : $chapternr;
  80. $item->folderContent = self::getFolderContentDetails($name, $baseUrl, $item->urlRel, $item->urlRelWoF, $item->path, $item->keyPath, $item->chapter);
  81. }
  82. else
  83. {
  84. $nameParts = self::getStringParts($name);
  85. $fileType = array_pop($nameParts);
  86. # if($name == 'index.md' || $fileType !== 'md' ) continue;
  87. if($name == 'index.md' || $name == 'index.txt' ) continue;
  88. $item->originalName = $name;
  89. $item->elementType = 'file';
  90. $item->fileType = $fileType;
  91. $item->order = count($nameParts) > 1 ? array_shift($nameParts) : NULL;
  92. $item->name = implode(" ",$nameParts);
  93. $item->name = iconv(mb_detect_encoding($item->name, mb_detect_order(), true), "UTF-8", $item->name);
  94. $item->slug = implode("-",$nameParts);
  95. $item->slug = URLify::filter(iconv(mb_detect_encoding($item->slug, mb_detect_order(), true), "UTF-8", $item->slug));
  96. $item->path = $fullPath . DIRECTORY_SEPARATOR . $name;
  97. $item->key = $iteration;
  98. $item->keyPath = $keyPath . '.' . $iteration;
  99. $item->keyPathArray = explode('.',$item->keyPath);
  100. $item->chapter = $chapter . '.' . $chapternr;
  101. $item->urlRelWoF = $fullSlugWithoutFolder . '/' . $item->slug;
  102. $item->urlRel = $fullSlugWithFolder . '/' . $item->slug;
  103. $item->urlAbs = $baseUrl . $fullSlugWithoutFolder . '/' . $item->slug;
  104. }
  105. $iteration++;
  106. $chapternr++;
  107. $contentDetails[] = $item;
  108. }
  109. return $contentDetails;
  110. }
  111. public static function getItemForUrl($folderContentDetails, $url, $result = NULL)
  112. {
  113. foreach($folderContentDetails as $key => $item)
  114. {
  115. if($item->urlRel === $url)
  116. {
  117. $item->active = true;
  118. $result = $item;
  119. }
  120. elseif($item->elementType === "folder")
  121. {
  122. $result = self::getItemForUrl($item->folderContent, $url, $result);
  123. }
  124. }
  125. return $result;
  126. }
  127. public static function getPagingForItem($content, $item)
  128. {
  129. $keyPos = count($item->keyPathArray)-1;
  130. $thisChapArray = $item->keyPathArray;
  131. $nextItemArray = $item->keyPathArray;
  132. $prevItemArray = $item->keyPathArray;
  133. $item->thisChapter = false;
  134. $item->prevItem = false;
  135. $item->nextItem = false;
  136. /************************
  137. * ADD THIS CHAPTER *
  138. ************************/
  139. if($keyPos > 0)
  140. {
  141. array_pop($thisChapArray);
  142. $item->thisChapter = self::getItemWithKeyPath($content, $thisChapArray);
  143. }
  144. /************************
  145. * ADD NEXT ITEM *
  146. ************************/
  147. if($item->elementType == 'folder')
  148. {
  149. /* get the first element in the folder */
  150. $item->nextItem = isset($item->folderContent[0]) ? clone($item->folderContent[0]) : false;
  151. }
  152. if(!$item->nextItem)
  153. {
  154. $nextItemArray[$keyPos]++;
  155. $item->nextItem = self::getItemWithKeyPath($content, $nextItemArray);
  156. }
  157. while(!$item->nextItem)
  158. {
  159. array_pop($nextItemArray);
  160. if(empty($nextItemArray)) break;
  161. $newKeyPos = count($nextItemArray)-1;
  162. $nextItemArray[$newKeyPos]++;
  163. $item->nextItem = self::getItemWithKeyPath($content, $nextItemArray);
  164. }
  165. /************************
  166. * ADD PREVIOUS ITEM *
  167. ************************/
  168. if($prevItemArray[$keyPos] > 0)
  169. {
  170. $prevItemArray[$keyPos]--;
  171. $item->prevItem = self::getItemWithKeyPath($content, $prevItemArray);
  172. if($item->prevItem && $item->prevItem->elementType == 'folder' && !empty($item->prevItem->folderContent))
  173. {
  174. /* get last item in folder */
  175. $item->prevItem = self::getLastItemOfFolder($item->prevItem);
  176. }
  177. }
  178. else
  179. {
  180. $item->prevItem = $item->thisChapter;
  181. }
  182. if($item->prevItem && $item->prevItem->elementType == 'folder'){ unset($item->prevItem->folderContent); }
  183. if($item->nextItem && $item->nextItem->elementType == 'folder'){ unset($item->nextItem->folderContent); }
  184. if($item->thisChapter){unset($item->thisChapter->folderContent); }
  185. return $item;
  186. }
  187. public static function getItemWithKeyPath($content, array $searchArray)
  188. {
  189. $item = false;
  190. foreach($searchArray as $key => $itemKey)
  191. {
  192. $item = isset($content[$itemKey]) ? clone($content[$itemKey]) : false;
  193. unset($searchArray[$key]);
  194. if(!empty($searchArray) && $item)
  195. {
  196. return self::getItemWithKeyPath($item->folderContent, $searchArray);
  197. }
  198. }
  199. return $item;
  200. }
  201. /* get breadcrumb as copied array, set elements active in original and mark parent element in original */
  202. public static function getBreadcrumb($content, $searchArray, $i = NULL, $breadcrumb = NULL)
  203. {
  204. if(!$i){ $i = 0; $breadcrumb = array();}
  205. while($i < count($searchArray))
  206. {
  207. $item = $content[$searchArray[$i]];
  208. $item->active = true;
  209. if($i == count($searchArray)-2)
  210. {
  211. $item->activeParent = true;
  212. }
  213. $copy = clone($item);
  214. if($copy->elementType == 'folder')
  215. {
  216. unset($copy->folderContent);
  217. $content = $item->folderContent;
  218. }
  219. $breadcrumb[] = $copy;
  220. $i++;
  221. return self::getBreadcrumb($content, $searchArray, $i++, $breadcrumb);
  222. }
  223. return $breadcrumb;
  224. }
  225. public static function getParentItem($content, $searchArray, $iteration = NULL)
  226. {
  227. if(!$iteration){ $iteration = 0; }
  228. while($iteration < count($searchArray)-2)
  229. {
  230. $content = $content[$searchArray[$iteration]]->folderContent;
  231. $iteration++;
  232. return self::getParentItem($content, $searchArray, $iteration);
  233. }
  234. return $content[$searchArray[$iteration]];
  235. }
  236. private static function getLastItemOfFolder($folder)
  237. {
  238. $lastItem = end($folder->folderContent);
  239. if(is_object($lastItem) && $lastItem->elementType == 'folder' && !empty($lastItem->folderContent))
  240. {
  241. return self::getLastItemOfFolder($lastItem);
  242. }
  243. return $lastItem;
  244. }
  245. public static function getStringParts($name)
  246. {
  247. return preg_split('/[\-\.\_\=\+\?\!\*\#\(\)\/ ]/',$name);
  248. }
  249. public static function getFileType($fileName)
  250. {
  251. $parts = preg_split('/\./',$fileName);
  252. return end($parts);
  253. }
  254. public static function splitFileName($fileName)
  255. {
  256. $parts = preg_split('/\./',$fileName);
  257. return $parts;
  258. }
  259. }