laravel-shift / blueprint

An expressive, human readable code generation tool.

Stars
783

Blueprint

Blueprint is an open-source tool for rapidly generating multiple Laravel components from a single, human readable definition.

Watch a quick demo of Blueprint in action and continue reading this document to get started.

Installation

You can install Blueprint via composer using the following command:

composer require --dev laravel-shift/blueprint

Blueprint will automatically register itself using package discovery.

Requirements

Blueprint requires a Laravel application running version 6.0 or higher.

While Blueprint may be more flexible in a future version, it currently assumes a standard project structure using the default App namespace.

Basic Usage

Blueprint adds multiple artisan commands. The most commonly used command is the blueprint:build command to generate the Laravel components:

php artisan blueprint:build [draft]

The draft file contains a definition of the components to generate. By default, the blueprint:build command attempts to load a draft.yaml file from the project root folder.

Defining Components

Use Blueprint's artisan commands you may generate multiple Laravel components from a single definition called a draft file.

Within this draft file you define models and controllers using an expressive, human-readable YAML syntax.

Let's review the following draft file:

models:
  Post:
    title: string:400
    content: longtext
    published_at: nullable timestamp

controllers:
  Post:
    index:
      query: all
      render: post.index with:posts

    store:
      validate: title, content
      save: post
      send: ReviewNotification to:post.author with:post
      dispatch: SyncMedia with:post
      fire: NewPost with:post
      flash: post.title
      redirect: post.index

From these simple 20 lines of YAML, Blueprint will generate all of the following Laravel components:

  • A model class for Post complete with fillable, casts, and dates properties, as well as relationships methods.
  • A migration to create the posts table.
  • A factory intelligently setting columns with fake data.
  • A controller class for PostController with index and store actions complete with code generated for each statement.
  • Routes for the PostController actions.
  • A form request of StorePostRequest validating title and content based on the Post model definition.
  • A mailable class for ReviewNotification complete with a post property set through the constructor.
  • A job class for SyncMedia complete with a post property set through the constructor.
  • An event class for NewPost complete with a post property set through the constructor.
  • A Blade template of post/index.blade.php rendered by [email protected].

While this draft file only defines a single model and controller, you may define multiple models and controllers.

Models

Within the models section of a draft file you may define multiple models. Each model begins with a name followed by a list of columns. Columns are key: value pairs where key is the column name and value defines its attributes.

Expanding on the example above, this draft file defines multiple models:

models:
  Post:
    title: string:400
    content: longtext
    published_at: nullable timestamp

  Comment:
    content: longtext
    published_at: nullable timestamp

  # additional models...

From this definition, Blueprint creates two models: Post and Comment, respectively. You may continue to define additional models.

Blueprint recommends defining the model name in its StudlyCase, singular form to follow Laravel naming conventions. For example, Post instead of post or posts.

Similarly, column names will be used as-is. The attributes of these columns may be any of the column types and column modifiers available in Laravel. You may define these as-is or using lowercase.

For complex attributes, you may use a key:value pair. From these example above, string:400 defines a string column type with a maximum length of 400 characters. Other examples include enum:'foo','bar','baz' or decimal:10,2.

By default, each model will automatically be defined with an id and timestamps columns. To disable these columns you may define them with a false value. For example, timestamps: false.

Blueprint also offers additional shorthands which will be expanded into valid YAML. Shorthands include an id data type, as well as defining soft deleting models.

For example:

models:
  Comment:
    user_id: id
    softDeletes
    # ...

Using these shorthands, Blueprint will generate a Comment class using the SoftDeletes trait. It will also create a user_id column with the appropriate data type for an integer foreign key.

Blueprint also inspects columns and assigns them to fillable, casts, and dates properties, as well as generate relationships methods.

By default, all columns except for id and timestamps will be added to the fillable property.

Where appropriate, Blueprint will cast columns to integer, boolean, and decimal types. Any date columns will be added to the dates properties.

Columns which use an id data type or end with _id will be used to generate belongsTo relationships. By default, Blueprint uses the column name prefix for the related model. If you define a relationship for a different model, you may use a id:model syntax.

For example:

models:
  Post:
    author_id: id:user
    # ...

Controllers

Similar to models, you may also define multiple controllers. Within the controllers section you define a controller by name. Each controller may define multiple actions which contain a list of statements.

Expanding on the example above, this draft file defines multiple controllers:

controllers:
  Post:
    index:
      query: all
      render: post.index with:posts
    create:
      render: post.create
    store:
      validate: title, content
      save: post
      redirect: post.index

  Comment:
    show:
      render: comment.show with:show

  # additional controller...

From this definition, Blueprint will generate two controllers. A PostController with index, create, and store actions. And a CommentController with a show action.

While you may specify the full name of a controller, Blueprint will automatically suffix names with Controller.

Blueprint encourages you to define resource controllers. Doing so allows Blueprint to infer details and generate even more code automatically.

Statements

Blueprint comes with an expressive set of statements which implicitly define additional components to generate. Each statement is a key: value pair.

The key defines the type of statement to generate. Currently, Blueprint supports the following types of statements:

validate

Generates a form request with rules based on the referenced model definition. Blueprint accepts a value containing a comma separated list of column names.

For example:

validate: title, content, author_id

Blueprint also updates the type-hint of the injected request object.

find

Generates an Eloquent find statement. If the value provided is a qualified reference, Blueprint will expand the reference to determine the model. Otherwise, Blueprint will attempt to use the controller to determine the related model.

query

Generates an Eloquent query statement using key:value pairs provided in value. Keys may be any of the basic query builder methods for where clauses and ordering.

For example:

query: where:title where:content order:published_at limit:5

Currently, Blueprint supports generating query statements for all, get, pluck, and count.

save/delete

Generates an Eloquent statement for saving a model. Blueprint uses the controller action to infer which statement to generate.

For example, for a store controller action, Blueprint will generate a Model::create() statement. Otherwise, a $model->save() statement will be generated.

Similarly, within a destroy controller action, Blueprint will generate a $model->delete() statement. Otherwise, a Model::destroy() statement will be generated.

flash

Generates a statement to flash data to the session. Blueprint will use the value as the session key and expands the reference as the session value.

For example:

flash: post.title
render
Generates a `return view();` statement complete with a template reference and data.

For example:

view: post.show with:post

When the template does not exist, Blueprint will generate the Blade template for the view.

redirect
Generates a `return redirect()` statement using the `value` as a reference to a named route passing any data as parameters.

For example:

redirect: post.show with:post
dispatch

Generates a statement to dispatch a Job using the value to instantiate an object and pass any data.

For example:

dispatch: SyncMedia with:post

If the referenced job class does not exist, Blueprint will create one using any data to define properties and a __construct method which assigns them.

fire

Generates a statement to dispatch a Event using the value to instantiate the object and pass any data.

For example:

fire: NewPost with:post

If the referenced event class does not exist, Blueprint will create one using any data to define properties and a __construct method which assigns them.

send

Generates a statement to send a Mailable using the value to instantiate the object, specify the recipient, and pass any data.

For example:

send: ReviewNotification to:post.author with:post

If the referenced mailable class does not exist, Blueprint will create one using any data to define properties and a __construct method which assigns them.

References

For convenience, Blueprint will use the name of a controller to infer the related model. For example, Blueprint will assume a PostController relates to a Post model.

Blueprint also supports a dot (.) syntax for more complex references. This allows you to define values which reference columns on other models.

For example, to find a User model within the PostController you may use:

controllers:
  Post:
    show:
      find: user.id
      # ...

While these references will often be used within Eloquent and query statements, they may be used in other statements as well. When necessary, Blueprint will convert these into variable references using an arrow (->) syntax.

Additional Console Commands

Beyond the blueprint:build command, Blueprint provides additional commands:

blueprint:erase

Erases the components created by the last build and warns about any updated components.

While this command is helpful, it's better to run the blueprint:build command from a clean working state and use Git commands like reset and clean to undo the last build.

blueprint:trace

Loads definitions for existing models into the Blueprint cache file (.blueprint) so you may reference them in your draft file.

Contributing

Contributions may be made by submitting a Pull Request against the master branch. Any submissions should be complete with tests and adhere to the PSR-2 code style.

You may also contribute by opening an issue to report a bug or suggest a new feature.