Created
April 13, 2020 04:01
-
-
Save frumbert/f91133e5ccf9b48287045e9390934528 to your computer and use it in GitHub Desktop.
Sort and Link to markdown files in nested sub-folders in PHP (e.g. build documentation)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
You have markdown files in nested folders which comtain | |
--01.getting-started | |
| | | |
| +--02.finalisation | |
| | | | |
| | docs.md | |
| | picture.png | |
| | | |
| +--01.installation | |
| | | |
| docs.md | |
| readme.txt | |
| media.jpg | |
| | |
|--02.profit | |
| | | |
| +--01.set-up | |
| | | |
| docs.md | |
| | |
+--intro.md | |
You want | |
<ol> | |
<li><a href='intro.md'>Getting Started</a> | |
<ol> | |
<li><a href='01.getting-started/01.installation/docs.md'>Getting Started</a></li> | |
<li><a href='01.getting-started/02.finalisation/docs.md'>Finalisation</a></li> | |
</ol> | |
<li>Profit | |
<ol> | |
<li><a href='02.profit/01.set-up/docs.md'>Set Up</a></li> | |
</ol> | |
</li> | |
</ol> | |
This script will do that efficiently using recursive directory iterators, regular expression iterators, sorting iterators, and array manipulation | |
Not shown here: Caching | |
*/ | |
$documentation_root = '.'; | |
// sort each item in an iterator by name | |
class ExampleSortedIterator extends SplHeap | |
{ | |
public function __construct(Iterator $iterator) | |
{ | |
foreach ($iterator as $item) { | |
$this->insert($item); | |
} | |
} | |
public function compare($b,$a) | |
{ | |
return strcmp($a->getRealpath(), $b->getRealpath()); | |
} | |
} | |
// list all files recursively, skipping dotfiles, and sort each directory by name | |
$rii = new ExampleSortedIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($documentation_root, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS))); | |
// set up output array | |
$files = array(); | |
// go through each sorted file | |
foreach ($rii as $file) { | |
// skip non-markdown files | |
if (strpos($file->getFilename(), ".md") === false) continue; | |
$name = substr($file->getPathname(), 2); | |
// turn 01.folder-name/01.sub-folder-name/docs.md into [01.folder-name, 01.sub-folder-name, docs.md] | |
$parts = explode('/',$name); | |
// create a reference to the output array | |
$current = &$files; | |
foreach ($parts as $key) { | |
// the reference is itself a reference with the key set as the step of the array | |
// each item in parts becomes an array with that name as a key | |
$current = &$current[$key]; | |
} | |
// $rii is now collapsed into a nested sorted array with null-terminated leaf nodes | |
} | |
function render($ol, $path_to_here = '.') { | |
$result = []; | |
foreach ($ol as $key => $value) { | |
// if the value is null then we are somehow inside a leaf node (could throw exception) | |
if (is_null($value)) continue; | |
// turn "02.some-label-value" into "Some Label Value" | |
$label = ucwords(str_replace('-',' ', preg_replace('/^\d{1,}\./', '',$key))); | |
// look in this value to see if there's a leaf node | |
// link to the leaf node, or just render the label | |
$link = ''; | |
foreach ($value as $branch => $leaf) { | |
if (is_null($leaf)) { | |
$link = $branch; | |
break; | |
} | |
} | |
$result[] = "<li>"; | |
if (empty($link)) { | |
$result[] = $label; | |
} else { | |
$result[] = "<a href='?url={$path_to_here}/{$key}/{$link}'>{$label}</a>"; | |
} | |
$children = render($value, $path_to_here . '/' . $key); | |
if (!empty($children)) { | |
$result[] = "<ol>"; | |
$result = array_merge($result, $children); | |
$result[] = "</ol>"; | |
} | |
$result[] = "</li>" . PHP_EOL; | |
} | |
return $result; | |
} | |
$output = render($files); | |
echo "<ol>", PHP_EOL; | |
echo implode('', $output); | |
echo "</ol>", PHP_EOL; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment