Skip to content

Instantly share code, notes, and snippets.

@kolber
Created November 20, 2009 03:00
Show Gist options
  • Save kolber/239250 to your computer and use it in GitHub Desktop.
Save kolber/239250 to your computer and use it in GitHub Desktop.
<?php
Class Helpers {
static function sort_by_length($a,$b){
if($a == $b) return 0;
return (strlen($a) > strlen($b) ? -1 : 1);
}
static function file_path_to_url($file_path) {
return preg_replace(array('/\d+?\./', '/\.\.\/content(\/)?/'), '', $file_path);
}
static function url_to_file_path($url) {
$file_path = '../content';
// Split the url and recursively unclean the parts into folder names
$url_parts = explode('/', $url);
foreach($url_parts as $u) {
// Look for a folder at the current $path
$matches = Helpers::list_files($file_path, '/^\d+?\.'.$u.'$/', true);
// No matches means a bad url
if (empty($matches)) return false;
else $file_path .= '/'.$matches[0];
}
return $file_path;
}
static function has_children($dir) {
// check if this folder contains inner folders - if it does, then it is a category
$inner_folders = Helpers::list_files($dir, '/.*/', true);
return !empty($inner_folders);
}
static function list_files($dir, $regex, $folders_only = false) {
if(!is_dir($dir)) return array();
$glob = ($folders_only) ? glob($dir."/*", GLOB_ONLYDIR) : glob($dir."/*");
if(!$glob) return array();
// loop through each glob result and push it to $dirs if it matches the passed regexp
$files = array();
foreach($glob as $file) {
// strip out just the filename
preg_match('/\/([^\/]+?)$/', $file, $slug);
if(preg_match($regex, $slug[1])) $files[] = $slug[1];
}
// sort list in reverse-numeric order
rsort($files, SORT_NUMERIC);
return $files;
}
}
Class Page {
var $url;
var $slug;
var $parent_path;
var $file_path;
var $content_file;
var $data;
function __construct($url) {
$this->url = $url;
$this->file_path = Helpers::url_to_file_path($url);
# if file doesn't exist, throw a 404 exception
if(!file_exists($this->file_path)) throw new Exception('404. Page does not exist.');
$this->content_file = $this->content_file();
#
$split_url = explode("/", $url);
$this->slug = $split_url[count($split_url) - 1];
# $this->parent_slug = (count($split_url) > 1) ? $split_url[count($split_url) - 2] : false;
array_pop($split_url);
$this->parent_path = implode("/", $split_url);
# create content data from content file
ContentData::create($this);
# if not called from the root document, don't create additional template_data
if($this->caller()) return;
#
TemplateData::create($this);
# recursively sort data arrays by length
# uksort($template_data, array('Helpers', 'sort_by_length'));
echo '<pre>';
var_dump($this->data);
echo '</pre><br>---<br>';
}
function __call($name, $arguments) {
if(preg_match('/set(.*)/', $name, $name)) {
# convert multiple words to underscores -- a function call of setCategoryList will create the array index $category_list
$var_name = strtolower(preg_replace('/(?<=.)([A-Z])/', '_\1', $name[1]));
# save into cash_data array
$this->data['/$'.$var_name.'/'] = $arguments[0];
}
}
# magic variable assignment method
function __set($name, $value) {
$this->data['/@'.$name.'/'] = $value;
}
function caller() {
$backtrace = debug_backtrace();
return isset($backtrace[3]['class']) ? $backtrace[3]['class'] : false;
}
function content_file() {
$txts = Helpers::list_files($this->file_path, '/\.txt$/');
return (!empty($txts)) ? preg_replace('/\.txt$/', '', $txts[0]) : false;
}
}
Class ContentData {
static function preparse($text) {
$patterns = array(
// replace inline colons
'/(?<=\n)([a-z0-9_-]+?):(?!\/)/',
'/:/',
'/\\\x01/',
// replace inline dashes
'/(?<=\n)-/',
'/-/',
'/\\\x02/',
// automatically link http:// websites
'/(?<![">])\bhttp&#58;\/\/([\S]+\.[\S]*\.?[A-Za-z0-9]{2,4})/',
// automatically link email addresses
'/(?<![;>])\b([A-Za-z0-9.-]+)@([A-Za-z0-9.-]+\.[A-Za-z]{2,4})/',
// convert lists
'/\n?-(.+?)(?=\n)/',
'/(<li>.*<\/li>)/',
// replace doubled lis
'/<\/li><\/li>/',
// replace headings h1. h2. etc
'/h([0-5])\.\s?(.*)/',
// wrap multi-line text in paragraphs
'/([^\n]+?)(?=\n)/',
'/<p>(.+):(.+)<\/p>/',
'/: (.+)(?=\n<p>)/',
// replace any keys that got wrapped in ps
'/(<p>)([a-z0-9_-]+):(<\/p>)/',
// replace any headings that got wrapped in ps
'/<p>(<h[0-5]>.*<\/h[0-5]>)<\/p>/'
);
$replacements = array(
// replace inline colons
'$1\\x01',
'&#58;',
':',
// replace inline dashes
'\\x02',
'&#45;',
'-',
// automatically link http:// websites
'<a href="http&#58;//$1">http&#58;//$1</a>',
// automatically link email addresses
'<a href="mailto&#58;$1&#64;$2">$1&#64;$2</a>',
// convert lists
'<li>$1</li>',
'<ul>$1</ul>',
// replace doubled lis
'</li>',
// replace headings h1. h2. etc
'<h$1>$2</h$1>',
// wrap multi-line text in paragraphs
'<p>$1</p>',
'$1:$2',
':<p>$1</p>',
// replace any keys that got wrapped in ps
'$2:',
'$1'
);
$parsed_text = preg_replace($patterns, $replacements, $text);
return $parsed_text;
}
static function create($page) {
## store contents of content file (if it exists, otherwise, pass back an empty string)
$content_file_path = $page->file_path.'/'.$page->content_file.'.txt';
$text = (file_exists($content_file_path)) ? file_get_contents($content_file_path) : '';
# include shared variables for each page
$shared = (file_exists('../content/_shared.txt')) ? file_get_contents('../content/_shared.txt') : '';
# run preparsing rules to clean up content files (the newlines are added to ensure the first and last rules have their double-newlines to match on)
$parsed_text = self::preparse("\n\n".$text."\n\n".$shared."\n\n");
# pull out each key/value pair from the content file
preg_match_all('/[\w\d_-]+?:[\S\s]*?\n\n/', $text, $matches);
foreach($matches[0] as $match) {
$colon_split = explode(':', $match);
# store page variables within Page::data
$page->$colon_split[0] = trim($colon_split[1]);
}
# set page name, url and thumbnail
$page->setName(ucfirst(preg_replace('/[-_](.)/e', "' '.strtoupper('\\1')", $page->slug)));
$page->setUrlPath($page->url);
# thumbnail
}
}
Class TemplateData {
static $navigation_tree;
static function extract_files() {
}
static function extract_pages() {
$pages = array();
foreach(NavigationTree::$nested_tree as &$page) if(!$page['/$children/']) $pages[] =& $page;
return $pages;
}
static function extract_categories() {
$categories = array();
foreach(NavigationTree::$nested_tree as &$page) if($page['/$children/']) $categories[] =& $page;
return $categories;
}
static function extract_siblings($pages) {
$siblings = array();
foreach($pages as $key => &$page) $siblings[$key] =& $page;
return $siblings;
}
static function extract_closest_siblings($siblings, $file_path) {
# store keys as array
$keys = array_keys($siblings);
$keyIndexes = array_flip($keys);
$neighbors = array();
# previous sibling
if (isset($keys[$keyIndexes[$file_path] - 1])) $neighbors[] = $siblings[$keys[$keyIndexes[$file_path] - 1]];
else $neighbors[] = $siblings[$keys[count($keys) - 1]];
# next sibling
if (isset($keys[$keyIndexes[$file_path] + 1])) $neighbors[] = $siblings[$keys[$keyIndexes[$file_path] + 1]];
else $neighbors[] = $siblings[$keys[0]];
return $neighbors;
}
static function create($page) {
# build navigation tree
NavigationTree::build();
# $navigation
$page->setNavigation(NavigationTree::$nested_tree);
# $pages
$page->setPages(self::extract_pages());
# $categories
$page->setCategories(self::extract_categories());
# $folder_name?
### These values are not being passed by reference (which effect memory usage unless the array item it is referencing changes after these reference are created)
# $parent
if($page->parent_path) $parent_reference = NavigationTree::$flat_tree[Helpers::url_to_file_path($page->parent_path)];
else $parent_reference = false;
$page->setParent($parent_reference);
# $children
$children_reference = (isset(NavigationTree::$flat_tree[Helpers::url_to_file_path($page->slug)]['/$children/'])) ? NavigationTree::$flat_tree[Helpers::url_to_file_path($page->slug)]['/$children/'] : false;
$page->setChildren($children_reference);
# $siblings
$siblings = ($parent_reference) ? $parent_reference['/$children/'] : self::extract_siblings(NavigationTree::$nested_tree);
$page->setSiblings($siblings);
# $next_sibling / $previous_sibling
$neighbors = self::extract_closest_siblings($siblings, $page->file_path);
$page->setPreviousSibling($neighbors[0]);
$page->setNextSibling($neighbors[1]);
###
# $images
# $video
# $media
# $.swf
# $.doc
# $.pdf
# etc.
}
}
Class NavigationTree {
static $flat_tree;
static $nested_tree;
static $replaced_data;
static function build($dir = '../content') {
# create both a nested tree and a flat tree at the same time
self::$nested_tree = self::nested_tree($dir);
return self::$nested_tree;
}
static function nested_tree($dir) {
$files = array();
foreach(Helpers::list_files($dir, '/.+/', true) as $file) {
# fill flat file array
$page = new Page(Helpers::file_path_to_url($dir.'/'.$file));
self::$flat_tree[$dir.'/'.$file] = $page->data;
# store reference to flat tree array item
$reference =& self::$flat_tree[$dir.'/'.$file];
$files[$dir.'/'.$file] = &$reference;
# recurse through any children
$files[$dir.'/'.$file]['/$children/'] = (Helpers::has_children($dir.'/'.$file)) ? self::nested_tree($dir.'/'.$file) : false;
}
return $files;
}
}
Class Stacey {
static $version = '1.1';
function __construct($get) {
# $page = new Page('about');
# $page = new Page('projects');
# $page = new Page('projects/project-name-10');
$page = new Page('projects/movie-project-2/sub-movie-project');
# $page = new Page('projects/movie-project-2/2008');
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment