While recently reading some threads on laravel.io, I stumbled across this particular thread. Essentially, it is a rather short discussion on how, at the time of the threads creation, Laravel 5 seems to have removed its workbench feature.

The workbench feature allowed Laravel developers to quickly create packages targeting the Laravel framework. It would create the directory structure, some classes and construct a composer.json file and a few other files for you. Pretty awesome.

This is Still a Concept

This a disclaimer up-front: there is no source code publicly available for this project - yet. As it is still very early, and is only a concept. I am publicly releasing this article to gauge interest and gather some feedback. Thoughts might seem disjointed and may now flow - proceed with caution.

It's Not Bad That Workbench Been Removed

I cannot say for sure that workbench will never back. It might. It might not. It might become a first-party package, maybe even a third-party package. Who knows? I do know know that it shouldn't. In the PHP world we have composer - a super awesome dependency manager. Composer is great for managing any external dependencies your projects might have. And I honestly believe the PHP world is better for it's existence. As great as it is, however, it doesn't offer that many options for creating the packages. And why should it?

We Need a Package Creator or Builder

We need a tool that can build or make projects. Use whatever constructive verb you want. The idea is that we have a command line utility that makes creating new projects/packages/whatever much easier. This utility would not replace composer, in fact, it would rely heavily on composer. Instead of creating a package template distribution system, and managing access and scaling we could just use composer. After all - it's what composer was designed to do.

Package templates are packages.

How to Manage Templates?

Templates would be packages, developed by individuals, companies - you know, people who already write code. Templates would be made available on Packagist for the open source community, and companies could just utilize products like Toran Proxy or Satis for managing private templates within their organization. These templates would have a special file including in the root folder: pagix.json. This file would contain instructions for the package generator engine.

Defining Templates

These instructions would be fairly simple. They might be instructions to gather information from the user that is required for the template, conditions on when to create folders, and even which commands should be run after a package is created.

An example pagix.json file might look like this:

{
    "name": "example/pagix",
    "description": "An example Pagix JSON file.",

    "ask": [
        {"for": "packageName", "message": "What is the name of your new package?", "isPackage": true},
        {"for": "email", "message": "What is your email?"},
        {"for": "name", "message": "What is your name?"},
        {"for": "license", "message": "What is the license of your package?"}
    ],

    "after": [
        {"run": "composer install"}
    ]
}

The above example file would ask the user for the package name, their email, name and what license their package should use. It also says that after the package is created, the engine should run composer install in the package directory. Fairly straightforward.

The engine would hold all of those values, and most likely some default values, such as the engine version number, etc. Template authors could then use placeholders within their template, and the engine would modify them as needed.

Template File Contents

For example, we could instruct the template engine to build a composer.json file that would typically see in a Laravel 4 package like so:

{
    "name": "@packageName@",
    "description": "",
    "license": "@license@",
    "authors": [
        {
            "name": "@name@",
            "email": "@email@"
        }
    ],
    "require": {
        "illuminate/support": "4.2.*"
    }
    "autoload": {
        "psr-4": {
            "@vendor|studly@\\@package|studly@\\": "src/@package|studly@/"
        }
    }
}

Placeholders inside files would be the name of the information, such as email surrounded by the @ symbol. When the engine sees @email@ it would then know to replace that with whatever value is associated with email.

Formatters can also be observed in the above example. @package|studly@ instructs the engine to take whatever value is stored for package and apply a format function studly to it before replacing the value. This means that a value of pagix would be formatted to Pagix before it is substituted in the template.

These would be available as formatters from the start:

  • studly
  • camel
  • title
  • singular
  • snake

With the placeholders and the formatters, developers could create some interesting templates. For example, a Laravel service provider class:

<?php namespace @vendor|studly@\@package|studly@;

use Illuminate\Support\ServiceProvider;

class @package|studly@ServiceProvider extends ServiceProvider {

        public function boot()
        {
            $this->package('@packageName@');
        }

        /**
         * Indicates if loading of the provider is deferred.
         *
         * @var bool
         */
        protected $defer = false;

        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {

        }

        /**
         * Get the services provided by the provider.
         *
         * @return array
         */
        public function provides()
        {
            return array();
        }

}

Although it might look complicated, it is simply a standard section of PHP code, with some special placeholders and formatters in place. If we were to create a new project with the name my/project the resulting service provider might look like this:

<?php namespace My\Package;

use Illuminate\Support\ServiceProvider;

class PacakgeServiceProvider extends ServiceProvider {

        public function boot()
        {
            $this->package('my/package');
        }

        /**
         * Indicates if loading of the provider is deferred.
         *
         * @var bool
         */
        protected $defer = false;

        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {

        }

        /**
         * Get the services provided by the provider.
         *
         * @return array
         */
        public function provides()
        {
            return array();
        }

}

which is perfectly valid PHP code, and a valid Laravel 4 service provider class.

Template File Names

Being able to create templates within files is powerful, but we need to be able to generate file names too. Considering the following template directory structure:

/mytemplate
  | pagix.json
  | composer.json
  /src
   /#vendor|studly#
     /#package|studly#
       #package|studly#ServiceProvider.php
     /config
     /lang
     /migrations
     /views
  /tests
  /public

We can see the same techniques of placeholders and formatters being used here, with the difference that placeholders are surrounded by the # character in file names. Again, if we used my/project to create a new package using the above template, we could expect the following directory structure and files to be created (and of course, having the file contents updated accordingly):

/mytemplate
  | composer.json
  /src
   /My
     /Project
       ProjectServiceProvider.php
     /config
     /lang
     /migrations
     /views
  /tests
  /public

In the above example output, pagix.json file has been removed. This file would most likely be removed from all projects created with a template.

Interacting With the Tool

So how would a tool like this be used? Its usage would be familiar to anyone that has used composer. Users would start the command line utility, give the command to create a new project and give the template name and the target directory (the directory the package should be created in):

pagix make:package package/name your/project/location

The package/name would be the same package name, as it would be found on Packagist. Consistency. At this point, the tool would load the template's configuration, ask for any data required and then proceed to create the project at the specified location. Simplicity.

Conclusion

I look forward to receiving feedback on this idea. Specifically, would this be useful? Can anyone see possible pitfalls, problems, awesome ideas? Leave a comment below!