What is Slim Framework?
Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and Restful APIs.
- Inspired by Sinatra
- Favors cleanliness over terseness
- Favors common cases over edge cases
Webpage http://www.slimframework.com/
Installation
There are two ways:
- Manual Installation
- Using Composer (Later will be explained)
Hello World
1. Manual installation
index.php
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
Hello World
2. Composer installation
index.php
require 'vendor/autoload.php';
$app = new \Slim\Slim();
$app->get('/hello/:name', function ($name) {
echo "Hello, $name";
});
$app->run();
...That's it!
Hello World
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
Don’t forget!
Routing
GET
$app->get('/books/:id', function ($id) {
//Show book identified by $id
});
POST
$app->post('/books', function () {
//Create book
});
PUT
$app->put('/books/:id', function ($id) {
//Update book identified by $id
});
DELETE
$app->get('/books/:id', function ($id) {
//Show book identified by $id
});
Routing
Method Override
Unfortunately, modern browsers do not provide native support for HTTP PUT and DELETE requests. To work around this limitation, ensure your HTML form’s method attribute is "post", then add a method override parameter to your HTML form like this:
<form action="/books/1" method="post">
... other form fields here...
<input type="hidden" name="_METHOD" value="PUT"/>
<input type="submit" value="Update Book"/>
</form>
Route Parameters
$app->get('/books/:one/:two', function ($one, $two) {
echo "The first paramter is " . $one;
echo "The second parameter is " . $two;
});
Optional Route Parameters
$app->get('/archive(/:year(/:month(/:day)))', function ($year = 2010, $month = 12, $day = 05) {
echo sprintf('%s-%s-%s', $year, $month, $day);
});
- /archive
- /archive/2010
- /archive/2010/12
- /archive/2010/12/05
Features
That was the routing but Slim has much more...
- Template rendering
- Flash messages
- Secure cookies with AES-256 encryption
- HTTP caching (ETag)
- Loggin with custom log writers
- Error handling and debugging
- Middleware and hook architecture
- Simple configuration
Slim Framework
Composer
Eloquent
Twig
What is Composer?
Composer is a Dependency Manager for PHP
Installation
Composer is very easy to install:
Go to http://getcomposer.org and download the installer
Or
Run this in your terminal
curl -s https://getcomposer.org/installer | php
Using Composer
Into the Root of your project create the file:
composer.json
{
"require": {
"slim/slim": "2.*"
}
}
Using composer
To get the dependencies
run in the terminal
composer install
Using composer
To Update the dependencies
run in the terminal
composer update
Packagist
It is the main Composer repository
There you can browse and search for packages.
Autoload
Composer generates a vendor/autoload.php file
You can simply include this file and you will get autoloading
require 'vendor/autoload.php';
Autoload
You can even add your own code to the autoloader by adding an autoload field to composer.json.
{
"autoload": {
}
}
There are two ways to autoload your classes:
- PSR-0
- Classmap
PSR-0
Here you define a mapping from namespaces to paths, relative to the package root
{
"autoload": {
"psr-0": {
"Monolog": "src/",
"Vendor\\Namespace\\": "src/",
"Vendor_Namespace_": "src/"
}
}
}
This is the recommended way though since it offers greater flexibility
After adding the autoload field, you have to re-run:
composer install
Classmap
You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0
{
"autoload": {
"classmap": ["src/", "lib/", "Something.php"]
}
}
After adding a new class or file, you have to run:
composer update
create-project
You can use Composer to create new projects from an existing package.
This is the equivalent of doing a git clone/svn checkout followed by a composer install of the vendors.
composer create-project slim/slim-skeleton [my-app-name]
Example
Installing Slim with Composer in Fortrabbit Server
Slim Framework
Composer
Eloquent
Twig
Laravel Framework ORM
Laravel comes with several tools to use with databases:
- Schema Builder
- Fluent Query Builder
- Eloquent ORM
Schema Builder
Provides methods for creating and modifying your database tables.
Schema Builder
Create tables
Schema::table('users', function($table)
{
$table->create();
$table->increments('id');
$table->string('username');
$table->string('email');
$table->string('phone')->nullable();
$table->text('about');
$table->timestamps();
});
Schema Builder
Methods allow you to add columns
$table->increments('id'); //Incrementing ID to the table
$table->string('email'); //VARCHAR equivalent column
$table->string('name', 100); //VARCHAR equivalent with a length
$table->integer('votes'); //INTEGER equivalent to the table
$table->float('amount'); //FLOAT equivalent to the table
$table->decimal('amount', 5, 2); //DECIMAL with a precision and scale
$table->boolean('confirmed'); //BOOLEAN equivalent to the table
$table->date('created_at'); //DATE equivalent to the table
$table->timestamp('added_on'); //TIMESTAMP equivalent to the table
$table->timestamps(); //Adds created_at and updated_at columns
$table->text('description'); //TEXT equivalent to the table
$table->blob('data'); //BLOB equivalent to the table
->nullable() //Designate that the column allows NULL values
->default($value) //Declare a default value for a column
->unsigned() //Set INTEGER to UNSIGNED
Schema Builder
Defining indexes
$table->primary('id'); //Adding a primary key
$table->primary(array('fname', 'lname')); //Adding composite keys
$table->unique('email'); //Adding a unique index
$table->fulltext('description'); //Adding a full-text index
$table->index('state'); //Adding a basic index
Fluent Query Builder
The Fluent Query Builder is Laravel's powerful fluent interface for building SQL queries and working with your database.
All queries use prepared statements and are protected against SQL injection.
You can begin a fluent query using the table method on the DB class. Just mention the table you wish to query
$query = DB::table('users');
Fluent Query Builder
Retrieving records
$users = DB::table('users')->get();
$user = DB::table('users')->first();
$user = DB::table('users')->find($id);
$email = DB::table('users')->where('id', '=', 1)->only('email');
$user = DB::table('users')->get(array('id', 'email as user_email'));
$user = DB::table('users')->distinct()->get();
Fluent Query Builder
Building Where Clauses
return DB::table('users')
->where('id', '=', 1)
->or_where('email', '=', 'example@gmail.com')
->first();
DB::table('users')->where_in('id', array(1, 2, 3))->get();
DB::table('users')->where_not_in('id', array(1, 2, 3))->get();
$users = DB::table('users')
->where('id', '=', 1)
->or_where(function($query)
{
$query->where('age', '>', 25);
$query->where('votes', '>', 100);
})
->get();
Fluent Query Builder
Table Joins
DB::table('users')
->join('phone', 'users.id', '=', 'phone.user_id')
->get(array('users.email', 'phone.number'));
DB::table('users')
->left_join('phone', 'users.id', '=', 'phone.user_id')
->get(array('users.email', 'phone.number'));
Fluent Query Builder
Ordering results
return DB::table('users')->order_by('email', 'desc')->get();
return DB::table('users')
->order_by('email', 'desc')
->order_by('name', 'asc')
->get();
Limit and Offset
return DB::table('users')->take(10)->get();
return DB::table('users')->skip(10)->get();
Fluent Query Builder
Aggregates
$min = DB::table('users')->min('age');
$max = DB::table('users')->max('weight');
$avg = DB::table('users')->avg('salary');
$sum = DB::table('users')->sum('votes');
$count = DB::table('users')->count();
$count = DB::table('users')->where('id', '>', 10)->count();
Fluent Query Builder
Insert - Update - Delete
DB::table('users')->insert(array('email' => 'example@gmail.com'));
$affected = DB::table('users')->update(array('email' => 'new_email@gmail.com'));
$affected = DB::table('users')->where('id', '=', 1)->delete();
Eloquent ORM
Eloquent is an ORM (Object-relational mapper) very easy to use
Define a simple model
class User extends Eloquent {}
Eloquent ORM
Conventions
- Each table should have a primary key named id
- Each table name should be the plural of its corresponding model name
But you can change it...
class User extends Eloquent {
protected $table = 'my_users';
protected $key = 'id_user';
}
Eloquent ORM
Retrieving Models
Of course every method that is available through the Fluent Query Builder is available in Eloquent
$user = User::where('email', '=', $email)->first();
$user = User::where_email($email)->first();
$users = User::where_in('id', array(1, 2, 3))->or_where('email', '=', $email)->get();
$users = User::order_by('votes', 'desc')->take(10)->get();
Eloquent ORM
Aggregates
Of course every method that is available through the Fluent Query Builder is available in Eloquent
$min = User::min('id');
$max = User::max('id');
$avg = User::avg('id');
$sum = User::sum('id');
$count = User::count();
$count = User::where('id', '>', 10)->count();
Eloquent ORM
Inserting and Updating Models
Of course every method that is available through the Fluent Query Builder is available in Eloquent
$user = new User; //Insert
$user = User::find(1); // Or getting first for Update
$user->email = 'example@gmail.com';
$user->password = 'secret';
$user->save();
Another way to insert a new record
$user = User::create(array('email' => 'example@gmail.com'));
Eloquent ORM
created_at and updated_at
Whenver you save the model, the creation an update timestamps will be set automatically
class User extends Eloquent {
public $timestamps = true;
}
You can update the update_at without saving the model
$comment = Comment::find(1);
$comment->touch();
Or
$comment = Comment::find(1);
$comment->timestamp();
//do something else here, but not modifying the $comment model data
$comment->save();
Eloquent ORM
Relationships
- One-to-One
- One-To-Many
- Many-To-Many
Eloquent ORM
Relation One-To-One
class User extends Eloquent {
public function phone()
{
return $this->has_one('Phone');
}
}
Now execute
$phone = User::find(1)->phone()->first();
Two queries will be performed
SELECT * FROM "users" WHERE "id" = 1
SELECT * FROM "phones" WHERE "user_id" = 1
Eloquent ORM
Relation One-To-Many
class Post extends Eloquent {
public function comments()
{
return $this->has_many('Comment');
}
}
Now execute
$comments = Post::find(1)->comments()->get();
$comments = Post::find(1)->comments;
Two queries will be performed
SELECT * FROM "posts" WHERE "id" = 1
SELECT * FROM "comments" WHERE "post_id" = 1
Eloquent ORM
Relation Many-To-Many
This is the most complicated, for the example create 3 tables
usersid - INTEGER
email - VARCHAR
roles
id - INTEGER
name - VARCHAR
role_user
id - INTEGER
user_id - INTEGER
role_id - INTEGER
Eloquent ORM
Relation Many-To-Many
class User extends Eloquent {
public function roles()
{
return $this->has_many_and_belongs_to('Role');
}
}
Now execute
$roles = User::find(1)->roles()->get();
Or
$roles = User::find(1)->roles;
Slim Framework
Composer
Eloquent
Twig
Twig
Twig is the flexible, fast and secure template language for PHP
Created by Fabien Potencier (Symfony)
Twig
Example .html using Twig
<!DOCTYPE html>
<html>
<head>
<title>My Webpage</title>
</head>
<body>
<ul id="navigation">
{% for item in navigation %}
<li><a href="{{ item.href }}">{{ item.caption }}</a></li>
{% endfor %}
</ul>
<h1>My Webpage</h1>
{{ a_variable }}
</body>
</html>
Twig
Variables
{{ foo.bar }}
{{ foo['bar'] }}
setting variables
{% set foo = 'foo' %}
{% set foo = [1, 2] %}
{% set foo = {'foo': 'bar'} %}
Twig
Filters
The following example removes all HTML tags{{ name|striptags|title }}
Example joining a list by commas
{{ list|join(', ') }}
Applying a list on a section of code
{% filter upper %}
This text becomes uppercase
{% endfilter %}
Twig
Functions and Control structure
{% for i in range(low=1, high=10, step=2) %}
{{ i }},
{% endfor %}
To display a list
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
If structure control
{% if users|length > 0 %}
<ul>
{% for user in users %}
<li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
Twig
Comments
{# note: disabled template because we no longer use this
{% for user in users %}
...
{% endfor %}
#}
Twig
Encoding and working with Dates
Encoding{{ data|convert_encoding('UTF-8', 'iso-2022-jp') }}
{# versus #}
{{ data|convert_encoding(from='iso-2022-jp', to='UTF-8') }}
Formating Dates with Timezones
{# both work #}
{{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }}
{{ "now"|date(timezone="Europe/Paris", 'd/m/Y H:i') }}
Twig
Template Inheritance
We can create a base "skeleton" template with all common elements<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
<div id="footer">
{% block footer %}
© Copyright 2011 by <a href="http://domain.invalid/">you</a>.
{% endblock %}
</div>
</body>
</html>
Twig
Template Inheritance
We can create a base "skeleton" template with all common elements{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ parent() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome to my awesome homepage.
</p>
{% endblock %}
Twig
Macros
Useful to reuse often used HTML fragments to not repeat yourself{% macro input(name, value = "", type = "text", size = 20) %}
<input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
{% endmacro %}
Import the macro
{% import "forms.html" as forms %}
<p>{{ forms.input('username') }}</p>
All Together
Example
Bootie Bowling Score
Program to see the score of Bootsoft teams
Database
Two tables in MySQL
usersid - INTEGER
name - VARCHAR
avatar - VARCHAR
team - VARCHAR
scores
id - INTEGER
round - INTEGER
points - INTEGER
user_id - INTEGER
Composer
We create the composer file in the root
{
"name": "Bowling",
"require": {
"php": ">=5.3.0",
"slim/slim": "2.*",
"slim/extras": "2.*",
"twig/twig": "1.*",
"dhorrigan/capsule": "*"
}
}
In the console execute:
composer install
Index and .htaccess
.htaccessRewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
index.php
require 'vendor/autoload.php';
$app = new \Slim\Slim();
$app->get('/', function () {
echo "Hello Bowling!!";
});
$app->run();
Models
models/User.phpclass User extends Illuminate\Database\Eloquent\Model {
protected $table = "Users";
public $timestamps = false;
public function scores() {
return $this->hasMany('Score');
}
}
models/Score.php
class Score extends Illuminate\Database\Eloquent\Model {
protected $table = "Scores";
public $timestamps = false;
}
Autoload Models
To autoload the models we have to add it to composer.json
{
"name": "Bowling",
"require": {
"php": ">=5.3.0",
"slim/slim": "2.*",
"slim/extras": "2.*",
"twig/twig": "1.*",
"dhorrigan/capsule": "*"
},
"autoload": {
"classmap": [
"models"
]
}
}
In the console execute:
composer update
Setting up database
In the index.php add this code
// Make a new connection
$app->db = Capsule\Database\Connection::make('default', array(
'driver' => 'mysql',
'host' => 'localhost',
'port' => 3306,
'database' => 'bowling',
'username' => 'root',
'password' => '',
'prefix' => '',
'charset' => "utf8",
'collation' => 'utf8_general_ci'
), true);
Generate the scores
Off the record: I generate the Score rows randomly with this code
$app->get('/generate', function () {
$users = User::all();
foreach ($users as $user) {
for ($i = 1; $i<=10; $i++) {
$oScore = new Score();
$oScore->round = $i;
$oScore->points = rand(0,10);
$oScore->user_id = $user->id;
$oScore->save();
}
}
echo "generated";
});
Routing
/users$app->get('/users', function () {
$users = User::all();
echo $users->toJson();
});
/team/:team
$app->get('/team/:team', function ($team) {
$users = User::where('team', '=', $team)->get();
echo $users->toJson();
});
/user/:id
$app->get('/user/:id', function ($id) use ($app) {
$user = User::with('scores')->where('id', '=', $id)->get();
echo $user->toJson();
echo Score::where('user_id', '=', $id)->sum('points');
});
Twig
Now lets setup Twig in Slim
In the index change$app = new \Slim\Slim();
By
// Setup custom Twig view
$twigView = new \Slim\Extras\Views\Twig();
$app = new \Slim\Slim(array(
'debug' => true,
'view' => $twigView,
'templates.path' => 'templates/',
));
Templates
We are going to get Zurb foundation (CSS Framework) using compass
Execute in the consolecompass create public -r zurb-foundation --using foundation
Templates
create base.html in templates
<!-- Nav Bar -->
<div class="row">
<div class="large-12 columns">
<div class="nav-bar right">
<ul class="button-group">
<li><a href="/team/TEAM_1" class="button">Team 1</a></li>
<li><a href="/team/TEAM_2" class="button">Team 2</a></li>
<li><a href="/team/TEAM_3" class="button">Team 3</a></li>
<li><a href="/team/TEAM_4" class="button">Team 4</a></li>
</ul>
</div>
<h1><a href="/">Bootsoft Bowling</a></h1>
<hr />
</div>
</div>
<!-- End Nav -->
{% block content %}{% endblock %}
Templates
create players.html in templates
{% extends "base.html" %}
{% block content %}
{% for user in users %}
<div class="row">
<div class="small-4 large-2 columns">
<img src="http://s3.amazonaws.com/37assets/svn/765-default-avatar.png" width="60"/>
</div>
<div class="small-4 large-6 columns">
<h2>{{ user.name|e }}</h2>
</div>
<div class="small-4 large-2 columns">
<h3>{{ user.score }}</h3>
</div>
</div>
{% endfor %}
{% endblock %}
Templates
Now at index.php change the code to
$app->get('/', function () use ($app) {
$users = User::all();
foreach ($users as $user) {
$user->score = Score::where('user_id', '=', $user->id)->sum('points');
}
$app->render('players.html', array('users' => $users));
});
Some Links
Slim Framework
Official Website
PHP the Rigth Way
http://www.phptherightway.com/
Keeping it Small (Jeremy Kendall)
Slim + Composer + Eloquent ORM (Phil Sturgeon)
Eloquent ORM
Laravel Framework
Laravel Eloquent ORM
THE END
Thank you!
BY Cesar
Slim Framework, Composer, Eloquent and Twig
By revul
Slim Framework, Composer, Eloquent and Twig
revul.es/slim
- 2,743