Welcome to the fourth instalment of Laravel Digest, the series where I give a regular rundown of important changes, fixes and additions to Laravel’s master branch. Due to the release of Laravel 4.1 I’ve decided to bring this post forward to match the status of Laravel on the day(ish) of release. As such, below are the changes up to the middle of December 2013:

  • Collection#first can now have a closure (and default) passed to it that will be passed into a array_first-like call (d600ebe):
1
2
3
4
5
6
7
8
9
<?php

// get all users
$users = User::all();

// get first that is enabled or string 'None' if none match
$firstEnabled = $users->first(function ($key, $model) {
    return $model->enabled == 1;
}, 'None'); // obviously an awful example in terms of what it returns

Welcome to the third instalment of Laravel Digest, the series where I give a regular rundown of important changes, fixes and additions to Laravel’s master branch. Below are the changes up to the end of November 2013:

  • Relationships can now reference any key on the parent model using a new last parameter for each of the \Eloquent\Model methods (belongsTo: c7d2740, hasOne, hasMany, morph relationships: a634f45):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

class User extends Eloquent
{
    // belongsTo
    public function group()
    {
        return $this->belongsTo('Group', 'group', 'name');
    }

    // hasOne
    public function city()
    {
        return $this->hasOne('City', 'city', 'name');
    }

    // hasMany
    public function roles()
    {
        return $this->hasMany('Role', 'role', 'type');
    }

    // etc...
}
  • Builder#has method now maintains a query’s constraints (7196279)

  • Scoped queries now return the value from the scope method for better chaining (23adaa4)

    • In case you’re confused how this is new functionality (I was), previously, the magic method that called your custom scope method ignored what you returned and instead returned the Builder instance (which to be honest is the 95%+ use case anyway), but it now returns what you actually return from your scope method (so if you weren’t already, make sure you return the Builder instance!)
  • has queries got even better: new whereHas() and orWhereHas() that allow you to set specific constraints on the has relation (a634f45):

1
2
3
4
5
6
<?php
// get all users with posts pre-attached, but only users with
// at least one post that is more than a year old
User::with('posts')->whereHas('posts', function ($query) {
    $query->where('created_at', '<', Carbon::now()->subYears(1));
})->get();

I’m not sure right now if the whereHas affects the with (i.e. what actually gets returned pre-attached) or just the mechanism for filtering the original model by the relationship. My guess is the latter.

1
2
3
4
<!-- this -->
<div>Hello, {{ isset($username) ? $username : 'anonymous' }}.</div>
<!-- can now be done like this -->
<div>Hello, {{ $username or 'anonymous' }}.</div>
  • Cache entries can now be tagged. New functionality includes using Cache::tags to get a list of the tags used in the cache, and items can be flushed by tag (70108fe)

  • Laravel now sends X-frame-Options: SAMEORIGIN by default in the HTTP headers (15513cc)

  • belongsToMany relations now have a firstOrFail method (b162579)

  • Schema builder now has nullableTimestamps method that creates timestamps as normal but makes them nullable fields (a44fbab)

  • Joins can now have complex conditions if joinWhere or leftJoinWhere are used (a644ea0)

  • New required_without_all validation rule that works like required_without but checks that at least one of the specified fields is present rather than all fields (93c1045)

  • Original method that was attempted is passed to Controller#missingMethod now as the first parameter, with the additional parameters as an array as the second parameter (de871fe)

  • New Blade @append method (f0ae98b):

1
2
3
4
5
6
7
8
9
@section('content')
Some content for the content section
@append

...

@section('content')
Some more content for the content section
@append
  • New query builder rememberForever method (c681584)

  • New Eloquent model booting and booted methods (2dfb383)

  • View#withErrors now accepts an optional parameter that is a object that implements MessageProviderInterface (i.e. can be asked for a MessageBag)(3c5ca1a)

    • Use case here is for validators: View::make('some.view')->withErrors($validator);
  • A big change to password resetting/reminder stuff (f86d5ea)

  • Collection#splice now returns the extracted elements (if any) as a new Collection (32f107d)

  • Commas are now allowed in route wildcards (fdd378b)

  • Using host detection in bootstrap/start.php you should now just use the machine name rather than HTTP_HOST, this change is good because it bridges artisan and HTTP environment detection (laravel/laravel@a297fe8)

  • On a BelongsToMany relationship, you can now use wherePivot and orWherePivot to add constraints to the pivot table conveniently (5d48577)

  • Database layer can now have separate connections for reading and writing. I’m not entirely sure why this was added but maybe it’s useful to some (a3b0e87). As I understand it from the tests, you can just override any settings from the connection’s config array in the read or write keys:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

// app/config/database.php

return array(
    // ...

  'connections' => array(
        'mysql' => array(

            // default settings for read/write for this connection
            'driver'    => 'mysql',
            'host'      => '127.0.0.1',
            'database'  => 'laravel',
            'username'  => 'user',
            'password'  => 'pass',
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',

            // read-specific overrides
            'read' => array(
                'database' => 'laravel_read',
            ),
        ),
    ),
);
  • Lots of work on queues (in particular releasing jobs back to the queue for Iron.io queues, as well as logging failed queue jobs into a database connection) (multiple commits).

  • Collection class now has merge, diff and intersect methods to work with multiple collections (2f54024).

  • Paginator has a new method fragment which can be used to set the fragment to be appended to the URIs generated by the paginator (if passed a string) or get the current fragment (if the argument is omitted or null) (ea9a924):

1
2
3
4
<?php

$paginator->fragment('my-frag'); // sets the fragment to be 'my-frag'
echo $paginator->fragment(); // echoes the current fragment (i.e. 'my-frag')
  • Eloquent’s Collection#find can now accept a model as the ‘key’ and it’ll search in the collection for a model which has the same key as the passed model (362db89):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

// get all enabled pages
$pages = Page::whereEnabled(1)->get();

// get page with id of 1
$page  = Page::find(1);

// before:
if ($pages->contains($page->getKey())) {
    // do something
}

// now:
if ($pages->contains($page)) {
    // do something
}
  • Locking added to QueryBuilder (a331432):
    • $builder->lockForUpdate() – same as calling $builder->lock(true)
    • $builder->sharedLock() – same as calling $builder->lock(false)
    • $builder->lock([string|boolean])
      • If true, signifies the row should be locked for update
      • If false, signifies that the row should be locked for share
      • If a string, the string will be used as the text to go in the ‘lock’ part of the query
    • It would appear that even if you don’t do anything to do with locks, you will now always get the shared lock due to the way the lock variable is handled, but maybe I’m wrong there, or maybe that’s implicit in RDBMSes anyway so it doesn’t harm anyone

Welcome to the second instalment of Laravel Digest, the series where I give a regular rundown of important changes, fixes and additions to Laravel’s master branch. Below are the changes up to the end of October 2013:

  • Blade braces can now be escaped using @ which is useful for people using clientside templating languages that also use the braces (cb93bf3):

The following code will output hello

1
{{ 'hello' }}

The following code will output {{ $variable }}

1
@{{ $variable }}

Use case, using handlebars.js:

1
<div class="name">@{{ user.name }}</div>
  • Queued cookies – because cookies can only be attached to a request, using Cookie::set() before the request was instantiated previous lost the cookie (or simply wasn’t allowed). Now Cookie::queue() can be used to queue cookies for eventual sending with the request.

  • Route::controller is back and appears slightly cleverer than before in that it first seeks out all callable methods on the given controller and adds each route individually, then sets up a ‘default’ route for anything it can’t detect (98c14a9)

    • Route::controllers can also be used to hook multiple controllers up in one go by passing an associative array of uri to controller FQCN
  • App::env() can now be used to check the environment against a list provided (array or multiple arguments) (66e5a0b)

  • Remote tail command (artisan tail) allows tailing of a remote log file (assuming the remote connection is set up correctly in the config and the remote project uses a single log file) (25b1cac)

    • As a consequence of this work, the logging system was simplified down to a single log file by default (no daily rotation and no SAPI name, this looks like it may generate rather large log files to me, I’d have preferred to keep daily rotation) (laravel/laravel@088f4b6)
    • Also as a consequence, the live debugging through sockets was removed. Now the tail command will tail a remote log file if there’s a remote connection specified, or tail the local log file if there’s no remote connection specified (f62d1a7/763a0265)
  • New Router::input() method that allows you to get the value of a named route parameter (28e36bb)

  • Controller filters can now be added as controller functions using the @ syntax as a shorthand (see issue 2432) (d0e0c63):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

class UserController extends Contoller
{
    public function __construct()
    {
        // before:
        $this->beforeFilter(function ($route) {
            return $this->hasPermission($route);
        }, ['only' => 'edit']);

        // after, shorthand
        $this->beforeFilter('@hasPermission', ['only' => 'edit']);
    }

    public function hasPermission($route)
    {
        $id = $route->getParameter('id');

        if (! Auth::user()->ownsPost($id)) {
            return Response::make('You are not authorised to edit this post', 401);
        }
    }
}
  • Can now pass DateTime and Carbon instances to Cache method that accept a duration (in this case, the time difference between now and the time passed is calculated in minutes) (977f803)

  • Now uses Stack for middleware (multiple commits). Repercussions:

    • close application hook is now deprecated in favour of using a stack middleware (18e1aec)
    • Presumably more…
  • Should now use Input::cookie for cookies, not Cookie::get (e0fe79e removed Cookie::get() and 58ec2fe for temporary deprecation code in the facade)

  • If using MySQL, UPDATE queries can now have orderBy and limit specified (d9d61e1)

  • As with overriding packages’ config and views, translations can now be overridden using a similar convention (5483042)

    • It should be noted that the convention is not the same: it is not app/lang/packages/vendor/package/ but uses the namespace (i.e. package name) only, like when referencing views/config (i.e. View::make('namespace:path.view') and Config:get('namespace:config.key'))

    • Files for a package vendor/package in locale en should go in app/lang/packages/en/package/ — see how it’s just package not vendor/package like it would be for config and views

    • So to reiterate, for a package called vendor/package:

      • Views: View::make('package::some/view')app/views/packages/vendor/package/some/view{.blade}.php
      • Config: Config::get('package::some.key')app/config/packages/vendor/package/some.php, then key key
      • Translations: Lang::get('package::some.key')app/lang/packages/en/package/some.php, then key key
  • You can now use Auth::viaRemember() to determine whether the logged-in user was authorised through the ‘remember me’ cookie or not (2184ad4)

  • New bindShared method on the IoC container which should now be used in place of the old share syntax (07233b3):

1
2
3
4
5
6
7
8
9
// this
$this->app['my.key'] = $this->app->share(function ($app) {
    return new MyClass();
});

// becomes this
$this->app->bindShared('my.key', function ($app) {
    return new MyClass();
});
  • ServiceProvider no longer uses very weird logic to guess a package’s namespace. This probably won’t affect many people but I’m pointing it out as it has affected me and it’s good to know for future reference (6089525)

  • You can now pass a view to Paginator::links([$view]) in order to override the default view for that call (9d1150c)

  • New hasManyThrough relation type (0925d86)

    • There’s no real documentation on this yet and the tests are a little cryptic, so I’ll talk more about this in the next update.
  • Validator::make can now take a fourth parameter that specified the custom parameters for the validator. Presumably to be used by custom validators. (93977e4)

  • IoC container old resolving method is now renamed to resolvingAny and now there’s a new resolving method in its place that accepts an abstract object type to only be fired when that abstract type is being resolved (aa6df0a)

  • Any alaises bound to a given IoC key will now be removed when rebinding the key (8f240f8)

  • Queue workers will no no longer run if the application is in maintenance mode (a8cdb68)

Composer’s been around for some time now, and gained a lot of popularity since its use in Laravel 4. I noticed back in the first half of 2013 that a lot of blogs and tutorials were teaching installation of packages (or, more correctly, addition of project dependencies) by editing your composer.json file’s require array and then doing a composer update on the command line. I thought back then that maybe because composer was new to these people (in general these were related to Laravel 4 which was in development at the time) they hadn’t yet discovered the easier, and technically less error-prone, way to do this that very few people seemed to be using and advising: composer require

Well it seems that most people still haven’t discovered the command, so I figured I would write about it. Instead of (possibly erroneously) manually editing your composer.json file to add a new package to your project’s dependencies and then calling composer update, you can use composer require to do the job for you. You’re having to use the command line anyway, so why not skip the manual editing of composer.json part?

The syntax is really simple:

composer require vendor/package version

It’s as easy as that. And you can even require a dev dependency with the --dev option:

composer require mockery/mockery 0.8.0 --dev

In fact, the command can be used to add multiple packages to your project’s dependencies by simply separating them with a space. In this case, it’s probably best to use the alternative version constraint syntax which is vendor/package:version or vendor/package=version:

composer require --dev mockery/mockery:0.8.0 phpunit/phpunit:~3.7.4

Also notice how the --dev can go either before or after the packages — use what works best for you.

Another good thing about it is that if anything goes wrong during installation of the packages or their dependencies then Composer will leave your composer.json file unchanged.


There is one caveat to this: if you wish to use the asterisk to denote any patch or minor version is okay, then it’s best to put the argument in question in quotes so that your shell doesn’t try (and probably fail) to interpret it as a glob on the filesystem. In my case (using fish) the following happens:

> composer require mockery/mockery 0.8.* --dev
fish: No matches for wildcard '0.8.*'.
composer require mockery/mockery 0.8.* --dev
                                 ^

However, with the argument quoted it’s all good:

composer require "mockery/mockery 0.8.*" --dev

Introducing Laravel digest, where I let you know what’s changed in the most recent commits to Laravel. I like to think of it as me reading the commitlog so you don’t have to. The general idea is that I’ll list out any notable changes on the master branch (although really I’m looking at both master and 4.0) since the previous update. I pretty much decide what’s classed as notable, but usually it’ll be stuff that actually affects the way developers work, so small bugfixes won’t be in, but new features or uses of existing components are included.

As this is the first installment of Laravel digest there’s no “since last time” so I’m arbitrarily deciding its since about mid-September. A fortnight seems like a good period of time between updates (and maybe longer where Taylor has less time to spend on the framework).

So, without further ado:

Notable recent changes (since approx. 15 September 2013) on master specifically (but most apply to 4.0 too):

  • artisan tinker is now a full REPL using Boris (5e8d2c0)

    • It does, however, require ext_readline and ext_posix if you want to use it though (ouch!)
  • Views can have data added eloquently (e7fd520)

1
2
3
4
5
6
7
8
9
10
<?php

// this
return View::make('view.name')->with(['user' => $user]);

// or this
return View::make('view.name', ['user' => $user]);

// becomes this
return View::make('view.name')->withUser($user);
  • View composers can have a priority attached so they run in a given order (fb4fe45)

  • Developers can specify a protected instance dates array in their Eloquent models that returns an array of fields that should be treated like dates (f15b034)

  • Query builder/Eloquent now has a chunk method that allows for working through large datasets without killing RAM usage (11d3e98):

1
2
3
4
5
6
7
8
<?php

User::whereActive('1')->chunk(
    100, // per chunk
    function($results) {
        // do something with set of 100 results at a time
    }
);
  • Route::group config array now accepts a namespace string that will automatically prefix controller names with the namespace – they can even be nested (3d0400e)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

// something a bit like this
Route::group(
    ['prefix' => 'admin'],
    function() {
        Route::get('some/url', 'MyApp\\Admin\\UserController@index');
        Route::get('some/other/url', 'MyApp\\Admin\\UserController@edit');
    }
);

// can become the slightly cleaner
Route::group(
    ['prefix' => 'admin', 'namespace' => 'MyApp\\Admin'],
    function() {
        Route::get('users', 'UserController@index');
        Route::get('user/edit', 'UserController@edit');
    }
);
  • Query builder/Eloquent can now find multiple rows with find() by passing an array (911e08b)
1
2
3
4
<?php

// get users 1 and 5
$users = User::find([1, 5]);
  • Can get current environment using artisan env (useful for debugging weird database connection issues with artisan – not so useful for knowing what environment the web site is running as artisan and the running web instance will use different methods to determine the environment, so they could quite easily be different) (5c7ba12)

  • Can now return an ArrayObject from a route action and it’ll be serialised as JSON (previously it was just just bare arrays and JsonableInterface objects) (bd4b0c6)

  • Packages’ views can now be published (like config and assets were) using artisan view:publish (44a27da)

  • Paginator can now be returned from a route action and it’ll be serialised to JSON (good for paginated responses in APIs) (5875b60)

  • Eloquent query builder now has firstOrNew and firstOrCreate methods (fce86bc):

    • firstOrNew tries to use the passed array of attributes to find the model, and if it can’t find it it’ll create a new (unsaved) instance of the model
    • firstOrCreate tries to use the passed array of attributes to find the model, and if it can’t find it it’ll create a new instance of the model and save it immediately
    • Implementation note: this also uses a convenient new method firstByAttributes which is unfortunately protected in Illuminate\Database\Eloquent\Model. The method is nothing special, just cycles through the array adding wheres to a query builder
  • new Redirect::away method allows passing of any URL – the passed URL is not validated, works just like Redirect::to otherwise (8c47d11)

  • Remote feature now allows setting the port (3f7c47c)

  • Like the Eloquent view data from e7fd520, redirects can do the same (97bbfe6):

1
2
3
<?php

Redirect::route('login')->withMessage('Please log in');
  • Validator now has a sometimes method that allows to set conditional rules (ffa70d3, docs):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

// say we're validating some kind of user type - if 'business_type' is set
// to 'business' then 'business_name' is requied

$v = Validator::make($data, [
    'email'        => 'required|email',
    'name'         => 'required',
    'license_type' => 'required',
]);

// this rule only applies when the closure returns true
$v->sometimes('business_name', 'required', function($input) {
    return $input->license_type == 'business';
});

The first parameter to sometimes can be an array that specifies multiple rules:

1
2
3
4
5
6
7
8
9
10
11
12
<?php

// Example: in the checkout area of an ecommerce site, only require the delivery
// fields to be set if the 'deliver to my billing address' field is not checked

$v->sometimes(
    ['delivery_name', 'delivery_address', 'delivery_country' /* etc. */],
    'required',
    function($input) {
        return $input->deliver_to_billing_address != 'yes';
    }
);