Browse Source

Merge branch 'staging'

Taylor Otwell 12 years ago
parent
commit
928ce7c037

+ 13 - 0
application/config/application.php

@@ -94,6 +94,19 @@ return array(
 
 	'language' => 'en',
 
+	/*
+	|--------------------------------------------------------------------------
+	| Supported Languages
+	|--------------------------------------------------------------------------
+	|
+	| These languages may also be supported by your application. If a request
+	| enters your application with a URI beginning with one of these values
+	| the default language will automatically be set to that language.
+	|
+	*/
+
+	'languages' => array(),
+
 	/*
 	|--------------------------------------------------------------------------
 	| SSL Link Generation

+ 1 - 1
artisan

@@ -4,7 +4,7 @@
  * Laravel - A PHP Framework For Web Artisans
  *
  * @package  Laravel
- * @version  3.2.5
+ * @version  3.2.6
  * @author   Taylor Otwell <taylorotwell@gmail.com>
  * @link     http://laravel.com
  */

+ 52 - 80
laravel/blade.php

@@ -105,7 +105,7 @@ class Blade {
 	/**
 	 * Compiles the specified file containing Blade pseudo-code into valid PHP.
 	 *
-	 * @param  string  $view
+	 * @param  string  $path
 	 * @return string
 	 */
 	public static function compile($view)
@@ -149,33 +149,31 @@ class Blade {
 		}
 
 		// First we'll split out the lines of the template so we can get the
-		// layout from the top of the template. By convention, it must be
+		// layout from the top of the template. By convention it must be
 		// located on the first line of the template contents.
-		preg_replace_callback(
-			'/^@layout(\s*?\(.+?\))(\r?\n)?/',
-			function($matches) use (&$value)
-			{
-				$value = substr( $value, strlen( $matches[0] ) ).CRLF.'@include'.$matches[1];
-			},
-			$value
-		);
+		$lines = preg_split("/(\r?\n)/", $value);
 
-		return $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
+		// 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
-	 * @param  string  $expression
 	 * @return string
 	 */
 	protected static function extract($value, $expression)
 	{
-		if ( preg_match("/@layout\s*?\(\s*?'(.+?)'\s*?\)/", $value, $matches))
-		{
-			return trim( $matches[1] );
-		}
+		preg_match('/@layout(\s*\(.*\))(\s*)/', $value, $matches);
+
+		return str_replace(array("('", "')"), '', $matches[1]);
 	}
 
 	/**
@@ -186,9 +184,9 @@ class Blade {
 	 */
 	protected static function compile_comments($value)
 	{
-		$value = preg_replace('/\{\{--(.*?)--\}\}/', "<?php // $1 ?>", $value);
-		
-		return preg_replace('/\{\{--(.*?)--\}\}/s', "<?php /* ?>$1<?php */ ?>", $value);
+		$value = preg_replace('/\{\{--(.+?)(--\}\})?\n/', "<?php // $1 ?>", $value);
+
+		return preg_replace('/\{\{--((.|\s)*?)--\}\}/', "<?php /* $1 */ ?>\n", $value);
 	}
 
 	/**
@@ -199,7 +197,7 @@ class Blade {
 	 */
 	protected static function compile_echos($value)
 	{
-		return preg_replace('/\{\{(.+?)\}\}/s', '<?php echo $1; ?>', $value);
+		return preg_replace('/\{\{(.+?)\}\}/', '<?php echo $1; ?>', $value);
 	}
 
 	/**
@@ -210,21 +208,27 @@ class Blade {
 	 */
 	protected static function compile_forelse($value)
 	{
-		preg_match_all('/@forelse\s*?\(\s*?\$(.+?)\s*?as\s*?\$(.+?)\s*?\)/', $value, $matches, PREG_SET_ORDER );
-
-		if ( count($matches) < 1 ) return $value;
+		preg_match_all('/(\s*)@forelse(\s*\(.*\))(\s*)/', $value, $matches);
 
-		foreach ($matches as $forelse)
+		foreach ($matches[0] as $forelse)
 		{
+			preg_match('/\s*\(\s*(\S*)\s/', $forelse, $variable);
+
 			// Once we have extracted the variable being looped against, we can add
 			// an if statement to the start of the loop that checks if the count
 			// of the variable being looped against is greater than zero.
-			$replace = '<?php if (count($'.$forelse[1].') > 0): foreach ($'.$forelse[1].' as $'.$forelse[2].'): ?>';
+			$if = "<?php if (count({$variable[1]}) > 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 PHP syntax.
-			$value = str_replace($forelse[0], $replace, $value);
+			$value = str_replace($forelse, $blade, $value);
 		}
 
 		return $value;
@@ -238,7 +242,7 @@ class Blade {
 	 */
 	protected static function compile_empty($value)
 	{
-		return str_replace('@empty', '<?php endforeach; else: ?>', $value);
+		return str_replace('@empty', '<?php endforeach; ?><?php else: ?>', $value);
 	}
 
 	/**
@@ -260,42 +264,9 @@ class Blade {
 	 */
 	protected static function compile_structure_openings($value)
 	{
-		preg_replace_callback(
-			'/@(if|elseif|foreach|for|while)(\s*?)(\([^\n\r\t]+\))/',
-			function($matches) use (&$value)
-			{
-				if(count( $matches ) === 4)
-				{
-					$open  = 0;
-					$close = 0;
-					$cut   = 0;
-					$len   = strlen($matches[3]);
-					for($i = 0; $i < $len; $i++)
-					{
-						if($matches[3][$i] === '(' )
-						{
-							$open++;
-						}
-						if($matches[3][$i] === ')' )
-						{
-							$close++;
-						}
-						if($open !== 0 && ($open === $close))
-						{
-							break;
-						}
-					}
-					$condition = substr($matches[3], 0, ($i + 1));
-					$value = str_replace(
-						'@'.$matches[1].$matches[2].$condition,
-						'<?php '.$matches[1].$condition.': ?>',
-						$value
-					);
-				}
-			},
-			$value
-		);
-		return $value;
+		$pattern = '/(\s*)@(if|elseif|foreach|for|while)(\s*\(.*\))/';
+
+		return preg_replace($pattern, '$1<?php $2$3: ?>', $value);
 	}
 
 	/**
@@ -306,9 +277,9 @@ class Blade {
 	 */
 	protected static function compile_structure_closings($value)
 	{
-		$pattern = '/@(endif|endforeach|endfor|endwhile|break|continue)/';
+		$pattern = '/(\s*)@(endif|endforeach|endfor|endwhile)(\s*)/';
 
-		return preg_replace($pattern, '<?php $1; ?>', $value);
+		return preg_replace($pattern, '$1<?php $2; ?>$3', $value);
 	}
 
 	/**
@@ -319,7 +290,7 @@ class Blade {
 	 */
 	protected static function compile_else($value)
 	{
-		return str_replace( '@else', '<?php else: ?>', $value);
+		return preg_replace('/(\s*)@(else)(\s*)/', '$1<?php $2: ?>$3', $value);
 	}
 
 	/**
@@ -330,9 +301,9 @@ class Blade {
 	 */
 	protected static function compile_unless($value)
 	{
-		$pattern = static::matcher('unless');
+		$pattern = '/(\s*)@unless(\s*\(.*\))/';
 
-		return preg_replace($pattern, '<?php if( ! ($1)): ?>', $value);
+		return preg_replace($pattern, '$1<?php if( ! ($2)): ?>', $value);
 	}
 
 	/**
@@ -356,7 +327,7 @@ class Blade {
 	{
 		$pattern = static::matcher('include');
 
-		return preg_replace($pattern, '<?php echo view$1->with(get_defined_vars())->render(); ?>', $value);
+		return preg_replace($pattern, '$1<?php echo view$2->with(get_defined_vars())->render(); ?>', $value);
 	}
 
 	/**
@@ -369,7 +340,7 @@ class Blade {
 	{
 		$pattern = static::matcher('render');
 
-		return preg_replace($pattern, '<?php echo render$1; ?>', $value);
+		return preg_replace($pattern, '$1<?php echo render$2; ?>', $value);
 	}
 
 	/**
@@ -382,7 +353,7 @@ class Blade {
 	{
 		$pattern = static::matcher('render_each');
 
-		return preg_replace($pattern, '<?php echo render_each$1; ?>', $value);
+		return preg_replace($pattern, '$1<?php echo render_each$2; ?>', $value);
 	}
 
 	/**
@@ -397,18 +368,19 @@ class Blade {
 	{
 		$pattern = static::matcher('yield');
 
-		return preg_replace($pattern, '<?php echo \\Laravel\\Section::yield$1; ?>', $value);
+		return preg_replace($pattern, '$1<?php echo \\Laravel\\Section::yield$2; ?>', $value);
 	}
 
 	/**
 	 * Rewrites Blade yield section statements into valid PHP.
 	 *
-	 * @param  string  $value
 	 * @return string
 	 */
 	protected static function compile_yield_sections($value)
 	{
-		return str_replace('@yield_section', '<?php echo \\Laravel\\Section::yield_section(); ?>', $value);
+		$replace = '<?php echo \\Laravel\\Section::yield_section(); ?>';
+
+		return str_replace('@yield_section', $replace, $value);
 	}
 
 	/**
@@ -423,7 +395,7 @@ class Blade {
 	{
 		$pattern = static::matcher('section');
 
-		return preg_replace($pattern, '<?php \\Laravel\\Section::start$1; ?>', $value);
+		return preg_replace($pattern, '$1<?php \\Laravel\\Section::start$2; ?>', $value);
 	}
 
 	/**
@@ -436,7 +408,7 @@ class Blade {
 	 */
 	protected static function compile_section_end($value)
 	{
-		return str_replace('@endsection', '<?php \\Laravel\\Section::stop(); ?>', $value);
+		return preg_replace('/@endsection/', '<?php \\Laravel\\Section::stop(); ?>', $value);
 	}
 
 	/**
@@ -453,7 +425,7 @@ class Blade {
 		}
 
 		return $value;
-	}
+	}	
 
 	/**
 	 * Get the regular expression for a generic Blade function.
@@ -463,13 +435,13 @@ class Blade {
 	 */
 	public static function matcher($function)
 	{
-		return '/@'.$function.'\s*?(\(.+?\))/';
+		return '/(\s*)@'.$function.'(\s*\(.*\))/';
 	}
 
 	/**
 	 * Get the fully qualified path for a compiled view.
 	 *
-	 * @param  string  $path
+	 * @param  string  $view
 	 * @return string
 	 */
 	public static function compiled($path)
@@ -477,4 +449,4 @@ class Blade {
 		return path('storage').'views/'.md5($path);
 	}
 
-}
+}

+ 39 - 26
laravel/documentation/changes.md

@@ -2,6 +2,8 @@
 
 ## Contents
 
+- [Laravel 3.2.6](#3.2.6)
+- [Upgrading From 3.2.5](#upgrade-3.2.6)
 - [Laravel 3.2.5](#3.2.5)
 - [Upgrading From 3.2.4](#upgrade-3.2.5)
 - [Laravel 3.2.4](#3.2.4)
@@ -35,12 +37,23 @@
 - [Laravel 3.1](#3.1)
 - [Upgrading From 3.0](#upgrade-3.1)
 
+<a name="3.2.6"></a>
+## Laravel 3.2.6
+
+- Revert Blade code back to 3.2.3 tag.
+
+<a name="upgrade-3.2.6"></a>
+### Upgrading From 3.2.5
+
+- Replace the **laravel** folder.
+
 <a name="3.2.5"></a>
+## Laravel 3.2.5
 
 - Revert nested where code back to 3.2.3 tag.
 
 <a name="upgrade-3.2.5"></a>
-## Upgrading From 3.2.4
+### Upgrading From 3.2.4
 
 - Replace the **laravel** folder.
 
@@ -52,7 +65,7 @@
 - Various bug fixes and improvements.
 
 <a name="upgrade-3.2.3"></a>
-## Upgrading From 3.2.3
+### Upgrading From 3.2.3
 
 - Replace the **laravel** folder.
 
@@ -63,7 +76,7 @@
 - Added `laravel.resolving` event for all IoC resolutions.
 
 <a name="upgrade-3.2.3"></a>
-## Upgrading From 3.2.2
+### Upgrading From 3.2.2
 
 - Replace the **laravel** folder.
 
@@ -79,7 +92,7 @@
 - Added `password` option to Auth configuration.
 
 <a name="upgrade-3.2.2"></a>
-## Upgrading From 3.2.1
+### Upgrading From 3.2.1
 
 - Replace the **laravel** folder.
 
@@ -94,7 +107,7 @@
 - Added `format` method to message container.
 
 <a name="upgrade-3.2.1"></a>
-## Upgrading From 3.2
+### Upgrading From 3.2
 
 - Replace the **laravel** folder.
 
@@ -151,7 +164,7 @@
 - Added `array_except` and `array_only` helpers, similar to `Input::except` and `Input::only` but for arbitrary arrays.
 
 <a name="upgrade-3.2"></a>
-## Upgrading From 3.1
+### Upgrading From 3.1
 
 - Add new `asset_url` and `profiler` options to application configuration.
 - Replace **auth** configuration file.
@@ -176,7 +189,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes cookie session driver bug that caused infinite loop on some occasions.
 
 <a name="upgrade-3.1.9"></a>
-## Upgrading From 3.1.8
+### Upgrading From 3.1.8
 
 - Replace the **laravel** folder.
 
@@ -186,7 +199,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes possible WSOD when using Blade's @include expression.
 
 <a name="upgrade-3.1.8"></a>
-## Upgrading From 3.1.7
+### Upgrading From 3.1.7
 
 - Replace the **laravel** folder.
 
@@ -198,7 +211,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Classify migration names.
 
 <a name="upgrade-3.1.7"></a>
-## Upgrading From 3.1.6
+### Upgrading From 3.1.6
 
 - Replace the **laravel** folder.
 
@@ -208,7 +221,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes many-to-many eager loading in Eloquent.
 
 <a name="upgrade-3.1.6"></a>
-## Upgrading From 3.1.5
+### Upgrading From 3.1.5
 
 - Replace the **laravel** folder.
 
@@ -218,7 +231,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes bug that could allow secure cookies to be sent over HTTP.
 
 <a name="upgrade-3.1.5"></a>
-## Upgrading From 3.1.4
+### Upgrading From 3.1.4
 
 - Replace the **laravel** folder.
 
@@ -229,7 +242,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes SQL "where in" (...) short-cut bug.
 
 <a name="upgrade-3.1.4"></a>
-## Upgrading From 3.1.3
+### Upgrading From 3.1.3
 
 - Replace the **laravel** folder.
 
@@ -239,7 +252,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes **delete** method in Eloquent models.
 
 <a name="upgrade-3.1.3"></a>
-## Upgrade From 3.1.2
+### Upgrade From 3.1.2
 
 - Replace the **laravel** folder.
 
@@ -249,7 +262,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes Eloquent query method constructor conflict.
 
 <a name="upgrade-3.1.2"></a>
-## Upgrade From 3.1.1
+### Upgrade From 3.1.1
 
 - Replace the **laravel** folder.
 
@@ -259,7 +272,7 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Fixes Eloquent model hydration bug involving custom setters.
 
 <a name="upgrade-3.1.1"></a>
-## Upgrading From 3.1
+### Upgrading From 3.1
 
 - Replace the **laravel** folder.
 
@@ -297,48 +310,48 @@ Add the following code above `Blade::sharpen()` in `application/start.php`..
 - Added "before" and "after" validation checks for dates.
 
 <a name="upgrade-3.1"></a>
-## Upgrading From 3.0
+### Upgrading From 3.0
 
-### Replace your **application/start.php** file.
+#### Replace your **application/start.php** file.
 
 The default **start.php** file has been expanded in order to give you more flexibility over the loading of your language, configuration, and view files. To upgrade your file, copy your current file and paste it at the bottom of a copy of the new Laravel 3.1 start file. Next, scroll up in the **start** file until you see the default Autoloader registrations (line 61 and line 76). Delete both of these sections since you just pasted your previous auto-loader registrations at the bottom of the file.
 
-### Remove the **display** option from your **errors** configuration file.
+#### Remove the **display** option from your **errors** configuration file.
 
 This option is now set at the beginning of your **application/start** file.
 
-### Call the parent controller's constructor from your controller.
+#### Call the parent controller's constructor from your controller.
 
 Simply add a **parent::__construct();** to to any of your controllers that have a constructor.
 
-### Prefix Laravel migration created indexes with their table name.
+#### Prefix Laravel migration created indexes with their table name.
 
 If you have created indexes on tables using the Laravel migration system and you used to the default index naming scheme provided by Laravel, prefix the index names with their table name on your database. So, if the current index name is "id_unique" on the "users" table, make the index name "users_id_unique".
 
-### Add alias for Eloquent in your application configuration.
+#### Add alias for Eloquent in your application configuration.
 
 Add the following to the **aliases** array in your **application/config/application.php** file:
 
 	'Eloquent' => 'Laravel\\Database\\Eloquent\\Model',
 	'Blade' => 'Laravel\\Blade',
 
-### Update Eloquent many-to-many tables.
+#### Update Eloquent many-to-many tables.
 
 Eloquent now maintains **created_at** and **updated_at** column on many-to-many intermediate tables by default. Simply add these columns to your tables. Also, many-to-many tables are now the singular model names concatenated with an underscore. For example, if the relationship is between User and Role, the intermediate table name should be **role_user**.
 
-### Remove Eloquent bundle.
+#### Remove Eloquent bundle.
 
 If you are using the Eloquent bundle with your installation, you can remove it from your bundles directory and your **application/bundles.php** file. Eloquent version 2 is included in the core in Laravel 3.1. Your models can also now extend simply **Eloquent** instead of **Eloquent\Model**.
 
-### Update your **config/strings.php** file.
+#### Update your **config/strings.php** file.
 
 English pluralization and singularization is now automatic. Just completely replace your **application/config/strings.php** file.
 
-### Add the **fetch** option to your database configuration file.
+#### Add the **fetch** option to your database configuration file.
 
 A new **fetch** option allows you to specify in which format you receive your database results. Just copy and paste the option from the new **application/config/database.php** file.
 
-### Add **database** option to your Redis configuration.
+#### Add **database** option to your Redis configuration.
 
 If you are using Redis, add the "database" option to your Redis connection configurations. The "database" value can be zero by default.
 

+ 8 - 1
laravel/documentation/database/schema.md

@@ -71,6 +71,7 @@ Command  | Description
 `$table->blob('data');`  |  BLOB equivalent to the table
 `->nullable()`  |  Designate that the column allows NULL values
 `->default($value)`  |  Declare a default value for a column
+`->unsigned()`  |  Set INTEGER to UNSIGNED
 
 > **Note:** Laravel's "boolean" type maps to a small integer column on all database systems.
 
@@ -144,4 +145,10 @@ You may also specify options for the "on delete" and "on update" actions of the
 
 You may also easily drop a foreign key constraint. The default foreign key names follow the [same convention](#dropping-indexes) as the other indexes created by the Schema builder. Here's an example:
 
-	$table->drop_foreign('posts_user_id_foreign');
+	$table->drop_foreign('posts_user_id_foreign');
+
+> **Note:** The field referenced in the foreign key is very likely an auto increment and therefore automatically an unsigned integer. Please make sure to create the foreign key field with **unsigned()** as both fields have to be the exact same type, the engine on both tables has to be set to **InnoDB**, and the referenced table must be created **before** the table with the foreign key.
+
+	$table->engine = 'InnoDB';
+
+	$table->integer('user_id')->unsigned();

+ 42 - 2
laravel/laravel.php

@@ -107,6 +107,48 @@ Routing\Router::register('*', '(:all)', function()
 	return Event::first('404');
 });
 
+/*
+|--------------------------------------------------------------------------
+| Gather The URI And Locales
+|--------------------------------------------------------------------------
+|
+| When routing, we'll need to grab the URI and the supported locales for
+| the route so we can properly set the language and route the request
+| to the proper end-point in the application.
+|
+*/
+
+$uri = URI::current();
+
+$languages = Config::get('application.languages', array());
+
+$languages[] = Config::get('application.language');
+
+/*
+|--------------------------------------------------------------------------
+| Set The Locale Based On The Route
+|--------------------------------------------------------------------------
+|
+| If the URI starts with one of the supported languages, we will set
+| the default lagnauge to match that URI segment and shorten the
+| URI we'll pass to the router to not include the lang segment.
+|
+*/
+
+foreach ($languages as $language)
+{
+	if (starts_with($uri, $language))
+	{
+		Config::set('application.language', $language);
+
+		$uri = trim(substr($uri, strlen($language)), '/'); break;
+	}
+}
+
+if ($uri == '') $uri = '/';
+
+URI::$uri = $uri;
+
 /*
 |--------------------------------------------------------------------------
 | Route The Incoming Request
@@ -118,8 +160,6 @@ Routing\Router::register('*', '(:all)', function()
 |
 */
 
-$uri = URI::current();
-
 Request::$route = Routing\Router::route(Request::method(), $uri);
 
 $response = Request::$route->call();

+ 86 - 1
laravel/profiling/profiler.php

@@ -14,7 +14,7 @@ class Profiler {
 	 *
 	 * @var array
 	 */
-	protected static $data = array('queries' => array(), 'logs' => array());
+	protected static $data = array('queries' => array(), 'logs' => array(), 'timers' => array());
 	
 	/**
 	 * Get the rendered contents of the Profiler.
@@ -32,10 +32,95 @@ class Profiler {
 			static::$data['memory'] = get_file_size(memory_get_usage(true));
 			static::$data['memory_peak'] = get_file_size(memory_get_peak_usage(true));
 			static::$data['time'] = number_format((microtime(true) - LARAVEL_START) * 1000, 2);
+			foreach ( static::$data['timers'] as &$timer)
+			{
+				$timer['running_time'] = number_format((microtime(true) - $timer['start'] ) * 1000, 2);
+			}
+
 			return render('path: '.__DIR__.'/template'.BLADE_EXT, static::$data);
 		}
 	}
 
+	/**
+	 * Allow a callback to be timed.
+	 *
+	 * @param closure $func
+	 * @param string $name
+	 * @return void
+	 */
+	public static function time( $func, $name = 'default_func_timer' )
+	{
+		// First measure the runtime of the func
+		$start = microtime(true);
+		$func();
+		$end = microtime(true);
+
+		// Check to see if a timer by that name exists
+		if (isset(static::$data['timers'][$name]))
+		{
+			$name = $name.uniqid();
+		}
+		
+		// Push the time into the timers array for display
+		static::$data['timers'][$name]['start'] = $start;
+		static::$data['timers'][$name]['end'] = $end;
+		static::$data['timers'][$name]['time'] = number_format(($end - $start) * 1000, 2);
+	}
+
+	/**
+	 *  Start, or add a tick to a timer.
+	 *
+	 * @param string $name
+	 * @return void
+	 */
+	public static function tick($name = 'default_timer', $callback = null)
+	{
+		$name = trim($name);
+		if (empty($name)) $name = 'default_timer';
+
+		// Is this a brand new tick?
+		if (isset(static::$data['timers'][$name]))
+		{
+			$current_timer = static::$data['timers'][$name];
+			$ticks = count($current_timer['ticks']);
+
+			// Initialize the new time for the tick
+			$new_tick = array();
+			$mt = microtime(true);
+			$new_tick['raw_time'] = $mt - $current_timer['start'];
+			$new_tick['time'] = number_format(($mt - $current_timer['start']) * 1000, 2);
+
+			// Use either the start time or the last tick for the diff
+			if ($ticks > 0)
+			{
+				$last_tick = $current_timer['ticks'][$ticks- 1]['raw_time'];
+				$new_tick['diff'] = number_format(($new_tick['raw_time'] - $last_tick) * 1000, 2);
+			}
+			else
+			{
+				$new_tick['diff'] = $new_tick['time'];
+			}
+
+			// Add the new tick to the stack of them
+			static::$data['timers'][$name]['ticks'][] = $new_tick;
+		}
+		else
+		{
+			// Initialize a start time on the first tick
+			static::$data['timers'][$name]['start'] = microtime(true);
+			static::$data['timers'][$name]['ticks'] = array();
+		}
+
+		// Run the callback for this tick if it's specified
+		if ( ! is_null($callback) and is_callable($callback))
+		{
+			// After we've ticked, call the callback function
+			call_user_func_array($callback, array(
+				static::$data['timers'][$name]
+			));
+		}
+	}
+
 	/**
 	 * Add a log entry to the log entries array.
 	 *

+ 48 - 2
laravel/profiling/template.blade.php

@@ -48,6 +48,52 @@
 					<span class="anbu-empty">There have been no SQL queries executed.</span>
 				@endif
 			</div>
+
+			<div class="anbu-tab-pane anbu-table anbu-checkpoints">
+				@if (count($timers) > 0)
+						<table>
+							<tr>
+								<th>Name</th>
+								<th>Running Time (ms)</th>
+								<th>Difference</th>
+							</tr>
+							@foreach ($timers as $name => $timer)
+							<tr>
+								<td class="anbu-table-first">
+									{{ $name }}
+								</td>
+								<td><pre>{{ $timer['running_time'] }}ms (time from start to render)</pre></td>
+								<td>&nbsp;</td>
+							</tr>
+
+							@if (isset($timer['ticks']))
+								@foreach( $timer['ticks'] as $tick)
+								<tr>
+									<td>
+										<pre>Tick</pre>
+									</td>
+									<td>
+										<pre>{{ $tick['time'] }}ms</pre>
+									</td>
+									<td>
+										<pre>+ {{ $tick['diff'] }}ms</pre>
+									</td>
+								</tr>
+								@endforeach
+							@else
+								<tr>
+									<td><pre>Running Time</pre></td>
+									<td><pre>{{ $timer['time'] }}ms</pre></td>
+									<td>&nbsp;</td>
+								</tr>
+							@endif
+							
+							@endforeach
+						</table>			
+				@else
+					<span class="anbu-empty">There have been no checkpoints set.</span>
+				@endif
+			</div>
 		</div>
 	</div>
 
@@ -61,7 +107,7 @@
 				@endif
 			</a>
 		</li>
-		<li><a class="anbu-tab">Time <span class="anbu-count">{{ $time }}ms</span></a></li>
+		<li><a class="anbu-tab" data-anbu-tab="anbu-checkpoints">Time <span class="anbu-count">{{ $time }}ms</span></a></li>
 		<li><a class="anbu-tab">Memory <span class="anbu-count">{{ $memory }} ({{ $memory_peak }})</span></a></li>
 		<li class="anbu-tab-right"><a id="anbu-hide" href="#">&#8614;</a></li>
 		<li class="anbu-tab-right"><a id="anbu-close" href="#">&times;</a></li>
@@ -75,4 +121,4 @@
 
 <script>window.jQuery || document.write("<script src='//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'>\x3C/script>")</script>
 <script>{{ file_get_contents(path('sys').'profiling/profiler.js') }}</script>
-<!-- /ANBU - LARAVEL PROFILER -->
+<!-- /ANBU - LARAVEL PROFILER -->

+ 16 - 4
laravel/url.php

@@ -26,7 +26,7 @@ class URL {
 	 */
 	public static function current()
 	{
-		return static::to(URI::current());
+		return static::to(URI::current(), null, false, false);
 	}
 
 	/**
@@ -89,9 +89,11 @@ class URL {
 	 *
 	 * @param  string  $url
 	 * @param  bool    $https
+	 * @param  bool    $asset
+	 * @param  bool    $locale
 	 * @return string
 	 */
-	public static function to($url = '', $https = null)
+	public static function to($url = '', $https = null, $asset = false, $locale = true)
 	{
 		// If the given URL is already valid or begins with a hash, we'll just return
 		// the URL unchanged since it is already well formed. Otherwise we will add
@@ -105,7 +107,17 @@ class URL {
 		// security for any new links generated.  So https for all secure links.
 		if (is_null($https)) $https = Request::secure();
 
-		$root = static::base().'/'.Config::get('application.index');
+		$root = static::base();
+
+		if ( ! $asset)
+		{
+			$root .= '/'.Config::get('application.index');
+		}
+
+		if ( ! $asset and $locale and count(Config::get('application.languages')) > 0)
+		{
+			$root .= '/'.Config::get('application.language');
+		}
 
 		// Since SSL is not often used while developing the application, we allow the
 		// developer to disable SSL on all framework generated links to make it more
@@ -232,7 +244,7 @@ class URL {
 			return rtrim($root, '/').'/'.ltrim($url, '/');
 		}
 
-		$url = static::to($url, $https);
+		$url = static::to($url, $https, true);
 
 		// Since assets are not served by Laravel, we do not need to come through
 		// the front controller. So, we'll remove the application index specified

+ 1 - 1
paths.php

@@ -3,7 +3,7 @@
  * Laravel - A PHP Framework For Web Artisans
  *
  * @package  Laravel
- * @version  3.2.5
+ * @version  3.2.6
  * @author   Taylor Otwell <taylorotwell@gmail.com>
  * @link     http://laravel.com
  */

+ 1 - 1
public/index.php

@@ -3,7 +3,7 @@
  * Laravel - A PHP Framework For Web Artisans
  *
  * @package  Laravel
- * @version  3.2.5
+ * @version  3.2.6
  * @author   Taylor Otwell <taylorotwell@gmail.com>
  * @link     http://laravel.com
  */