Package Development

Introduction

Packages are the primary way of adding functionality to Laravel. Packages might be anything from a great way to work with dates like Carbon, or an entire BDD testing framework like Behat.

Of course, there are different types of packages. Some packages are stand-alone, meaning they work with any framework, not just Laravel. Both Carbon and Behat are examples of stand-alone packages. Any of these packages may be used with Laravel by simply requesting them in your composer.json file.

On the other hand, other packages are specifically intended for use with Laravel. In previous versions of Laravel, these types of packages were called "bundles". These packages may have routes, controllers, views, configuration, and migrations specifically intended to enhance a Laravel application. As no special process is needed to develop stand-alone packages, this guide primarily covers the development of those that are Laravel specific.

All Laravel packages are distributed via Packagist and Composer, so learning about these wonderful PHP package distribution tools is essential.

Creating A Package

The easiest way to create a new package for use with Laravel is the workbench Artisan command. First, you will need to set a few options in the app/config/workbench.php file. In that file, you will find a name and email option. These values will be used to generate a composer.json file for your new package. Once you have supplied those values, you are ready to build a workbench package!

Issuing The Workbench Artisan Command

  1. php artisan workbench vendor/package --resources

The vendor name is a way to distinguish your package from other packages of the same name from different authors. For example, if I (Taylor Otwell) were to create a new package named "Zapper", the vendor name could be Taylor while the package name would be Zapper. By default, the workbench will create framework agnostic packages; however, the resources command tells the workbench to generate the package with Laravel specific directories such as migrations, views, config, etc.

Once the workbench command has been executed, your package will be available within the workbench directory of your Laravel installation. Next, you should register the ServiceProvider that was created for your package. You may register the provider by adding it to the providers array in the app/config/app.php file. This will instruct Laravel to load your package when your application starts. Service providers use a [Package]ServiceProvider naming convention. So, using the example above, you would add Taylor\Zapper\ZapperServiceProvider to the providers array.

Once the provider has been registered, you are ready to start developing your package! However, before diving in, you may wish to review the sections below to get more familiar with the package structure and development workflow.

Note: If your service provider cannot be found, run the php artisan dump-autoload command from your application's root directory

Package Structure

When using the workbench command, your package will be setup with conventions that allow the package to integrate well with other parts of the Laravel framework:

Basic Package Directory Structure

  1. /src
  2. /Vendor
  3. /Package
  4. PackageServiceProvider.php
  5. /config
  6. /lang
  7. /migrations
  8. /views
  9. /tests
  10. /public

Let's explore this structure further. The src/Vendor/Package directory is the home of all of your package's classes, including the ServiceProvider. The config, lang, migrations, and views directories, as you might guess, contain the corresponding resources for your package. Packages may have any of these resources, just like "regular" applications.

Service Providers

Service providers are simply bootstrap classes for packages. By default, they contain two methods: boot and register. Within these methods you may do anything you like: include a routes file, register bindings in the IoC container, attach to events, or anything else you wish to do.

The register method is called immediately when the service provider is registered, while the boot command is only called right before a request is routed. So, if actions in your service provider rely on another service provider already being registered, or you are overriding services bound by another provider, you should use the boot method.

When creating a package using the workbench, the boot command will already contain one action:

  1. $this->package('vendor/package');

This method allows Laravel to know how to properly load the views, configuration, and other resources for your application. In general, there should be no need for you to change this line of code, as it will setup the package using the workbench conventions.

By default, after registering a package, its resources will be available using the "package" half of vendor/package. However, you may pass a second argument into the package method to override this behavior. For example:

  1. // Passing custom namespace to package method
  2. $this->package('vendor/package', 'custom-namespace');
  3. // Package resources now accessed via custom-namespace
  4. $view = View::make('custom-namespace::foo');

There is not a "default location" for service provider classes. You may put them anywhere you like, perhaps organizing them in a Providers namespace within your app directory. The file may be placed anywhere, as long as Composer's auto-loading facilities know how to load the class.

If you have changed the location of your package's resources, such as configuration files or views, you should pass a third argument to the package method which specifies the location of your resources:

  1. $this->package('vendor/package', null, '/path/to/resources');

Deferred Providers

If you are writing a service provider that does not register any resources such as configuration or views, you may choose to make your provider "deferred". A deferred service provider is only loaded and registered when one of the services it provides is actually needed by the application IoC container. If none of the provider's services are needed for a given request cycle, the provider is never loaded.

To defer the execution of your service provider, set the defer property on the provider to true:

  1. protected $defer = true;

Next you should override the provides method from the base Illuminate\Support\ServiceProvider class and return an array of all of the bindings that your provider adds to the IoC container. For example, if your provider registers package.service and package.another-service in the IoC container, your provides method should look like this:

  1. public function provides()
  2. {
  3. return array('package.service', 'package.another-service');
  4. }

Package Conventions

When utilizing resources from a package, such as configuration items or views, a double-colon syntax will generally be used:

Loading A View From A Package

  1. return View::make('package::view.name');

Retrieving A Package Configuration Item

  1. return Config::get('package::group.option');

Note: If your package contains migrations, consider prefixing the migration name with your package name to avoid potential class name conflicts with other packages.

Development Workflow

When developing a package, it is useful to be able to develop within the context of an application, allowing you to easily view and experiment with your templates, etc. So, to get started, install a fresh copy of the Laravel framework, then use the workbench command to create your package structure.

After the workbench command has created your package. You may git init from the workbench/[vendor]/[package] directory and git push your package straight from the workbench! This will allow you to conveniently develop the package in an application context without being bogged down by constant composer update commands.

Since your packages are in the workbench directory, you may be wondering how Composer knows to autoload your package's files. When the workbench directory exists, Laravel will intelligently scan it for packages, loading their Composer autoload files when the application starts!

If you need to regenerate your package's autoload files, you may use the php artisan dump-autoload command. This command will regenerate the autoload files for your root project, as well as any workbenches you have created.

Running The Artisan Autoload Command

  1. php artisan dump-autoload

Package Routing

In prior versions of Laravel, a handles clause was used to specify which URIs a package could respond to. However, in Laravel 4, a package may respond to any URI. To load a routes file for your package, simply include it from within your service provider's boot method.

Including A Routes File From A Service Provider

  1. public function boot()
  2. {
  3. $this->package('vendor/package');
  4. include __DIR__.'/../../routes.php';
  5. }

Note: If your package is using controllers, you will need to make sure they are properly configured in your composer.json file's auto-load section.

Package Configuration

Accessing Package Configuration Files

Some packages may require configuration files. These files should be defined in the same way as typical application configuration files. And, when using the default $this->package method of registering resources in your service provider, may be accessed using the usual "double-colon" syntax:

  1. Config::get('package::file.option');

Accessing Single File Package Configuration

However, if your package contains a single configuration file, you may simply name the file config.php. When this is done, you may access the options directly, without specifying the file name:

  1. Config::get('package::option');

Registering A Resource Namespace Manually

Sometimes, you may wish to register package resources such as views outside of the typical $this->package method. Typically, this would only be done if the resources were not in a conventional location. To register the resources manually, you may use the addNamespace method of the View, Lang, and Config classes:

  1. View::addNamespace('package', __DIR__.'/path/to/views');

Once the namespace has been registered, you may use the namespace name and the "double colon" syntax to access the resources:

  1. return View::make('package::view.name');

The method signature for addNamespace is identical on the View, Lang, and Config classes.

Cascading Configuration Files

When other developers install your package, they may wish to override some of the configuration options. However, if they change the values in your package source code, they will be overwritten the next time Composer updates the package. Instead, the config:publish artisan command should be used:

  1. php artisan config:publish vendor/package

When this command is executed, the configuration files for your application will be copied to app/config/packages/vendor/package where they can be safely modified by the developer!

Note: The developer may also create environment specific configuration files for your package by placing them in app/config/packages/vendor/package/environment.

Package Views

If you are using a package in your application, you may occasionally wish to customize the package's views. You can easily export the package views to your own app/views directory using the view:publish Artisan command:

  1. php artisan view:publish vendor/package

This command will move the package's views into the app/views/packages directory. If this directory doesn't already exist, it will be created when you run the command. Once the views have been published, you may tweak them to your liking! The exported views will automatically take precedence over the package's own view files.

Package Migrations

Creating Migrations For Workbench Packages

You may easily create and run migrations for any of your packages. To create a migration for a package in the workbench, use the —bench option:

  1. php artisan migrate:make create_users_table --bench="vendor/package"

Running Migrations For Workbench Packages

  1. php artisan migrate --bench="vendor/package"

Running Migrations For An Installed Package

To run migrations for a finished package that was installed via Composer into the vendor directory, you may use the —package directive:

  1. php artisan migrate --package="vendor/package"

Package Assets

Moving Package Assets To Public

Some packages may have assets such as JavaScript, CSS, and images. However, we are unable to link to assets in the vendor or workbench directories, so we need a way to move these assets into the public directory of our application. The asset:publish command will take care of this for you:

  1. php artisan asset:publish
  2. php artisan asset:publish vendor/package

If the package is still in the workbench, use the —bench directive:

  1. php artisan asset:publish --bench="vendor/package"

This command will move the assets into the public/packages directory according to the vendor and package name. So, a package named userscape/kudos would have its assets moved to public/packages/userscape/kudos. Using this asset publishing convention allows you to safely code asset paths in your package's views.

Publishing Packages

When your package is ready to publish, you should submit the package to the Packagist repository. If the package is specific to Laravel, consider adding a laravel tag to your package's composer.json file.

Also, it is courteous and helpful to tag your releases so that developers can depend on stable versions when requesting your package in their composer.json files. If a stable version is not ready, consider using the branch-alias Composer directive.

Once your package has been published, feel free to continue developing it within the application context created by workbench. This is a great way to continue to conveniently develop the package even after it has been published.

Some organizations choose to host their own private repository of packages for their own developers. If you are interested in doing this, review the documentation for the Satis project provided by the Composer team.