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
4

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.

 

This article was written quite a while ago (8 years), please keep this in mind when using the information written here. Links, code and commands might be outdated or broken.

Random articles

  • MINI, an extremely simple barebone PHP applicationMINI, an extremely simple barebone PHP application
  • New project: Building a naked PHP skeleton / boilerplate application from scratchNew project: Building a naked PHP skeleton / boilerplate application from scratch
  • Install MINI in 30 seconds inside Ubuntu 14.04 LTSInstall MINI in 30 seconds inside Ubuntu 14.04 LTS
  • SensioLabs, creator of Symfony and Silex PHP frameworks, gets $7 million capitalSensioLabs, creator of Symfony and Silex PHP frameworks, gets $7 million capital
  • PHPStorm: 42 Tips and Tricks (47min video talk by Mikhail Vink at Dutch PHP Conference 2015)PHPStorm: 42 Tips and Tricks (47min video talk by Mikhail Vink at Dutch PHP Conference 2015)
  • What’s new in PHPStorm 9What’s new in PHPStorm 9
  • Experimenting with HHVM at Etsy (Link)Experimenting with HHVM at Etsy (Link)
  • Dangerous Performance Myths in the Web (video talk by Thomas Lohner, PHPUG Latvia)Dangerous Performance Myths in the Web (video talk by Thomas Lohner, PHPUG Latvia)
  • How to setup / install PHP 5.6 on Ubuntu 14.04 LTSHow to setup / install PHP 5.6 on Ubuntu 14.04 LTS
appapplicationbareboneframeworkminimini2nakedPHPskeleton
Share this

4 Comments

  • Andrew Gordon
    December 26, 2014 11:33 pm

    Coming from a .NET C#/Java/C/C++ Server/Embedded development background, I was looking for a PHP framework to quickly build some web applications. Tried all the usual suspects and came across Mini2 and it was definitely the quickest to get up and running. I’ve seen your comments on GitHub around cleaning up the design, and yes you could make it more elegant and ‘purest’ MVC, but there’s something to be said for a lightweight framework that focuses on the least code possible. I’ve developed a number of applications using the MVVM pattern, including .NET C#/XAML and Java ZK, and although architecturally they were as loosely coupled and had the maximum of separation of concerns as you can get, I did feel that the resulting SLOCS were just too high.

    Reply
  • Piotr
    December 11, 2014 11:43 am

    Good job man.
    Btw. does it mean you will focus now on mini2? It would be nice to give some pros and cons mini vs mini2.

    cheers

    Reply
    • Chris
      December 16, 2014 7:18 pm

      Thanks! :) Yes, MINI2 is more in focus, simply as it’s more modern, more modular and offers so much more possibilities with Slim. The main pro for MINI2 is for sure the simpler architecture, the usage of Slim and the easy integration of Middleware, external libraries etc. Cons are that MINI2 / Slim is so simple that it’s mainly just 1-2 files, so it might get messy if you’re not rebuilding some things (configs, routes, etc.).

      However, if you are familiar with Composer, RESTful routes and think Slim is a nice tool, then MINI2 is the choice.

      Reply
      • Philip
        June 30, 2015 6:23 pm

        Please how can i use MINi1 to upload images, its really giving me headache

        Reply

Leave A Comment Cancel reply

Frontend Ops Conf 2014 – Paul Irish: Delivering The Goods In Under 1000ms (40min video)

This article was written quite a while ago (8 years), please keep this in mind when using the information written

node.js

PayPal drops Java, goes node.js / JavaScript

First: this is not a Java-vs.-AnyOtherLanguage diss, just an article about a very interesting development: Using “frontend-languages” for serious server-side

mod-rewrite-ubuntu-14-04-lts

Which server OS version to choose ? Some EOL lists of Debian, Ubuntu and CentOS

Moving running projects (especially smaller ones that you’ve made for clients years ago) from an outdated and not-supported linux version

Hacked french TV channel exposed passwords in TV interview (video, screenshots, links)

This week a major french TV networks was hacked (Article on CNN #1, #2), resulting in 11 channels being completely

atomic-design

An introduction into Atomic Design, a super-clean way to style web applications

A super-interesting talk of Brad Frost at beyond tellerrand 2013, explaining the basics of Atomic Design: What is Atomic Design

vagrant

A preinstalled Vagrant box with PHP HipHop / HHVM and Ubuntu 13.10 (Saucy Salamander)

Here’s an excellent downloadable Vagrant box that’s brings you a preinstalled HHVM / HipHop for PHP within a Ubuntu 13.10

New project: Building a naked PHP skeleton / boilerplate application from scratch

[This post is from November 2013. In the meantime (I’m writing this in November 2014) the project has changed its

goodbye-lamp-going-hhvm-nosql-nginx-php

[RePost] Goodbye LAMP: Going Nginx, NoSQL, HHVM (41min conference talk with Arne Blankerts)

Another excellent find by Germany’s PHP Magazin in the article “Nginx, NoSQL, HHVM: Goodbye LAMP Stack?“: 41 minutes super-interesting (english)

phpstorm-github-code-color-syntax-theme

Get Github’s code colors in PHPStorm (2014 style)

I really love the colors on GitHub’s code previews but couldn’t find any themes that copy that in a beautiful

windows-xp-eol

Windows XP is officially dead from today. Do you know people still using it ? Punch them.

From today, April 8th 2014, Windows XP is officially dead. Basically XP was already dead in 2009 when – after

1/4

Categories

Search

js javascript
JavaScript Testing Tactics (21min video by Justin Searls)
New project: Building a naked PHP skeleton / boilerplate application from scratch
php
A super-simple introduction into PHP namespaces (7min video)
php
Awesome list of Design Patterns with PHP code examples
How to show memory usage (Ubuntu)
Install MINI in 30 seconds inside Ubuntu 14.04 LTS
PHPMyAdmin not found after installation ? Here’s a fix (Ubuntu 12.04) !
php
PHP.net hacked, but most things are fine again
php
Why Modern PHP is Awesome And How You Can Use It Today (Slides by Matt Stauffer)
A collection of beautiful ajax loaders / spinners in pure .svg / CSS
windows-xp-eol
Windows XP is officially dead from today. Do you know people still using it ? Punch them.
set up a local virtual machine for development with vagrant and puphpet / puppet (and ubuntu, linux, php, apache, mysql)
A super-simple pre-configured Vagrant box with HipHop, Hack and Hack code examples
php-legacy-code
Interesting talk on modernizing a legacy PHP codebase
Microsoft announces “holographic” 3D interfaces (promo video)
phpstorm 7.0 php
How to install GitHub’s, NetBeans’s and Sublime2’s syntax highlighting code colours theme in PHPStorm 6/7

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
 
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept”, you consent to the use of ALL the cookies.
Do not sell my personal information.
Cookie SettingsAccept
Manage consent

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
CookieDurationDescription
cookielawinfo-checkbox-analytics11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional11 monthsThe cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance11 monthsThis cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy11 monthsThe cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytics
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Advertisement
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.
Others
Other uncategorized cookies are those that are being analyzed and have not been classified into a category as yet.
SAVE & ACCEPT