Laravel 5 Package Development: The Service Provider

Laravel

Let's take a look at upgrading a package service provider to work with Laravel 5. The service provider is intended to inform the application of the package's existance and register its assets. Exactly how this is done will vary depending on the needs of the pacakge, but there are several common items which we will discuss here: Configuration, Language Files, Views and Public Assets. John Hout has a great write up about this, which I will be expanding on.

Two important things before we begin. First have to remove this line from our boot() method, because it is no longer needed:

$this->package('rydurham/sentinel');

Secondly, Laravel 5 now ships with a vendor:publish command, which greatly simplifies copying files from the vendor/package directory into the main application. Any folders or files added to the $this->publishes array in the boot() method will be published when you run the vendor:publish command. (Vendor in this case is literally 'vendor', not the vendor name of your package.) As per the documentation, add this to your boot() command:

1public function boot()
2{
3 // ...
4
5 $this->publishes([
6 __DIR__.'/path/to/file1.php' => base_path('location/in/main/application/file1.php'),
7 __DIR__.'/path/to/directory' => base_path('location/in/main/application/directory'),
8 // Add as items as you want, pointing to any location.
9 // Works with both files and directories
10 ]);
11
12 // ...
13}
ServiceProvider.php

Configuration

Configuration management in Laravel 5 has been greatly simplified, and there is no longer a need for accessing config options via a namespace. Add your package config file to the $this->publishes array and publish it to the main application config folder: base_path('config/sentinel.php'). You can name it whatever you want, but I would reccomend giving it the same name as your package.

Accessing config values can be done in the same way you are used to:

Config::get('sentinel.allow_usernames')

or you can use this new helper function:

config('sentinel.allow_usernames')

It is possible that someone using your package may not publish the config file, or they only have a subset of the configurable values in their local version of the config file. In those situations it can be beneficial to selectively merge their config file with the default config file in the package repository. This can be done with the mergeConfigFrom method in the boot function:

1public function boot()
2{
3 // ...
4
5 $this->mergeConfigFrom(__DIR__.'/../config/sentinel.php', 'sentinel');
6
7 // ...
8}
ServiceProvider.php

Views and Assets

Package views can still be accessed via a namespace. In lieu of the old view:publish command, you should add your views to the publishes array. The loadViewsFrom function allows you to register the view namespace, however you may want to check to see if the views have been published before you create the namespace:

1public function boot()
2{
3 // ...
4
5 // Establish Views Namespace
6 if (is_dir(base_path() . '/resources/views/packages/rydurham/sentinel')) {
7 // The package views have been published - use those views.
8 $this->loadViewsFrom(base_path() . '/resources/views/packages/rydurham/sentinel', 'Sentinel');
9 } else {
10 // The package views have not been published. Use the defaults.
11 $this->loadViewsFrom(__DIR___ . '/../views/bootstrap', 'sentinel');
12 }
13
14 // ...
15}
ServiceProvider.php

Assets like javascript files or images should be added to the publishes array and pointed to the public folder.

Language Files

Making translation files available to the application is very straightforward, and translation strings can still be accessed with the trans() function using a namespace:

1public function boot()
2{
3 // ...
4
5 // Establish Translator Namespace
6 $this->loadTranslationsFrom(__DIR__ . '/../lang', 'Sentinel');
7
8 // ...
9}
ServiceProvider.php

Controllers & Routes

Some packages might make use of their own controllers and routing. To add routes, just include the routes.php file as such:

1public function boot()
2{
3 // ...
4
5 // Add Sentinel Routes
6 include __DIR__ . '/../routes.php';
7
8 // ...
9}
ServiceProvider.php

Controllers should be namespaced, and autoloaded via the composer.json file:

1"autoload": {
2 "classmap": [
3 "src/seeds",
4 "src/controllers"
5 ],
6 "psr-4": {
7 "Sentinel\\": "src/Sentinel"
8 }
9},
composer.json

Resources

About the Author

Ryan Durham is a software developer who lives in Portland, Oregon, with his wife and daughter. His numerous areas of interest include PHP, Laravel, Elixir and PostgreSQL, as well as organizational efficiency and communications strategies.

You can find him on GitHub and LinkedIn.