diff --git a/artisan b/artisan index 2f3dbeb6..9200cb9a 100644 --- a/artisan +++ b/artisan @@ -4,7 +4,7 @@ * Laravel - A PHP Framework For Web Artisans * * @package Laravel - * @version 3.2.8 + * @version 3.2.9 * @author Taylor Otwell * @link http://laravel.com */ diff --git a/laravel/auth/drivers/driver.php b/laravel/auth/drivers/driver.php index db649d24..96e90637 100644 --- a/laravel/auth/drivers/driver.php +++ b/laravel/auth/drivers/driver.php @@ -127,6 +127,8 @@ public function logout() $this->cookie($this->recaller(), null, -2000); Session::forget($this->token()); + + $this->token = null; } /** diff --git a/laravel/database/eloquent/model.php b/laravel/database/eloquent/model.php index c2566496..bdcf6daf 100644 --- a/laravel/database/eloquent/model.php +++ b/laravel/database/eloquent/model.php @@ -528,7 +528,7 @@ public function get_dirty() foreach ($this->attributes as $key => $value) { - if ( ! isset($this->original[$key]) or $value !== $this->original[$key]) + if ( ! array_key_exists($key, $this->original) or $value != $this->original[$key]) { $dirty[$key] = $value; } @@ -544,7 +544,7 @@ public function get_dirty() */ public function get_key() { - return $this->get_attribute(static::$key); + return array_get($this->original, static::$key); } /** @@ -721,7 +721,7 @@ public function __isset($key) { if (array_key_exists($key, $this->$source)) return true; } - + if (method_exists($this, $key)) return true; } diff --git a/laravel/documentation/changes.md b/laravel/documentation/changes.md index 013eb948..417e4f85 100644 --- a/laravel/documentation/changes.md +++ b/laravel/documentation/changes.md @@ -2,6 +2,8 @@ ## Contents +- [Laravel 3.2.9](#3.2.9) +- [Upgrading From 3.2.8](#upgrade-3.2.9) - [Laravel 3.2.8](#3.2.8) - [Upgrading From 3.2.7](#upgrade-3.2.8) - [Laravel 3.2.7](#3.2.7) @@ -41,6 +43,17 @@ - [Laravel 3.1](#3.1) - [Upgrading From 3.0](#upgrade-3.1) + +## Laravel 3.2.9 + +- Always log exceptions even when there are "logger" event listeners. +- Fix nasty view exception messages. + + +### Upgrading From 3.2.8 + +- Replace the **laravel** folder. + ## Laravel 3.2.8 diff --git a/laravel/error.php b/laravel/error.php index 6b75d210..a53d2e0b 100644 --- a/laravel/error.php +++ b/laravel/error.php @@ -15,6 +15,18 @@ public static function exception($exception, $trace = true) ob_get_level() and ob_end_clean(); + $message = $exception->getMessage(); + + // For Laravel view errors we want to show a prettier error: + $file = $exception->getFile(); + + if (str_contains($exception->getFile(), 'eval()') and str_contains($exception->getFile(), 'laravel/view.php')) + { + $message = 'Error rendering view: ['.View::$last['name'].']'.PHP_EOL.PHP_EOL.$message; + + $file = View::$last['path']; + } + // If detailed errors are enabled, we'll just format the exception into // a simple error message and display it on the screen. We don't use a // View in case the problem is in the View class. @@ -22,9 +34,9 @@ public static function exception($exception, $trace = true) { echo "

Unhandled Exception

Message:

-
".$exception->getMessage()."
+
".$message."

Location:

-
".$exception->getFile()." on line ".$exception->getLine()."
"; +
".$file." on line ".$exception->getLine()."
"; if ($trace) { diff --git a/laravel/laravel.php b/laravel/laravel.php index 74c387f9..3e382b89 100644 --- a/laravel/laravel.php +++ b/laravel/laravel.php @@ -137,7 +137,7 @@ foreach ($languages as $language) { - if (starts_with($uri, $language)) + if (preg_match("#^{$language}(?:$|/)#i", $uri)) { Config::set('application.language', $language); diff --git a/laravel/log.php b/laravel/log.php index 6de027df..f2b2b3f8 100644 --- a/laravel/log.php +++ b/laravel/log.php @@ -49,15 +49,9 @@ public static function write($type, $message) Event::fire('laravel.log', array($type, $message)); } - // If there aren't listeners on the log event, we'll just write to the - // log files using the default conventions, writing one log file per - // day so the files don't get too crowded. - else - { - $message = static::format($type, $message); + $message = static::format($type, $message); - File::append(path('storage').'logs/'.date('Y-m-d').'.log', $message); - } + File::append(path('storage').'logs/'.date('Y-m-d').'.log', $message); } /** diff --git a/laravel/str.php b/laravel/str.php index 23f2b731..68130042 100644 --- a/laravel/str.php +++ b/laravel/str.php @@ -9,17 +9,22 @@ class Str { */ public static $pluralizer; - /** - * Get the default string encoding for the application. - * - * This method is simply a short-cut to Config::get('application.encoding'). - * - * @return string - */ - public static function encoding() - { - return Config::get('application.encoding'); - } + /** + * Cache application encoding locally to save expensive calls to Config::get(). + * + * @var string + */ + public static $encoding = null; + + /** + * Get the appliction.encoding without needing to request it from Config::get() each time. + * + * @return string + */ + protected static function encoding() + { + return static::$encoding ?: static::$encoding = Config::get('application.encoding'); + } /** * Get the length of a string. diff --git a/laravel/tests/application/models/model.php b/laravel/tests/application/models/model.php new file mode 100644 index 00000000..cd2c82bd --- /dev/null +++ b/laravel/tests/application/models/model.php @@ -0,0 +1,15 @@ +set_attribute('setter', 'setter: '.$setter); + } + + public function get_getter() + { + return 'getter: '.$this->get_attribute('getter'); + } + +} \ No newline at end of file diff --git a/laravel/tests/cases/auth.test.php b/laravel/tests/cases/auth.test.php index 44ff671e..3be1c1e5 100644 --- a/laravel/tests/cases/auth.test.php +++ b/laravel/tests/cases/auth.test.php @@ -294,9 +294,6 @@ public function testLogoutMethodLogsOutUser() Auth::logout(); - // A workaround since Cookie will is only stored in memory, until Response class is called. - Auth::driver()->token = null; - $this->assertNull(Auth::user()); $this->assertFalse(isset(Session::$instance->session['data']['laravel_auth_drivers_fluent_login'])); diff --git a/laravel/tests/cases/eloquent.test.php b/laravel/tests/cases/eloquent.test.php new file mode 100644 index 00000000..ac489f39 --- /dev/null +++ b/laravel/tests/cases/eloquent.test.php @@ -0,0 +1,292 @@ + 'Taylor', 'age' => 25, 'setter' => 'foo'); + + $model = new Model($array); + + $this->assertEquals('Taylor', $model->name); + $this->assertEquals(25, $model->age); + $this->assertEquals('setter: foo', $model->setter); + } + + /** + * Test the Model::fill method. + * + * @group laravel + */ + public function testAttributesAreSetByFillMethod() + { + $array = array('name' => 'Taylor', 'age' => 25, 'setter' => 'foo'); + + $model = new Model(); + $model->fill($array); + + $this->assertEquals('Taylor', $model->name); + $this->assertEquals(25, $model->age); + $this->assertEquals('setter: foo', $model->setter); + } + + /** + * Test the Model::fill_raw method. + * + * @group laravel + */ + public function testAttributesAreSetByFillRawMethod() + { + $array = array('name' => 'Taylor', 'age' => 25, 'setter' => 'foo'); + + $model = new Model(); + $model->fill_raw($array); + + $this->assertEquals($array, $model->attributes); + } + + /** + * Test the Model::fill method with accessible. + * + * @group laravel + */ + public function testAttributesAreSetByFillMethodWithAccessible() + { + Model::$accessible = array('name', 'age'); + + $array = array('name' => 'Taylor', 'age' => 25, 'foo' => 'bar'); + + $model = new Model(); + $model->fill($array); + + $this->assertEquals('Taylor', $model->name); + $this->assertEquals(25, $model->age); + $this->assertNull($model->foo); + + Model::$accessible = null; + } + + /** + * Test the Model::fill method with empty accessible array. + * + * @group laravel + */ + public function testAttributesAreSetByFillMethodWithEmptyAccessible() + { + Model::$accessible = array(); + + $array = array('name' => 'Taylor', 'age' => 25, 'foo' => 'bar'); + + $model = new Model(); + $model->fill($array); + + $this->assertEquals(array(), $model->attributes); + $this->assertNull($model->name); + $this->assertNull($model->age); + $this->assertNull($model->foo); + + Model::$accessible = null; + } + + /** + * Test the Model::fill_raw method with accessible. + * + * @group laravel + */ + public function testAttributesAreSetByFillRawMethodWithAccessible() + { + Model::$accessible = array('name', 'age'); + + $array = array('name' => 'taylor', 'age' => 25, 'setter' => 'foo'); + + $model = new Model(); + $model->fill_raw($array); + + $this->assertEquals($array, $model->attributes); + + Model::$accessible = null; + } + + /** + * Test the Model::__set method. + * + * @group laravel + */ + public function testAttributeMagicSetterMethodChangesAttribute() + { + Model::$accessible = array('setter'); + + $array = array('setter' => 'foo', 'getter' => 'bar'); + + $model = new Model($array); + $model->setter = 'bar'; + $model->getter = 'foo'; + + $this->assertEquals('setter: bar', $model->get_attribute('setter')); + $this->assertEquals('foo', $model->get_attribute('getter')); + + Model::$accessible = null; + } + + /** + * Test the Model::__get method. + * + * @group laravel + */ + public function testAttributeMagicGetterMethodReturnsAttribute() + { + $array = array('setter' => 'foo', 'getter' => 'bar'); + + $model = new Model($array); + + $this->assertEquals('setter: foo', $model->setter); + $this->assertEquals('getter: bar', $model->getter); + } + + /** + * Test the Model::set_* method. + * + * @group laravel + */ + public function testAttributeSetterMethodChangesAttribute() + { + Model::$accessible = array('setter'); + + $array = array('setter' => 'foo', 'getter' => 'bar'); + + $model = new Model($array); + $model->set_setter('bar'); + $model->set_getter('foo'); + + $this->assertEquals('setter: bar', $model->get_attribute('setter')); + $this->assertEquals('foo', $model->get_attribute('getter')); + + Model::$accessible = null; + } + + /** + * Test the Model::get_* method. + * + * @group laravel + */ + public function testAttributeGetterMethodReturnsAttribute() + { + $array = array('setter' => 'foo', 'getter' => 'bar'); + + $model = new Model($array); + + $this->assertEquals('setter: foo', $model->get_setter()); + $this->assertEquals('getter: bar', $model->get_getter()); + } + + /** + * Test determination of dirty/changed attributes. + * + * @group laravel + */ + public function testDeterminationOfChangedAttributes() + { + $array = array('name' => 'Taylor', 'age' => 25, 'foo' => null); + + $model = new Model($array, true); + $model->name = 'Otwell'; + $model->new = null; + + $this->assertTrue($model->changed('name')); + $this->assertFalse($model->changed('age')); + $this->assertFalse($model->changed('foo')); + $this->assertFalse($model->changed('new')); + $this->assertTrue($model->dirty()); + $this->assertEquals(array('name' => 'Otwell', 'new' => null), $model->get_dirty()); + + $model->sync(); + + $this->assertFalse($model->changed('name')); + $this->assertFalse($model->changed('age')); + $this->assertFalse($model->changed('foo')); + $this->assertFalse($model->changed('new')); + $this->assertFalse($model->dirty()); + $this->assertEquals(array(), $model->get_dirty()); + } + + /** + * Test the Model::purge method. + * + * @group laravel + */ + public function testAttributePurge() + { + $array = array('name' => 'Taylor', 'age' => 25); + + $model = new Model($array); + $model->name = 'Otwell'; + $model->age = 26; + + $model->purge('name'); + + $this->assertFalse($model->changed('name')); + $this->assertNull($model->name); + $this->assertTrue($model->changed('age')); + $this->assertEquals(26, $model->age); + $this->assertEquals(array('age' => 26), $model->get_dirty()); + } + + /** + * Test the Model::table method. + * + * @group laravel + */ + public function testTableMethodReturnsCorrectName() + { + $model = new Model(); + $this->assertEquals('models', $model->table()); + + Model::$table = 'table'; + $this->assertEquals('table', $model->table()); + + Model::$table = null; + $this->assertEquals('models', $model->table()); + } + + /** + * Test the Model::to_array method. + * + * @group laravel + */ + public function testConvertingToArray() + { + Model::$hidden = array('password', 'hidden'); + + $array = array('name' => 'Taylor', 'age' => 25, 'password' => 'laravel', 'null' => null); + + $model = new Model($array); + + $first = new Model(array('first' => 'foo', 'password' => 'hidden')); + $second = new Model(array('second' => 'bar', 'password' => 'hidden')); + $third = new Model(array('third' => 'baz', 'password' => 'hidden')); + + $model->relationships['one'] = new Model(array('foo' => 'bar', 'password' => 'hidden')); + $model->relationships['many'] = array($first, $second, $third); + $model->relationships['hidden'] = new Model(array('should' => 'visible')); + $model->relationships['null'] = null; + + $this->assertEquals(array( + 'name' => 'Taylor', 'age' => 25, 'null' => null, + 'one' => array('foo' => 'bar'), + 'many' => array( + array('first' => 'foo'), + array('second' => 'bar'), + array('third' => 'baz'), + ), + 'hidden' => array('should' => 'visible'), + 'null' => null, + ), $model->to_array()); + + } + +} \ No newline at end of file diff --git a/laravel/view.php b/laravel/view.php index d8275c6e..5ac37520 100644 --- a/laravel/view.php +++ b/laravel/view.php @@ -44,6 +44,13 @@ class View implements ArrayAccess { */ public static $cache = array(); + /** + * THe last view to be rendered. + * + * @var string + */ + public static $last; + /** * The Laravel view loader event name. * @@ -367,7 +374,17 @@ public function get() ob_get_clean(); throw $e; } - return ob_get_clean(); + $content = ob_get_clean(); + + // The view filter event gives us a last chance to modify the + // evaluated contents of the view and return them. This lets + // us do something like run the contents through Jade, etc. + if (Event::listeners('view.filter')) + { + return Event::first('view.filter', array($content, $this->path)); + } + + return $content; } /** @@ -377,6 +394,8 @@ public function get() */ protected function load() { + static::$last = array('name' => $this->view, 'path' => $this->path); + if (isset(static::$cache[$this->path])) { return static::$cache[$this->path]; diff --git a/public/index.php b/public/index.php index 3b213a95..f58e72f6 100644 --- a/public/index.php +++ b/public/index.php @@ -3,7 +3,7 @@ * Laravel - A PHP Framework For Web Artisans * * @package Laravel - * @version 3.2.8 + * @version 3.2.9 * @author Taylor Otwell * @link http://laravel.com */