postprefix
6/13/2011 - 4:44 AM

stacey-partials-v2.php

<?php
Class Page {

	var $template;
	var $partials;
	
	#
	# This faked data will be dynamically created (by searching through and parsing the /content folder) and stored within the Page class
	#
	var $data = array(
		'/$false/' => false,
		'/$true/' => true,
		'/$pages/' => array(
			array(
				'/$name/' => 'About',
				'/$url/' => './about-me/',
				'/$children/' => false
			),
			array(
				'/$name/' => 'Contact',
				'/$url/' => './contact/',
				'/$children/' => false
			)
		),
		'/$category_list/' => array(
			array(
				'/$name/' => 'Projects',
				'/$url/' => './projects/',
				'/$children/' => array(
					array(
						'/$name/' => 'Project 1',
						'/$url/' => './projects/project-1',
						'/$children/' => false
					),
					array(
						'/$name/' => 'Project 2',
						'/$url/' => './projects/project-2',
						'/$children/' => array(
							array(
								'/$name/' => 'Project 2 Movies',
								'/$url/' => './projects/project-2/movies/',
								'/$children/' => array(
									array(
										'/$name/' => 'Distant child',
										'/$url/' => './projects/project-2/movies/long-lost-child'
									),
									array(
										'/$name/' => 'Help, I am alive too!',
										'/$url/' => './projects/project-2/movies/im-alive/'
									)
								)
							),
							array(
								'/$name/' => 'Project 2 Flash Animations',
								'/$url/' => './projects/project-2/swfs/',
								'/$children/' => array(
									array(
										'/$name/' => 'Project 2 Flash Animation 1',
										'/$url/' => './projects/project-2/swfs/swf1.swf',
										'/$children/' => false
									)
								)
							)
						)
					)
				)
			),
			array(
				'/$name/' => 'Blog',
				'/$url/' => './blog/',
				'/$children/' => array(
					array(
						'/$name/' => 'Entry 1',
						'/$url/' => './blog/entry-1',
						'/$children/' => false
					)
				)
			)
		)
	);
	
	function __construct() {
		# store fake templates
		$this->template = $GLOBALS['template'];
		# store fake partials
		$this->partials = $GLOBALS['partials'];
		$this->render();
	}
	
	static function content_vars($content) {
		$replacement_pairs = array();
		# extract key/values from content file
		preg_match_all('/[\w\d_-]+?:[\S\s]*?\n\n/', $content, $matches);
		foreach($matches[0] as $match) {
			$colon_split = explode(':', $match);
			$replacement_pairs['/@'.$colon_split[0].'/'] = trim($colon_split[1]);
		}
		return $replacement_pairs;
	}
	
	function render() {
		
		#
		# This section fakes stacey's content file parser
		#
		
		# pull out each key/value pair from the content file and combine with the Faked page data
		$data = array_merge($this->data, $this->content_vars($GLOBALS['content_file']."\n\n"));
		
		# replace standard content variables
		$parsed_content = Partial::parse($data, $this->template);
		
		# render final output
		echo $parsed_content;
	}
	
}

Class Partial {
	
	static function get_partial_template($name) {
		return (isset($GLOBALS['partials'][$name])) ? $GLOBALS['partials'][$name] : '\'/templates/partials/'.$name.'.html\' not found';
		// return (file_exists('../templates/partials'.$name.'.html')) ? file_get_contents('../templates/partials'.$name.'.html') : '\'/templates/partials/'.$name.'.html\' not found';
	}
	
	static function parse($data, $template) {
		$template = Partial::parse_if($data, $template);
		$template = Partial::parse_foreach($data, $template);
		$template = Partial::parse_includes($data, $template);
		$template = Partial::parse_vars($data, $template);
		return $template;
	}
	
	static function parse_if($data, $template) {
 
		# match any inner if statements
		preg_match('/([\S\s]*?)if\s+?(\$.+?)\?\s+?do([\S\s]+?)endif([\S\s]*)$/', $template, $template_parts);
		
		if(!empty($template_parts)) {
			# Run the replacements on the pre-"if" part of the partial
			$template = Partial::parse($data, $template_parts[1]);
			
			# If the condition is true
			if(isset($data['/'.$template_parts[2].'/']) && ($data['/'.$template_parts[2].'/'])) {
				# Parse the block inside the if statement
				$template .= Partial::parse($data, $template_parts[3]);
			} 
			
			# Run the replacements on the post-"if" part of the partial
			$template .= Partial::parse($data, $template_parts[4]);
			
		}
		return $template;
	}
	
	static function parse_foreach($data, $template) {
		# Split out the partial into the parts Before, Inside, and After the foreach loop
		preg_match('/([\S\s]*?)foreach[\s]+?(\$.+?)[\s]+?do([\S\s]+)end([\S\s]*)$/', $template, $template_parts);
		if(!empty($template_parts)) {
			# Run the replacements on the pre-"foreach" part of the partial
			$template = Partial::parse($data, $template_parts[1]);
			
			# Traverse one level deeper into the data hierachy
			$pages = $data['/'.$template_parts[2].'/'];
			if ($pages) {
				foreach ($pages as $data_item) {
					# Recursively parse the inside part of the foreach loop
					$template .= Partial::parse($data_item, $template_parts[3]);
				}
			}
			
			# Run the replacements on the post-"foreach" part of the partial
			$template .= Partial::parse($data, $template_parts[4]);	
		}
		return $template;
	}
	
	static function parse_includes($data, $template) {
		# Split out the partial into the parts Before, Inside, and After the :include
		preg_match('/([\S\s]*?):([\w\d-_]+?)(\.html)?\b([\S\s]*)$/', $template, $template_parts);
		
		###### TODO: There is no protection against endless loops due to circular inclusions
		if (!empty($template_parts)) {
			# Run the replacements on the pre-":include" part of the partial
			$template = Partial::parse($data, $template_parts[1]);

			# Parse the included template
			$inner_template = Partial::get_partial_template($template_parts[2]);
			$template .= Partial::parse($data, $inner_template);
			
			# Run the replacements on the post-":include" part of the partial
			$template .= Partial::parse($data, $template_parts[4]);
		}
		return $template;
	}
	
	static function parse_vars($data, $template) {
		# Split out the partial into the parts Before, Inside, and After the @var
		preg_match('/([\S\s]*?)([\@\$][\w\d-_]+?)\b([\S\s]*)$/', $template, $template_parts);
		
		if (!empty($template_parts)) {
			# Run the replacements on the pre-"@var" part of the partial
			$template = Partial::parse($data, $template_parts[1]);

			# Replace the @var
			$var = $data['/'.$template_parts[2].'/'];
			if ($var && is_string($var)) {
				$template .= $var;
			}
			
			# Run the replacements on the post-"@var" part of the partial
			$template .= Partial::parse($data, $template_parts[3]);
		}
		return $template;
		
	}
	
	
}

# ----------------------------------------------------------

#
#
#	Faked Content file
#
#

$content_file = <<<EOS

title: Stacey, new partials (proof of concept)

EOS;

#
#
#	Faked Template
#
#

$template = <<<EOS
<html>
	<head>
		<title>@title</title>
	</head>
	<body>
	<h1>@title</h1>
		<div id="container">
			<hr>
			:pages
			<hr>
			:category_list
			<hr>
			:non_existant_partial
			<hr>
			if \$true? do
				:footer.html
			endif
		</div>
	</body>
</html>
EOS;

#
#
#	Faked Partials
#
#

$pages_partial_html = <<<EOS
<ol id="wrapper">
foreach \$pages do
	<li>:link</li>
end
</ol>
EOS;

$categories_partial_html = <<<EOS
<ol id="wrapper">
foreach \$category_list do
	:link
	:children
end
</ol>
EOS;

$footer_partial_html = <<<EOS
<div id="footer">
	if \$category_list? do
		<p>Footer.</p>
	endif

	if \$images? do
		<p>show images here</p>
	endif
</div>
EOS;

$link_partial_html = <<<EOS
<a class="page-link" href="\$url">\$name</a>
EOS;

$children_partial_html = <<<EOS
if \$children? do
	<ol class="children" title="Children of \$url">
	foreach \$children do
		<li>
			:link
			:children
		</li>
	end
	</ol>
endif
EOS;

#
# This variable will be created by looping through each file within /templates/partials
#
$partials = array(
	'pages' => $pages_partial_html,
	'category_list' => $categories_partial_html,
	'footer' => $footer_partial_html,
	'children' => $children_partial_html,
	'link' => $link_partial_html
);

#
#
#	Init
#
#

$p = new Page;

?>