$item) { if (!in_array($item, array(".",".."))) { $nameParts = self::getStringParts($item); $fileType = array_pop($nameParts); if($fileType == 'md' OR $fileType == 'txt' ) { $folderContent[] = $item; } } } return $folderContent; } /* * scans content of a folder recursively * vars: folder path as string * returns: multi-dimensional array with names of folders and files */ public static function scanFolder($folderPath, $draft = false) { $folderItems = scandir($folderPath); $folderContent = array(); # if it is the live version and if it is a folder that is not published, then do not show the folder and its content. if(!$draft && !in_array('index.md', $folderItems)){ return false; } foreach ($folderItems as $key => $item) { if (!in_array($item, array(".",".."))) { if (is_dir($folderPath . DIRECTORY_SEPARATOR . $item)) { $subFolder = $item; $folderPublished = file_exists($folderPath . DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . 'index.md'); # scan that folder only if it is a draft or if the folder is published (contains index.md) if($draft OR $folderPublished) { $folderContent[$subFolder] = self::scanFolder($folderPath . DIRECTORY_SEPARATOR . $subFolder, $draft); } } else { $nameParts = self::getStringParts($item); $fileType = array_pop($nameParts); if($fileType == 'md') { $folderContent[] = $item; } if($draft === true && $fileType == 'txt') { if(isset($last) && ($last == implode($nameParts)) ) { array_pop($folderContent); $item = $item . 'md'; } $folderContent[] = $item; } /* store the name of the last file */ $last = implode($nameParts); } } } return $folderContent; } /* * Transforms array of folder item into an array of item-objects with additional information for each item * vars: multidimensional array with folder- and file-names * returns: array of objects. Each object contains information about an item (file or folder). */ public static function getFolderContentDetails(array $folderContent, $extended, $baseUrl, $fullSlugWithFolder = NULL, $fullSlugWithoutFolder = NULL, $fullPath = NULL, $keyPath = NULL, $chapter = NULL) { $contentDetails = []; $iteration = 0; $chapternr = 1; foreach($folderContent as $key => $name) { $item = new \stdClass(); if(is_array($name)) { $nameParts = self::getStringParts($key); $fileType = ''; if(in_array('index.md', $name)) { $fileType = 'md'; $status = 'published'; } if(in_array('index.txt', $name)) { $fileType = 'txt'; $status = 'unpublished'; } if(in_array('index.txtmd', $name)) { $fileType = 'txt'; $status = 'modified'; } $item->originalName = $key; $item->elementType = 'folder'; $item->contains = self::getFolderContentType($name, $fullPath . DIRECTORY_SEPARATOR . $key . DIRECTORY_SEPARATOR . 'index.yaml'); $item->status = $status; $item->fileType = $fileType; $item->order = count($nameParts) > 1 ? array_shift($nameParts) : NULL; $item->name = implode(" ",$nameParts); $item->name = iconv(mb_detect_encoding($item->name, mb_detect_order(), true), "UTF-8", $item->name); $item->slug = implode("-",$nameParts); $item->slug = URLify::filter(iconv(mb_detect_encoding($item->slug, mb_detect_order(), true), "UTF-8", $item->slug)); $item->path = $fullPath . DIRECTORY_SEPARATOR . $key; $item->pathWithoutType = $fullPath . DIRECTORY_SEPARATOR . $key . DIRECTORY_SEPARATOR . 'index'; $item->urlRelWoF = $fullSlugWithoutFolder . '/' . $item->slug; $item->urlRel = $fullSlugWithFolder . '/' . $item->slug; $item->urlAbs = $baseUrl . $fullSlugWithoutFolder . '/' . $item->slug; $item->key = $iteration; $item->keyPath = isset($keyPath) ? $keyPath . '.' . $iteration : $iteration; $item->keyPathArray = explode('.', $item->keyPath); $item->chapter = $chapter ? $chapter . '.' . $chapternr : $chapternr; $item->active = false; $item->activeParent = false; $item->hide = false; # check if there are extended information if($extended && isset($extended[$item->urlRelWoF])) { $item->name = ($extended[$item->urlRelWoF]['navtitle'] != '') ? $extended[$item->urlRelWoF]['navtitle'] : $item->name; $item->hide = ($extended[$item->urlRelWoF]['hide'] === true) ? true : false; } # sort posts in descending order if($item->contains == "posts") { rsort($name); } $item->folderContent = self::getFolderContentDetails($name, $extended, $baseUrl, $item->urlRel, $item->urlRelWoF, $item->path, $item->keyPath, $item->chapter); } else { # do not use files in base folder (only folders are allowed) # if(!isset($keyPath)) continue; # do not use index files if($name == 'index.md' || $name == 'index.txt' || $name == 'index.txtmd' ) continue; $nameParts = self::getStringParts($name); $fileType = array_pop($nameParts); $nameWithoutType = self::getNameWithoutType($name); if($fileType == 'md') { $status = 'published'; } elseif($fileType == 'txt') { $status = 'unpublished'; } else { $fileType = 'txt'; $status = 'modified'; } $item->originalName = $name; $item->elementType = 'file'; $item->status = $status; $item->fileType = $fileType; $item->order = count($nameParts) > 1 ? array_shift($nameParts) : NULL; $item->name = implode(" ",$nameParts); $item->name = iconv(mb_detect_encoding($item->name, mb_detect_order(), true), "UTF-8", $item->name); $item->slug = implode("-",$nameParts); $item->slug = URLify::filter(iconv(mb_detect_encoding($item->slug, mb_detect_order(), true), "UTF-8", $item->slug)); $item->path = $fullPath . DIRECTORY_SEPARATOR . $name; $item->pathWithoutType = $fullPath . DIRECTORY_SEPARATOR . $nameWithoutType; $item->key = $iteration; $item->keyPath = isset($keyPath) ? $keyPath . '.' . $iteration : $iteration; $item->keyPathArray = explode('.',$item->keyPath); $item->chapter = $chapter . '.' . $chapternr; $item->urlRelWoF = $fullSlugWithoutFolder . '/' . $item->slug; $item->urlRel = $fullSlugWithFolder . '/' . $item->slug; $item->urlAbs = $baseUrl . $fullSlugWithoutFolder . '/' . $item->slug; $item->active = false; $item->activeParent = false; $item->hide = false; # check if there are extended information if($extended && isset($extended[$item->urlRelWoF])) { $item->name = ($extended[$item->urlRelWoF]['navtitle'] != '') ? $extended[$item->urlRelWoF]['navtitle'] : $item->name; $item->hide = ($extended[$item->urlRelWoF]['hide'] === true) ? true : false; } } $iteration++; $chapternr++; $contentDetails[] = $item; } return $contentDetails; } public static function getFolderContentType($folder, $yamlpath) { # check if folder is empty or has only index.yaml-file. This is a rare case so make it quick and dirty if(count($folder) == 1) { # check if in folder yaml file contains "posts", then return posts $folderyamlpath = getcwd() . DIRECTORY_SEPARATOR . 'content' . DIRECTORY_SEPARATOR . $yamlpath; $fileContent = false; if(file_exists($folderyamlpath)) { $fileContent = file_get_contents($folderyamlpath); } if($fileContent && strpos($fileContent, 'contains: posts') !== false) { return 'posts'; } return 'pages'; } else { $file = $folder[0]; $nameParts = self::getStringParts($file); $order = count($nameParts) > 1 ? array_shift($nameParts) : NULL; $order = substr($order, 0, 7); if(\DateTime::createFromFormat('Ymd', $order) !== FALSE) { return "posts"; } else { return "pages"; } } } public static function getItemForUrl($folderContentDetails, $url, $baseUrl, $result = NULL) { # if we are on the homepage if($url == '/' OR $url == $baseUrl) { # return a standard item-object $item = new \stdClass; $item->elementType = 'folder'; $item->path = ''; $item->urlRel = '/'; $item->pathWithoutType = DIRECTORY_SEPARATOR . 'index'; return $item; } foreach($folderContentDetails as $key => $item) { # set item active, needed to move item in navigation if($item->urlRel === $url) { $item->active = true; $result = $item; } elseif($item->elementType === "folder") { $result = self::getItemForUrl($item->folderContent, $url, $baseUrl, $result); } } return $result; } public static function getPagingForItem($content, $item) { $keyPos = count($item->keyPathArray)-1; $thisChapArray = $item->keyPathArray; $nextItemArray = $item->keyPathArray; $prevItemArray = $item->keyPathArray; $item->thisChapter = false; $item->prevItem = false; $item->nextItem = false; /************************ * ADD THIS CHAPTER * ************************/ if($keyPos > 0) { array_pop($thisChapArray); $item->thisChapter = self::getItemWithKeyPath($content, $thisChapArray); } /************************ * ADD NEXT ITEM * ************************/ if($item->elementType == 'folder') { /* get the first element in the folder */ $item->nextItem = isset($item->folderContent[0]) ? clone($item->folderContent[0]) : false; } if(!$item->nextItem) { $nextItemArray[$keyPos]++; $item->nextItem = self::getItemWithKeyPath($content, $nextItemArray); } while(!$item->nextItem) { array_pop($nextItemArray); if(empty($nextItemArray)) break; $newKeyPos = count($nextItemArray)-1; $nextItemArray[$newKeyPos]++; $item->nextItem = self::getItemWithKeyPath($content, $nextItemArray); } /************************ * ADD PREVIOUS ITEM * ************************/ if($prevItemArray[$keyPos] > 0) { $prevItemArray[$keyPos]--; $item->prevItem = self::getItemWithKeyPath($content, $prevItemArray); if($item->prevItem && $item->prevItem->elementType == 'folder' && !empty($item->prevItem->folderContent)) { /* get last item in folder */ $item->prevItem = self::getLastItemOfFolder($item->prevItem); } } else { $item->prevItem = $item->thisChapter; } if($item->prevItem && $item->prevItem->elementType == 'folder'){ unset($item->prevItem->folderContent); } if($item->nextItem && $item->nextItem->elementType == 'folder'){ unset($item->nextItem->folderContent); } if($item->thisChapter){unset($item->thisChapter->folderContent); } return $item; } /* * Gets a copy of an item with a key * @param array $content with the full structure of the content as multidimensional array * @param array $searchArray with the key as a one-dimensional array like array(0,3,4) * @return array $item */ public static function getItemWithKeyPath($content, array $searchArray) { $item = false; foreach($searchArray as $key => $itemKey) { $item = isset($content[$itemKey]) ? clone($content[$itemKey]) : false; unset($searchArray[$key]); if(!empty($searchArray) && $item) { return self::getItemWithKeyPath($item->folderContent, $searchArray); } } return $item; } # https://www.quora.com/Learning-PHP-Is-there-a-way-to-get-the-value-of-multi-dimensional-array-by-specifying-the-key-with-a-variable # NOT IN USE public static function getItemWithKeyPathNew($array, array $keys) { $item = $array; foreach ($keys as $key) { $item = isset($item[$key]->folderContent) ? $item[$key]->folderContent : $item[$key]; } return $item; } /* * Extracts an item with a key https://stackoverflow.com/questions/52097092/php-delete-value-of-array-with-dynamic-key * @param array $content with the full structure of the content as multidimensional array * @param array $searchArray with the key as a one-dimensional array like array(0,3,4) * @return array $item * NOT IN USE ?? */ public static function extractItemWithKeyPath($structure, array $keys) { $result = &$structure; $last = array_pop($keys); foreach ($keys as $key) { if(isset($result[$key]->folderContent)) { $result = &$result[$key]->folderContent; } else { $result = &$result[$key]; } } $item = $result[$last]; unset($result[$last]); return array('structure' => $structure, 'item' => $item); } # NOT IN USE public static function deleteItemWithKeyPath($structure, array $keys) { $result = &$structure; $last = array_pop($keys); foreach ($keys as $key) { if(isset($result[$key]->folderContent)) { $result = &$result[$key]->folderContent; } else { $result = &$result[$key]; } } $item = $result[$last]; unset($result[$last]); return $structure; } /* get breadcrumb as copied array, set elements active in original and mark parent element in original */ public static function getBreadcrumb($content, $searchArray, $i = NULL, $breadcrumb = NULL) { # if it is the first round, create an empty array if(!$i){ $i = 0; $breadcrumb = array();} while($i < count($searchArray)) { $item = $content[$searchArray[$i]]; if($i == count($searchArray)-1) { $item->active = true; } else { $item->activeParent = true; } /* $item->active = true; if($i == count($searchArray)-2) { $item->activeParent = true; } */ $copy = clone($item); if($copy->elementType == 'folder') { unset($copy->folderContent); $content = $item->folderContent; } $breadcrumb[] = $copy; $i++; return self::getBreadcrumb($content, $searchArray, $i++, $breadcrumb); } return $breadcrumb; } public static function getParentItem($content, $searchArray, $iteration = NULL) { if(!$iteration){ $iteration = 0; } while($iteration < count($searchArray)-2) { $content = $content[$searchArray[$iteration]]->folderContent; $iteration++; return self::getParentItem($content, $searchArray, $iteration); } return $content[$searchArray[$iteration]]; } private static function getLastItemOfFolder($folder) { $lastItem = end($folder->folderContent); if(is_object($lastItem) && $lastItem->elementType == 'folder' && !empty($lastItem->folderContent)) { return self::getLastItemOfFolder($lastItem); } return $lastItem; } public static function getStringParts($name) { return preg_split('/[\-\.\_\=\+\?\!\*\#\(\)\/ ]/',$name); } public static function getFileType($fileName) { $parts = preg_split('/\./',$fileName); return end($parts); } public static function splitFileName($fileName) { $parts = preg_split('/\./',$fileName); return $parts; } public static function getNameWithoutType($fileName) { $parts = preg_split('/\./',$fileName); return $parts[0]; } }