Logo
  • PHP
    • HipHop / HHVM
    • Modern PHP
    • PHPStorm
    • LAMP
    • Laravel
    • Composer
    • PDO
  • JavaScript
    • node.js
    • AngularJS
  • CSS
    • SASS
    • “CSS4” (CSS level 4)
  • HTML
  • Git
  • LAMP
  • Vagrant
  • UI / UX
  • Architecture of …
  • Off-Topic
With ♥ from Berlin
December 11, 2014
Chris
Local Development, mini, MVC, PHP
Comments Off on MINI2, an extremely simple barebone PHP application on top of Slim

MINI2, an extremely simple barebone PHP application on top of Slim

PreviousNext

For my daily work I often needed to setup super-simple PHP applications, just some more or less static pages plus some dynamic pages with simple database calls, one or two simple forms and maybe a little bit of AJAX. You know, the typical agency stuff. This usually led to the question: Use a real framework or just mash some .php files together ? The result was MINI, an extremely simple naked PHP application (or maybe even a framework), more on that in another article or directly on GitHub.

As MINI is really just very very basic I tried to upgrade this project a little bit by building the same naked application from scratch, this time on top of Slim, the popular micro framework. The result is MINI2, a super-simple script that might be a very simple, but very powerful base for smaller PHP applications. As the application’s core logic is now delivered by Slim, the script itself is extremely compact and comes with just 2 (!) php files plus some view templates and the casual .js and .css stuff.

 

The features of MINI2

  • built on top of Slim (you can easily update Slim without harming MINI2)
  • RESTful routes
  • extremely simple: the entire application is just 2 .php files (plus external dependencies plus view templates)
  • makes “beautiful” clean URLs (like example.com/car/show/17, not example.com/index.php?type=car&action=show&id=17)
  • uses Twig as template engine, others are possible (via Slim packages)
  • uses pure PDO instead of ORM (it’s easier to handle)
  • basic CRUD functions: create, read, update/edit and delete content
  • basic search
  • basic AJAX demo
  • (optional) shows emulated PDO SQL statement for easy debugging
  • (optional) compiles SCSS to CSS on the fly
  • (optional) minifies CSS on the fly
  • (optional) minifies JS on the fly
  • (optional) dev/test/production switch

 

The requirements of MINI2

  • PHP 5.3+
  • MySQL
  • mod_rewrite activated (when using Apache), document root routed to /public (tutorial below)

 

A simple screenshot

mini-screenshot

Installation

There’s a quick installation guideline on GitHub. If you are familiar with Vagrant then there’s also a one-click installation (yo, just a simple vagrant up command) that will create a fully configured Ubuntu 14.04 LTS with a completely setup MINI2 inside. Check the GitHub readme for more information.

The structure of MINI2

mini2-structure
Two folders, Mini and public. public holds the index.php that contains your application’s logic plus your JavaScript files, the scss (SASS) / CSS files and for sure the .htaccess that makes beautiful URLs. The SASS-to-CSS compiling is totally optional, you can turn it off by simple commenting out one line of code later.

The folder Mini contains – beside installation stuff – just the model/model.php that holds a set of data-manipulating methods (the MVC-model) and the folder view that holds a set of Twig files (which is just HTML with shortcodes for easily echoing out PHP variables), so it’s the MVC-view. Before you ask: There’s no folder controller as index.php works as the controller.

In the root folder there’s the composer.json that contains the to-be-loaded dependencies and a rule for autoloading our files. When fetching the dependencies while installing MINI2, Composer will load Slim (the router, more on that later), Twig (the template engine that renders the HTML and the variables from .twig files) and some other small tools and put them into the automatically created vendor folder, you know the process. If you have no idea what this means, then MINI2 is not for you, sorry.

The subfolder modules inside public/scss just contains a .scss with variables (like $font-color: #222222;) for easier SASS rendering, a common way to modularize your scss.

The folder _install in Mini holds 3 .sql statements with demo data for a working demo setup, the folder _vagrant contains a Vagrantfile and a bootstrap.sh to create a 100% automatically installing Ubuntu 14.04 LTS box with MINI2 running inside, more on that in the install tutorial on GitHub.

How MINI2 works

MINI2 works like most other frameworks and uses URLs like this: example.com/songs, example.com/songs/editsong/17, example.com/subpage etc. instead of ugly messy index.php?xxx=111&yyy=222 URIs. By default an installation of MINI2 needs a simple configuration of your Apache (or nginx or IIS) that routes the user directly to /public/index.php. This is easy to set up and clearly described in the install tutorial. Beside the aesthetical point this also prevents access to anything else then the /public folder, which makes your application much much more secure and also protects any potential .git files/folder, swap/noise files etc. from being curl’ed etc.

Let’s look into public/index.php, step by step:

<?php

/******************************* LOADING & INITIALIZING BASE APPLICATION ****************************************/

// Configuration for error reporting, useful to show every little problem during development
error_reporting(E_ALL);
ini_set("display_errors", 1);

// Load Composer's PSR-4 autoloader (necessary to load Slim, Mini etc.)
require '../vendor/autoload.php';

// Initialize Slim (the router/micro framework used)
$app = new \Slim\Slim();

// and define the engine used for the view @see http://twig.sensiolabs.org
$app->view = new \Slim\Views\Twig();
$app->view->setTemplatesDirectory("../Mini/view");

For development, the error reporting is set to maximum, then the Composer-autoloader is loaded, and Slim is initialized. As we use Twig as the template engine Twig is also initialized and the path to the view files is defined. By the way, I really like the way Slim handles this: $app->view. Beautiful!

 

/******************************************* THE CONFIGS *******************************************************/

// Configs for mode "development" (Slim's default), see the GitHub readme for details on setting the environment
$app->configureMode('development', function () use ($app) {

    // pre-application hook, performs stuff before real action happens @see http://docs.slimframework.com/#Hooks
    $app->hook('slim.before', function () use ($app) {

        // SASS-to-CSS compiler @see https://github.com/panique/php-sass
        SassCompiler::run("scss/", "css/");

        // CSS minifier @see https://github.com/matthiasmullie/minify
        $minifier = new MatthiasMullie\Minify\CSS('css/style.css');
        $minifier->minify('css/style.css');

        // JS minifier @see https://github.com/matthiasmullie/minify
        // DON'T overwrite your real .js files, always save into a different file
        //$minifier = new MatthiasMullie\Minify\JS('js/application.js');
        //$minifier->minify('js/application.minified.js');
    });

    // Set the configs for development environment
    $app->config(array(
        'debug' => true,
        'database' => array(
            'db_host' => 'localhost',
            'db_port' => '',
            'db_name' => 'mini',
            'db_user' => 'root',
            'db_pass' => 'your_password'
        )
    ));
});

Here we defined the configs for the development environment. To define for production you’d simply copy this block and fill the according credentials. More on that in the GitHub readme. Skip the $app->hook block for now and look at $app->config: This is self-explaining, right ? Okay, back to $app->hook: These are Slim’s hooks, blocks of code than are called at specific points in the application’s lifetime, in this case before the application is run. Here, in the default setup, these lines are just compiling our .scss files to .css and the style.css is minified, both via Composer-loaded libraries.

 

/******************************************** THE MODEL ********************************************************/

// Initialize the model, pass the database configs. $model can now perform all methods from Mini\model\model.php
$model = new \Mini\model\model($app->config('database'));

Just one line. To better understand this, have a look into Mini/model/model.php (shortened for better explanation):

<?php

namespace Mini\Model;

use PDO;

class Model
{
    /**
     * The database connection
     * @var PDO
     */
    private $db;

    /**
     * When creating the model, the configs for database connection creation are needed
     * @param $config
     */
    function __construct($config)
    {
        // PDO db connection statement preparation
        $dsn = 'mysql:host=' . $config['db_host'] . ';dbname='    . $config['db_name'] . ';port=' . $config['db_port'];

        // note the PDO::FETCH_OBJ, returning object ($result->id) instead of array ($result["id"])
        // @see http://php.net/manual/de/pdo.construct.php
        $options = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING);

        // create new PDO db connection
        $this->db = new PDO($dsn, $config['db_user'], $config['db_pass'], $options);
    }

    /**
     * Get all songs from database
     */
    public function getAllSongs()
    {
        $sql = "SELECT id, artist, track, link, year, country, genre FROM song";
        $query = $this->db->prepare($sql);
        $query->execute();
        return $query->fetchAll();
    }
}

This is just a simple class that expects an array with database configs when being constructed. When constructed, a database connection will be created and all methods – which are usually database calls and data-manipulating blocks – can be used. So, back to our index.php, let’s look again at that line:

 

/******************************************** THE MODEL ********************************************************/

// Initialize the model, pass the database configs. $model can now perform all methods from Mini\model\model.php
$model = new \Mini\model\model($app->config('database'));

So we create the Model object above and pass the configs to it. We can now perform actions on the $model, like $model->getAllSongs(); ! Totally simple.

 

/************************************ THE ROUTES / CONTROLLERS *************************************************/

// GET request on homepage, simply show the view template index.twig
$app->get('/', function () use ($app) {
    $app->render('index.twig');
});

// GET request on /subpage, simply show the view template subpage.twig
$app->get('/subpage', function () use ($app) {
    $app->render('subpage.twig');
});

This is where the real action starts: Here the routes are defined, some might also call them controllers. The logic behind is extremely simple, everything inside $app->get(‘/’ … will be called when a GET request is made on the project’s homepage, like example.com, everything inside $app->get(‘/’subpage … will be called when a GET request is made on example.com/subpage. Super-simple. Slim’s router can handle GET (browser’s default when simply “surfing” websites), POST (usually when submitting a form) and most other REST verbs.

The line $app->render(‘index.twig’); says what you expect: The file Mini/view/index.twig (which is just pure HTML in this case) is loaded, so in this case a simple static page is shown. See the Twig documentation for more information. You’ll  love Twig, as it’s indeed easier than pure PHP (!).

Now to some more complex routes:

// All requests on /songs and behind (/songs/search etc) are grouped here. Note that $model is passed (as some routes
// in /songs... use the model)
$app->group('/songs', function () use ($app, $model) {

    // GET request on /songs. Perform actions getAmountOfSongs() and getAllSongs() and pass the result to the view.
    // Note that $model is passed to the route via "use ($app, $model)". I've written it like that to prevent creating
    // the model / database connection in routes that does not need the model / db connection.
    $app->get('/', function () use ($app, $model) {

        $amount_of_songs = $model->getAmountOfSongs();
        $songs = $model->getAllSongs();

        $app->render('songs.twig', array(
            'amount_of_songs' => $amount_of_songs,
            'songs' => $songs
        ));
    });

    // POST request on /songs/addsong (after a form submission from /songs). Asks for POST data, performs
    // model-action and passes POST data to it. Redirects the user afterwards to /songs.
    $app->post('/addsong', function () use ($app, $model) {

        // in a real-world app it would be useful to validate the values (inside the model)
        $model->addSong(
            $_POST["artist"], $_POST["track"], $_POST["link"], $_POST["year"], $_POST["country"], $_POST["genre"]);
        $app->redirect('/songs');
    });

    // GET request on /songs/deletesong/:song_id, where :song_id is a mandatory song id.
    // Performs an action on the model and redirects the user to /songs.
    $app->get('/deletesong/:song_id', function ($song_id) use ($app, $model) {

        $model->deleteSong($song_id);
        $app->redirect('/songs');
    });

 

$app->group(‘/songs’ … “groups” everything that happens under example.com/songs, like example.com/songs itself, example.com/songs/editsong etc. Let’s look at $app->get(‘/’, … which defines what happens under example.com/songs(/). Here we show a twig file like before, but also pass some variables to the view: Mini/view/songs.twig will be shown, and the content of $amount_of_songs will be available inside that file via {{ amount_of_songs }} [that’s the syntax of Twig], like this (songs.twig):

<h2>We have {{ amount_of_songs }} songs</h2>

Okay, back to the index.php: The above code clearly shows where $amount_of_songs comes from: $amount_of_songs = $model->getAmountOfSongs(); ! As we have defined $model earlier we can use any method from that class and so get or manipulate data, like in this case simply fetching a number. Important: Note that as we use $model inside the $app->get block, the $model variable has to be passed inside, like shown in exactly that line and the $app->group line before: use ($app, $model .. defines which variable are known inside these methods. Without passing the $model we could not use $model inside.

Next block: $app->post( handles a POST request on example.com/songs/addsong. The method’s code is nearly self-explaining: We perform a method of $model and pass some variable from $_POST there. After that we route the user back to example.com/songs via $app->redirect(‘/songs’).

 

And basically: That’s it! Finally the index.php closes with

/******************************************* RUN THE APP *******************************************************/

$app->run();

to run the entire application for sure. Have a deeper look into all these files for a better understanding and some more examples, like the AJAX call or the search feature. Also, make sure you read into Slim’s excellent documention and the Twig docs.

 

Where to find MINI2 ?

On GitHub for sure, you might also bookmark the portal page php-mini.com and the Facebook page. I’m also trying to build a documentation on php-mini.com/documentation. There’s also the first version of MINI (1) on GitHub.

 

appapplicationbareboneframeworkminimini2nakedPHPskeleton
Share this

How to get a single table out of a massive MySQL .sql database backup file (mysql dump splitter)

Imagine the following situation: Somebody backs up an entire MySQL database – a very large one – with common tools.

How to hack time (KUNG FURY promo campaign)

:) Finally, KUNG FURY is out! No need for further words, unless you lived in a cave for the last

Experimenting with HHVM at Etsy (Link)

Extremely interesting blog post of Etsy on how they try out HHVM / HipHop: https://codeascraft.com/2015/04/06/experimenting-with-hhvm-at-etsy/

phpstorm 7.0 php

How to debug code on a remote server (or in vagrant box) with PHPStorm

Please also note: There are several methods to do remote debugging. This is the one that works without any browser

forbes 30 under 30

Need motivation ? Check out these 2 awesome “FORBES 30 under 30” lists (web, UI, games)

The FORBES magazine has just published the new “30 under 30” lists, and they are really really interesting! Lots of

bitdeli git github stats

Get visitor stats for your GitHub repo with BitDeli

GitHub is the definitive #1 “hoster” for git repositories, no question. And this highly sympathic company has made version control

gamescom 2014 trailers

GAMESCOM 2014: Awesome Next-Gen ingame graphics

Currently Germany’s biggest conference of the gaming industry is running, and everyday awesome stuff reaches the public. Excellent in-game sequences

O’Reilly’s Learning JavaScript Design Patterns by Addy Osmani for free

Addy Osmani has published his excellent book Learning JavaScript Design Patterns for free! You can read the entire book including

php

A super-simple introduction into PHP namespaces (7min video)

Once again, Jesse of JREAM totally nails it right on the head. A super-simple introduction into PHP namespaces. If you

php

Test out PHP 5.6alpha1 on Windows 7 / 8 with two clicks

The popular Apache-MySQLP-PHP stack EasyPHP has become very professional, maintained and especially modularized in the last 2 years, and when

1/4

Categories

Search

modern-php
Creator of Slim framework and “PHP – The right way” writes book: “Modern PHP”, available 2015
Creators of Laravel launch one-click-installations of Laravel (including nginx, PHP 5.5 etc.)
The New Era of JavaScript (28min conference talk, Jack Franklin, 2013)
Symfony devs: Creator of Symfony framework is hiring (Cologne, Germany)!
Joshua Davis – my hero of Flash – in two excellent interviews (audio, video)
october cms
[Link] How To Install October CMS on a VPS running Ubuntu 14.04
twig
A 6min video introduction into Twig, the PHP templating engine
phpstorm-github-code-color-syntax-theme
Get Github’s code colors in PHPStorm (2014 style)
laracon-2014-eu-amsterdam
Laracon 2013 – Jordi Boggiano: In Depth Composer (47min video)
What’s new in PHPStorm 9
java
Interesting: code of the same application in PHP, Python, Ruby, Closure, node.js, Java and Go
compress-png
Compress png, jpeg, gif and svg up to 90% with Compressor.io
organizing css
Jonathan Snook – CSS is a Mess – How to organize CSS in big projects (54min video talk)
hearthbleed-ssl-bug
The SSL Heartbleed bug explained in 30 seconds
hack-php
The first micro framework written in Hack is there: hack-mvc !

Tags

apache bash centos composer conference coupon CSS debian fonts framework git GitHub hack HHVM HipHop HTML HTML5 IDE JavaScript JS LAMP laravel linux mod_rewrite MVC MySQL Nginx optimization PHP PHP 5.5 PHP 5.6 phpmyadmin PHPStorm security server SSD Ubuntu UI UX vagrant video virtual machine voucher VPS wordpress
Side-Project: Wordle-Solver:
www.wordle-helper.info

Pages

  • Privacy Policy