| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 | <?php namespace Laravel; use FilesystemIterator as fIterator;class Blade {	/**	 * All of the compiler functions used by Blade.	 *	 * @var array	 */	protected static $compilers = array(		'layouts',		'echos',		'forelse',		'empty',		'endforelse',		'structure_openings',		'structure_closings',		'else',		'includes',		'render_each',		'render',		'yields',		'yield_sections',		'section_start',		'section_end',	);	/**	 * Register the Blade view engine with Laravel.	 *	 * @return void	 */	public static function sharpen()	{		Event::listen(View::engine, function($view)		{			// The Blade view engine should only handle the rendering of views which			// end with the Blade extension. If the given view does not, we will			// return false so the View can be rendered as normal.			if ( ! str_contains($view->path, BLADE_EXT))			{				return false;			}			$compiled = path('storage').'views/'.md5($view->path);			// If the view doesn't exist or has been modified since the last time it			// was compiled, we will recompile the view into pure PHP from it's			// Blade representation, writing it to cached storage.			if ( ! file_exists($compiled) or Blade::expired($view->view, $view->path))			{				file_put_contents($compiled, Blade::compile($view));			}			$view->path = $compiled;			// Once the view has been compiled, we can simply set the path to the			// compiled view on the view instance and call the typical "get"			// method on the view to evaluate the compiled PHP view.			return $view->get();		});	}	/**	 * Determine if a view is "expired" and needs to be re-compiled.	 *	 * @param  string  $view	 * @param  string  $path	 * @param  string  $compiled	 * @return bool	 */	public static function expired($view, $path)	{		$compiled = static::compiled($path);		return filemtime($path) > filemtime(static::compiled($path));	}	/**	 * Compiles the specified file containing Blade pseudo-code into valid PHP.	 *	 * @param  string  $path	 * @return string	 */	public static function compile($view)	{		return static::compile_string(file_get_contents($view->path), $view);	}	/**	 * Compiles the given string containing Blade pseudo-code into valid PHP.	 *	 * @param  string  $value	 * @param  View    $view	 * @return string	 */	public static function compile_string($value, $view = null)	{		foreach (static::$compilers as $compiler)		{			$method = "compile_{$compiler}";			$value = static::$method($value, $view);		}		return $value;	}	/**	 * Rewrites Blade "@layout" expressions into valid PHP.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_layouts($value)	{		// If the Blade template is not using "layouts", we'll just return it		// it unchanged since there is nothing to do with layouts and we'll		// just let the other Blade compilers handle the rest.		if ( ! starts_with($value, '@layout'))		{			return $value;		}		// First we'll split out the lines of the template so we can get the		// the layout from the top of the template. By convention it must		// be located on the first line of the template contents.		$lines = preg_split("/(\r?\n)/", $value);		$pattern = static::matcher('layout');		$lines[] = preg_replace($pattern, '$1@include$2', $lines[0]);		// We will add a "render" statement to the end of the templates and		// and then slice off the @layout shortcut from the start so the		// sections register before the parent template renders.		return implode(CRLF, array_slice($lines, 1));	}	/**	 * Extract a variable value out of a Blade expression.	 *	 * @param  string  $value	 * @return string	 */	protected static function extract($value, $expression)	{		preg_match('/@layout(\s*\(.*\))(\s*)/', $value, $matches);		return str_replace(array("('", "')"), '', $matches[1]);	}	/**	 * Rewrites Blade echo statements into PHP echo statements.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_echos($value)	{		return preg_replace('/\{\{(.+?)\}\}/', '<?php echo $1; ?>', $value);	}	/**	 * Rewrites Blade "for else" statements into valid PHP.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_forelse($value)	{		preg_match_all('/(\s*)@forelse(\s*\(.*\))(\s*)/', $value, $matches);		foreach ($matches[0] as $forelse)		{			preg_match('/\$[^\s]*/', $forelse, $variable);			// Once we have extracted the variable being looped against, we can add			// an if statmeent to the start of the loop that checks if the count			// of the variable being looped against is greater than zero.			$if = "<?php if (count({$variable[0]}) > 0): ?>";			$search = '/(\s*)@forelse(\s*\(.*\))/';			$replace = '$1'.$if.'<?php foreach$2: ?>';			$blade = preg_replace($search, $replace, $forelse);			// Finally, once we have the check prepended to the loop we'll replace			// all instances of this "forelse" syntax in the view content of the			// view being compiled to Blade syntax with real syntax.			$value = str_replace($forelse, $blade, $value);		}		return $value;	}	/**	 * Rewrites Blade "empty" statements into valid PHP.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_empty($value)	{		return str_replace('@empty', '<?php endforeach; ?><?php else: ?>', $value);	}	/**	 * Rewrites Blade "forelse" endings into valid PHP.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_endforelse($value)	{		return str_replace('@endforelse', '<?php endif; ?>', $value);	}	/**	 * Rewrites Blade structure openings into PHP structure openings.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_structure_openings($value)	{		$pattern = '/(\s*)@(if|elseif|foreach|for|while)(\s*\(.*\))/';		return preg_replace($pattern, '$1<?php $2$3: ?>', $value);	}	/**	 * Rewrites Blade structure closings into PHP structure closings.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_structure_closings($value)	{		$pattern = '/(\s*)@(endif|endforeach|endfor|endwhile)(\s*)/';		return preg_replace($pattern, '$1<?php $2; ?>$3', $value);	}	/**	 * Rewrites Blade else statements into PHP else statements.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_else($value)	{		return preg_replace('/(\s*)@(else)(\s*)/', '$1<?php $2: ?>$3', $value);	}	/**	 * Rewrites Blade @include statements into valid PHP.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_includes($value)	{		$pattern = static::matcher('include');		return preg_replace($pattern, '$1<?php echo view$2->with(get_defined_vars())->render(); ?>', $value);	}	/**	 * Rewrites Blade @render statements into valid PHP.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_render($value)	{		$pattern = static::matcher('render');		return preg_replace($pattern, '$1<?php echo render$2; ?>', $value);	}	/**	 * Rewrites Blade @render_each statements into valid PHP.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_render_each($value)	{		$pattern = static::matcher('render_each');		return preg_replace($pattern, '$1<?php echo render_each$2; ?>', $value);	}	/**	 * Rewrites Blade @yield statements into Section statements.	 *	 * The Blade @yield statement is a shortcut to the Section::yield method.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_yields($value)	{		$pattern = static::matcher('yield');		return preg_replace($pattern, '$1<?php echo \\Laravel\\Section::yield$2; ?>', $value);	}	/**	 * Rewrites Blade yield section statements into valid PHP.	 *	 * @return string	 */	protected static function compile_yield_sections($value)	{		$replace = '<?php echo \\Laravel\\Section::yield_section(); ?>';		return str_replace('@yield_section', $replace, $value);	}	/**	 * Rewrites Blade @section statements into Section statements.	 *	 * The Blade @section statement is a shortcut to the Section::start method.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_section_start($value)	{		$pattern = static::matcher('section');		return preg_replace($pattern, '$1<?php \\Laravel\\Section::start$2; ?>', $value);	}	/**	 * Rewrites Blade @endsection statements into Section statements.	 *	 * The Blade @endsection statement is a shortcut to the Section::stop method.	 *	 * @param  string  $value	 * @return string	 */	protected static function compile_section_end($value)	{		return preg_replace('/@endsection/', '<?php \\Laravel\\Section::stop(); ?>', $value);	}	/**	 * Get the regular expression for a generic Blade function.	 *	 * @param  string  $function	 * @return string	 */	protected static function matcher($function)	{		return '/(\s*)@'.$function.'(\s*\(.*\))/';	}	/**	 * Get the fully qualified path for a compiled view.	 *	 * @param  string  $view	 * @return string	 */	public static function compiled($path)	{		return path('storage').'views/'.md5($path);	}}
 |