Bacon is a clean, minimalistic and fast MVC framework. Our goal is to ease web development and provide a solid foundation for common use cases.


Head over here to dive into Bacon


Get your own copy

Contribute & Support

Find us on Github, get support and help us improve Bacon

Latest tag: GitHub version

Getting Started

This article gets you started on working with Bacon as quickly as possible and gives you an overview on how to handle common use cases.


The bare minimum to get started with Bacon is PHP (>= 7.0), composer and git. You can either install those from, and respectively, or via your distribution.
This tutorial will not go into details of how to do that.

Once you have PHP, composer and git set up, you can create a skeleton project with the following composer command:

% composer create-project brainsware/bacon-dist CatBlog

Note: brainsware/bacon-dist is used here as brainsware/bacon itself is only published as a library and would require you to set up a project on your own.

This will download all the necessary packages, and create all important directories and sample configuration files for your new cat blog.

You should see the following output:

Installing brainsware/bacon-dist (1.0)
  - Installing brainsware/bacon-dist (1.0)
    Loading from cache

Created project in CatBlog
Loading composer repositories with package information
Installing dependencies
  - Installing brainsware/php-markdown-extra-extended (dev-master 1.0)
    Cloning 1.0

  - Installing brainsware/sauce (1.0)
    Loading from cache

  - Installing minmb/phpmailer (dev-master df44323)
    Cloning df443234ad0ca10cbf91a0c0a728b256afcab1d1

  - Installing twig/twig (dev-master ba67e2c)
    Cloning ba67e2cf8e2ca6cada1de5a316a724df648c52ac

  - Installing brainsware/bacon (1.0)
    Loading from cache

Writing lock file
Generating autoload files

We will describe each of these pieces of software and how they fit into the overall architecture of Bacon later on. For now let's consider them as opaque building blocks.


Bacon uses PHP files for storing all of its configurations.

The skeleton project comes with an Intro controller, which is set as the default fallback controller in Config/Base.php

The second config file you will want to look at is Config/Database.php
Here are the basic options you will want to set for your database:

'server'   => 'db.dbznet',  # Enter your server host here
'name'     => 'blogDB',     # The name of your database
'type'     => 'mysql',      # Anything your PDO Installation supports. (
'username' => 'blogDBuser', # The username you want to connect to your database with
'password' => 'VryScrPswd', # The password.

Bacon does not provide default values for these options. If your application needs a database, you will have to create it and connect Bacon to it via Config/Database.php.

How to create a Blog

The classic project to demonstrate working with a web framework is a blog. We'll stick with our CatBlog example from above.


Before anything else, we need a means of retrieving data from the database. In Bacon this is done with models.

The simplest form of model is a class inheriting from \Bacon\ORM\Model in the namespace \Models holding a static variable $table_name with the table name:

# Models/Post.php:

namespace Model;

class Post extends \Bacon\ORM\Model
    public static $table_name = 'post';

This model will provide you with basic functionality for adding, editing, deleting and retrieving entries from the table "post". We'll get back to more indepth discussion of the ORM in its own chapter.


An Application controller is already present in the skeleton project. It is supposed to hold any global methods that are needed in all controllers, e.g. authentication code or template filter methods. All controllers must derive from that global Application controller.

# Controllers/Application.php:

namespace Controllers;

class Application extends \Bacon\Controller
    public function init ()
        # This method gets called before any other.
        # Useful for initiating things like authentication, session checks,
        # adding hooks to Twig, etc.
        # For now we'll leave it empty.

Now let's create a basic controller that shows us a list of all entries.

# Controllers/Blag.php:

namespace Controllers;

class Blag extends Application
    // Blag#index is called when /blag (GET) is requested.
    public function index ()
        # ::all() retrieves a collection of all entries in the post table
        $this->posts = \Models\Post::all();


Bacon uses Twig as its templating engine.

Views follow the same structure as controllers do; for each controller there is a folder with the same name. Additionally, a default layout in the Views/ directory is mandatory. The names of the templates are the same as the controller actions



URLs map to controllers and their methods in a very specific way. There is no configuration for routing. We prefer the principle of convention over configuration. The base of this convention is the REST principle. A resource maps to a controller and its actions with the HTTP vocabulary. The only thing needed for introducing a new URL is dropping in a new controller with the same name and implement its actions.

The callable controller actions are:

Action URL HTTP Method
#index /resource GET
#new /resource/new GET
#show /resource/:id GET
#create /resource/ POST
#edit /resource/:id/edit GET
#update /resource/:id PUT 1
#destroy /resource/:id DELETE 1

:id is an arbitrary identifier for a specific resource you wish to access. In our example this could be the cat's name: By calling /catcontent/new we can create a new cat profile for a cat named PuffyPaws and #show that profile with /catcontent/PuffyPaws

Pretty URLs

Bacon relies on the Front Controller Pattern and as such all requests should be handled by Bacon's boot.php included in htdocs/index.php of your skeleton project. Many modern Web Application Servers like Nginx and Apache HTTPD have a very simple way of implementing this.

Supposing you use Apache, add this to your virtual host definition:

# httpd.conf, in the VirtualHost:
FallbackResource /index.php

This means: send all requests that do not point to a specific file to index.php.

  1. Since browsers only allow GET and POST requests, PUT and DELETE are distinguished from a normal POST request by a parameter called _method. It may be embedded in a hidden form field or in the URL as GET parameter. 

Found a typo or want to help extend the documentation? Fork us on Github!


Bacon development version

Most work on Bacon happens when we actually use it in our projects. To do this, we now have a "development" version of bacon-dist available in the repository''s master branch. This in turn requires the master of Bacon and Sauce. The tags are considered stable and each include the latest stable version of their dependencies.

Creating a new project using the development version works like this:

% composer create-project brainsware/bacon-dist ProjectName dev-master

Composer will also ask you whether you want to keep the version control information. To keep it without asking, use the --keep-vcs flag.

Bacon releases 0.1.1 - 0.1.5

A couple of weeks have passed since the first release of Bacon, but we did not stop working on it and have released the tags 0.1.1 to 0.1.5 for Bacon and the tag 0.1.1 for Sauce.

The full changelog can be found here.

A few of the changes are worth noting:

bacon-dist package changed

The bacon-dist composer package now requires the latest 0.1.* version so you get updates as soon as they''re released. To update your dependencies run composer update.

Redirects in a Controller''s init() method

In some cases one needs a way to escape a controller very early, e.g. if authentication requirements are not met. The init() method now sports this via redirects.

class Backend extends Application
    protected function init()
        // $this->logged in might be defined in Application
        if (!$this->logged_in()) {
            return $this->redirect([ ''backend/login'' ]);


Most of the changes in \\Bacon\\ORM\\Model and \\Bacon\\ORM\\Collection are refactorings in terms of quality and clean code. All methods querying the database now use prepared statements and a few internal properties now use Sauce Object and Vector instead of builtin arrays.

Two changes however might affect the users of the ORM: A class \\Bacon\\Exceptions\\ValidationError has been added and the static::$timestamps property is now by default true (explicitely set so in \\Bacon\\ORM\\Model).

When calling $model_instance->error(''column'', ''message''); a new ValidationError object is created and pushed, but not thrown.

The case insensitive Router

After moving Bacon to use Composer and its PSR-0 autoloader, controller and view directories had to always start with a capital letter. The router did not care much about the case of the directories and files it searched for, so it depended on the underlying OS or file system whether it was case sensitive or not. On Windows the change to the PSR-0 autoloader did not break anything. On Linux however one had to provide uppercase resource names in the URI, which looks odd. We also did not like the possibility of introducing bugs (okay, we did actually have that bug in our applications) when working on different platforms.

So the router is now case insensitive.

Misc changes

  • The documentation now resides in the Bacon repository instead of''s. That way it comes with your local checkout/download of bacon and can be found in vendor/brainsware/bacon/docs. It is written in Github flavoured markdown.
  • \\Bacon\\Log now outputs timestamps formatted according to ISO 8061.
  • bin/server has been changed to run on port 8080 instead of 80 by default no longer requiring sudo.
  • \\Sauce\\CliColors has been added.

First public Bacon release!

We, Brainsware, have developed Bacon over the last years to cover all our clients' common use cases and thus have created a base for fast and robust web development using PHP. Since we do not want to keep that to ourselves, Bacon is now released to the wild under the Apache-2.0 license.

What makes Bacon special?

PHP and its surrounding development environment, as well as web development practices in general, have evolved quite a bit in the past years and we tried to keep in touch with that. Thus Bacon strives to integrate in all the new and shiny infrastructure available for PHP developers.

  • A very permissive license (Apache-2.0)
  • Full usage of PHP 5.4 features, especially in the underlying general purpose library Sauce
  • PSR-0 and mostly PSR-1 compatible (we prefer #under_score method names instead of #camelCase)
  • Available as Composer packages for ease of installation and dependency management
  • Library, website and skeleton project fully available for you to fork on Github

What does Bacon provide?

Bacon is still quite small and minimalistic, it does however implement a complete MVC structure. With this structure and some conventions Bacon makes it very easy to cover a wide variety of use cases of modern web development.

  • A simple ORM
  • RESTful routing: a simple, standardized way of mapping URIs to controllers also following our principle of convention over configuration
  • Robust controller infrastructure including the standard template engine Twig
  • Standardized upload handling for asynchronous XHR as well as classic HTML uploads
  • Simple ways of turning your controllers into web services or AJAX API endpoints
  • Support for CoffeeScript

Where will Bacon go?

As good as we think Bacon is already, we still have a lot of features lined up in our queue:

  • Migrations, validations and associations for the ORM
  • Standardized error and error message handling in the ORM and controllers
  • Internationalization and localization
  • Proper, automatable unit and regression testing suite with a simple DSL for Bacon, Sauce and the applications built with it
  • API documentation generation that integrates neatly with the rest of documentation
  • Keep up-to-date with new features in PHP

We will try to keep and improve the usability of Bacon as a whole, to further ease web development.

If you have any questions, feature request or just want to get in touch don''t hesitate to contact us on Github. We also encourage you to fiddle around with Bacon and its environment yourself, if you feel like something is missing, you found a typo or just want to experiment. So fork us and send us pull requests!