laravel and django and rails, oh my!
DESCRIPTION
The Laravel Framework. Showing Laravel alongside Rails and Django. A presentation at CoderFaire 2014.TRANSCRIPT
Caddis InteractiveChris Roberts @thechrisroberts
Laravel and Django and Rails, Oh My!Become a web artisan with the Laravel PHP framework
1
Caddis InteractiveChris Roberts @thechrisroberts 2
Caddis InteractiveChris Roberts @thechrisroberts
Compare Apples to ApplesWhich of these is your favorite Doctor?
3
Caddis InteractiveChris Roberts @thechrisroberts
Apples to Apples
4
Caddis InteractiveChris Roberts @thechrisroberts
• Pick what fits you and learn it inside and out.
• Always be ready to try new things.
• Find the right tool for the job.
Choosing Your EnvironmentIn some ways, it doesn’t matter
5
Caddis InteractiveChris Roberts @thechrisroberts
• What does your server environment support?
• Will your chosen framework scale up when your work goes viral?
• Are your developers familiar with the tools?
• How is the community support?
• Does it have the third-party utilities you need?
Choosing Your EnvironmentWhen it matters
6
Caddis InteractiveChris Roberts @thechrisroberts
• Ruby is generally considered more human-readable
• Python is more script-like and white space significant
• PHP uses a C-style syntax
Looking at the details: Language SyntaxLanguage Overview
7
Caddis InteractiveChris Roberts @thechrisroberts
• Each language supports closures
• Ruby: blocks, procs, and lambdas
• Python and PHP: nested functions
• PHP closures introduced in PHP 5.3
Looking at the details: Language SyntaxLanguage Overview
8
Caddis InteractiveChris Roberts @thechrisroberts
• Each language supports OO code.
• PHP is not what it used to be.
• Namespaces, inheritance, autoloading
• PSR standards
Looking at the details: Object OrientedLanguage Overview
9
Caddis InteractiveChris Roberts @thechrisroberts
• Each framework has options for unit testing
• Django uses Python’s unittest
• Rails has unit testing baked in
• Laravel has out-of-the-box support for PHPUnit with the ability to run assertions on your routes
Find your bugs before your users find themUnit Testing
10
Caddis InteractiveChris Roberts @thechrisroberts
• Ruby: gem packages
• Python: pip (official support in Python 3.4)
• PHP: composer
Looking at the details: Third-party PackagesLanguage Overview
11
Caddis InteractiveChris Roberts @thechrisroberts
• Ruby: Github (Rails and Erlang), original Twitter
• Python: Disqus, Instagram
• PHP: Wikipedia, many CMS’s, Facebook uses their own variant
Who uses itLanguage Overview
12
Caddis InteractiveChris Roberts @thechrisroberts
• Numerous frameworks per language
• Rails and Django are the most popular for their languages
• PHP has many contenders: Yii, Zend, CakePHP, CodeIgniter, Symfony, Aura, Slim, Silex, numerous others.
• Pick the one that fits your project
Rails, Django, and LaravelFramework Overview
13
Caddis InteractiveChris Roberts @thechrisroberts
• Follows PSR-0/PSR-4 for namespacing and autoloading
• Flexible configuration system with multiple environment support
• Powerful ORM tied to a comprehensive query builder
• Highly extensible through service providers
• MVC design pattern in Laravel 4
• Excellent documentation
Laravel for PHPThe PHP Framework for Web Artisans
14
Caddis InteractiveChris Roberts @thechrisroberts
DWRM (Doctor Who Relationship Management)
15
Caddis InteractiveChris Roberts @thechrisroberts
Getting up and running
16
Caddis InteractiveChris Roberts @thechrisroberts
• Models: doctors, companions, enemies, episodes
• Also prepare for users, comments, and ratings
• Need pivot tables to track relationships
• Set up migrations to easily create and update our data structure
• Add seed data for testing
Pieces for a DWRMSetting things up
17
Caddis InteractiveChris Roberts @thechrisroberts
• Laravel Migrations: versionable table schemas.
• Puts your schema inside source control
• Easily built out with Laravel’s command line utility: artisan
MigrationsBuilding out your database in code
18
Caddis InteractiveChris Roberts @thechrisroberts
Laravel ArtisanThis command line tool provides numerous helpers from generating classes to running migrations to seeding data.
19
Caddis InteractiveChris Roberts @thechrisroberts
use Illuminate\Database\Schema\Blueprint;use Illuminate\Database\Migrations\Migration;
class CreateDoctorsTable extends Migration {
public function up(){
Schema::create('doctors', function($table) {$table->increments('id')
->integer('number') ->string('image') ->text('description') ->timestamps();
});}
public function down(){
Schema::drop('doctors');}
}
20
Caddis InteractiveChris Roberts @thechrisroberts
use Illuminate\Database\Schema\Blueprint;use Illuminate\Database\Migrations\Migration;
class ModifyDoctorsTable extends Migration {
public function up(){
Schema::table('doctors', function($table) {$table->string('name');
});}
public function down(){
Schema::table('doctors', function($table) {$table->dropColumn('name');
});}
}
21
Caddis InteractiveChris Roberts @thechrisroberts
Run the Migration
22
Caddis InteractiveChris Roberts @thechrisroberts
class CreateDoctors < ActiveRecord::Migration def change create_table :doctors do |t| t.integer :number t.string :name t.string :image t.text :description t.timestamps end endend
Rails MigrationRails provides a similar mechanism for setting up your data structure
23
Caddis InteractiveChris Roberts @thechrisroberts
Django MigrationDjango also provides migrations, though they work a bit differently than Rails or Laravel
24
• Changes are made on the model class file
• Migrations are automatically generated based on model changes
Caddis InteractiveChris Roberts @thechrisroberts
• Laravel seeding makes use of its ORM methods to easily create and store model data.
• The query builder can also be used to manipulate data directly.
• DB seeds are run using Artisan.
Loading test dataLaravel data seeding makes it easy to bootstrap your website or load data for testing.
25
Caddis InteractiveChris Roberts @thechrisroberts
class DoctorTableSeeder extends Seeder {
public function run(){
Doctor::delete();
Doctor::create(array('name' => 'Christopher Eccleston', 'number' => '9', 'description' => '...', 'image' => '...' ));
Doctor::create(array('name' => 'David Tennant', 'number' => '10', 'description' => '...', 'image' => '...' ));
Doctor::create(array('name' => 'Matt Smith', 'number' => '11', 'description' => '...', 'image' => '...' ));
Doctor::create(array('name' => 'Peter Capaldi', 'number' => '12', 'description' => '...', 'image' => '...' ));
}}
26
Caddis InteractiveChris Roberts @thechrisroberts
class CompanionTableSeeder extends Seeder {
public function run(){
Companion::delete();
$doctorNine = Doctor::where('number', 9)->first();$doctorTen = Doctor::where('number', 10)->first();
Companion::create(array(‘name' => 'Rose Tyler','description' => '...','image' => '...'
)) ->doctors() ->attach(array($doctorNine->id, $doctorTen->id));
}}
27
Caddis InteractiveChris Roberts @thechrisroberts
Running php artisan db:seed
28
Caddis InteractiveChris Roberts @thechrisroberts
• Similar in Rails
Doctor.create(name: "David Tennant", number: 10, description: "...")
• Different in Django
• Can import from structured data (XML, JSON, etc)
• Primarily imported via data migration
Django and RailsOther ways to do the same
29
Caddis InteractiveChris Roberts @thechrisroberts
• Class that provides additional abstraction between you and data
• A model represents an object in the database
• The framework provides ways to manipulate those models
• Laravel, Rails, and Django each follow the Active Record pattern
Data ModelWriting code that represents “things”
30
Caddis InteractiveChris Roberts @thechrisroberts
• Laravel’s ORM (called Eloquent) makes it easy to connect related models.
• In our demo, each doctor has a companion, each episode a doctor, companion, and enemy, etc.
• We also have comments and ratings that can attach to any of these.
Model relationshipsConnecting related pieces
31
Caddis InteractiveChris Roberts @thechrisroberts
Modeling the Doctorclass Doctor extends Eloquent {
public function companions(){
return $this->belongsToMany('Companion');}
public function enemies(){
return $this->belongsToMany('Enemy');}
public function episodes(){
return $this->belongsToMany('Episode');}
}
32
Caddis InteractiveChris Roberts @thechrisroberts
Modeling the Companionclass Companion extends Eloquent {
public function doctors(){
return $this->belongsToMany('Doctor');}
public function episodes(){
return $this->belongsToMany('Episode');}
}
33
Caddis InteractiveChris Roberts @thechrisroberts
Relationships
There are many ways models might relate to each other. Laravel provides methods for interacting with each option. This includes nested relations, ie, accessing a grandparent model through a child.
• one-to-one
• hasOne(…)
• belongsTo(…)
• one-to-many
• hasMany(…)
• belongsTo(…)
• many-to-many
• belongsToMany(…)
34
Caddis InteractiveChris Roberts @thechrisroberts
• Our tables are defined and created
• We’ve loaded seed data
• We have pieced together our models and their relations
• Time to get something on screen
• First step: connecting the URL to our code
Stepping backReviewing the state of our application
35
Caddis InteractiveChris Roberts @thechrisroberts
• Routing is finding out where a user once to go and directing them to the appropriate place in your code.
• Laravel provides several ways to define your application routes.
• It also provides filters to allow you to lock routes based on certain situations, ie, keep guests away from routes requiring authentication.
Laravel RoutingProvides a powerful interface to direct users based on their url path and depending on your defined filters
36
Caddis InteractiveChris Roberts @thechrisroberts
Routing the DoctorRoute::get('/', 'IndexController@index');
Route::get('/doctors', 'DoctorController@index');Route::get('/companions', 'CompanionController@index');Route::get('/enemies', 'EnemyController@index');Route::get('/episodes', 'EpisodeController@index');
Route::get('/doctor/{id}', 'DoctorController@get');Route::get('/companion/{id}', 'CompanionController@get');Route::get('/enemy/{id}', 'EnemyController@get');Route::get('/episode/{season}/{show}', 'EpisodeController@get');
Route::post('/comment', 'CommentController@post');
37
Caddis InteractiveChris Roberts @thechrisroberts
Django Routing• Django handles routes via a URL dispatcher which matches
routs through regular expressions.
• Does not match against GET, POST, etc. from django.conf.urls import patterns, urlfrom . import views
urlpatterns = patterns('', url(r'^doctors/$', views.list_doctors) url(r'^doctor/(\d+)$', views.view_doctor))
38
Caddis InteractiveChris Roberts @thechrisroberts
Rails Routing• Routes defined in application routes.db
• Out of the box, no route filtering
• Able to define specific routes to specific controller methods
• Able to automatically route to controllers and methods
Rails.application.routes.draw do root 'index#index' get 'doctors' => 'doctor#index' get 'doctor/:id' => 'doctor#get' resources :enemyend
39
Caddis InteractiveChris Roberts @thechrisroberts
• Performs data validation
• Interacts with necessary models
• Generates views
• Returns responses to the client or redirects to an alternate route
Laravel ControllersMediating between your model and view
40
Caddis InteractiveChris Roberts @thechrisroberts
DoctorController.phpclass DoctorController extends BaseController {
public function index(){
$doctors = Doctor::orderBy('number')->get();return View::make('doctors', array(‘doctors' => $doctors));
}
public function get($id){
$doctor = Doctor::with(array(‘companions', ‘episodes'))->find($id);$ratings = RatingController::getRating('doctor', $id);$comments = Comment::where('item_id', $id)
->where('item_type', 'doctor') ->with('user') ->orderBy('created_at', 'desc') ->get();
return View::make('items.doctor', array( 'doctor' => $doctor, 'ratings' => $ratings, 'comments' => $comments ));
}}
41
Caddis InteractiveChris Roberts @thechrisroberts
Blade Tempting@extends('layouts.structure')
@section('content') <h1>The Modern Doctor</h1> <div class="row doctor"> @foreach ($doctors as $doctor) <div class="item"> <a href="/doctor/{{ $doctor->id }}"> <img src="{{ $doctor->image }}"> <h3>{{ $doctor->name }}</h3> </a> </div> @endforeach </div>@stop
42
Caddis InteractiveChris Roberts @thechrisroberts
Blade Tempting<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title> @if (isset($title)) {{ $title }} | @endif The Doctor </title> <link rel="stylesheet" href="/assets/css/style.css"> </head>
<body> <header class="container"> <h1 class="site"><a href="/">The Island of Doctor Who</a></h1> </header>
<div class="container"> @yield('content') </div> </body> <script src="/assets/js/script.min.js"></script></html>
43
Caddis InteractiveChris Roberts @thechrisroberts
Blade Tempting@extends('layouts.structure')
@section('content') <h1>The Modern Doctor</h1> <div class="row doctor"> @foreach ($doctors as $doctor) <div class="item"> <a href="/doctor/{{ $doctor->id }}"> <img src="{{ $doctor->image }}"> <h3>{{ $doctor->name }}</h3> </a> </div> @endforeach </div>@stop
44
Chris Roberts Caddis Interactive 45
Chris Roberts Caddis Interactive 46
Chris Roberts Caddis Interactive 47
Caddis InteractiveChris Roberts @thechrisroberts
public function get($id){
$doctor = Doctor::with(array(‘companions', ‘episodes’))->find($id);
$ratings = Rating::getRating('doctor', $id);$comments = Comment::where('item_id', $id)
->where('item_type', 'doctor') ->with('user') ->orderBy('created_at', 'desc') ->get();
return View::make('items.doctor', array('doctor' => $doctor, 'ratings' => $ratings, 'comments' => $comments ));
}
Retrieving individual modelsLaravel makes it easy to retrieve a model, any related data, and pass it to a view for presentation.
48
Caddis InteractiveChris Roberts @thechrisroberts
@extends('layouts.structure')
@section('content') <h1 class="title">{{ $doctor['name'] }}</h1> <div class="hero"> <img src="{{ $doctor['image'] }}"> </div>
<div class="rating"> Rated {{ $ratings['rating'] }} out of 5 with {{ $ratings['numRatings'] }} votes </div>
<p class="description"> {{ $doctor['description'] }} </p>
49
Caddis InteractiveChris Roberts @thechrisroberts
<h2>Companions</h2> <div class="row companion"> @foreach ($doctor['companions'] as $companion) <div class="item"> <a href="/companion/{{ $companion->id }}"> <img src="{{ $companion->image }}"> <h3>{{ $companion->name }}</h3> </a> </div> @endforeach </div>
<h2>Episodes</h2> <div class="row episode"> @foreach ($doctor['episodes'] as $episode) <div class="item"> <a href="/episode/{{ $episode->season }}/{{ $episode->episode }}"> <img src="{{ $episode->image }}"> <h3>Season {{ $episode->season }} episode {{ $episode->episode }}</h3> <h3>{{ $episode->name }}</h3> </a> </div> @endforeach </div>
@include('layouts.comment', array('type' => 'doctor', 'id' => $doctor['id'], 'comments' => $comments))@stop
50
Caddis InteractiveChris Roberts @thechrisroberts
<a name="comments"></a><h1>Comments</h1>
@if($errors->has())Display errors
@endif
<h2>Add Comment</h2>
{{ Form::open(array('url' => '/comment/')) }} {{ Form::hidden('type', $type) }} {{ Form::hidden('id', $id) }} {{ Form::label('title', 'Comment title'); }} {{ Form::text('title'); }} {{ Form::label('email', 'Email address'); }} {{ Form::text('email'); }} {{ Form::label('content', 'Comment text'); }} {{ Form::textarea('content'); }} {{ Form::submit('Submit'); }}{{ Form::close() }}
@if ($comments && sizeof($comments) > 0) @foreach ($comments as $comment) <div class="comment"> <h3>{{{ $comment['title'] }}}</h3> <div class="meta">Comment by {{ $comment['user']['name'] }} at {{ date('m-d-Y H:i:s', strtotime($comment['created_at'])) }}</div> <p> {{{ $comment['content'] }}} </p> </div> @endforeach@endif
51
Caddis InteractiveChris Roberts @thechrisroberts
class BaseController extends Controller {
public function __construct(){
$this->beforeFilter('csrf', array('on' => 'post'));}
}
CSRF ProtectionLaravel comes with filters to help protect you and your users from CSRF attacks
52
Caddis InteractiveChris Roberts @thechrisroberts
$validator = Validator::make(Input::all(),array(
'type' => 'in:doctor,companion,enemy,episode','title' => 'required|min:5','email' => 'required|email','content' => 'required',
));
ValidationOnce user data is received, Laravel provides tools to simplify validation and storage.
53
Caddis InteractiveChris Roberts @thechrisroberts
When the test failsif ($validator->fails()) {
return Redirect::to(URL::previous() . '#comments')->withErrors($validator)->withInput();
}
54
Chris Roberts Caddis Interactive 55
Caddis InteractiveChris Roberts @thechrisroberts
If valid, store the comment$comment = new Comment();$comment->user_id = Auth::id();$comment->item_id = Input::get('id');$comment->item_type = Input::get('type');$comment->title = Input::get('title');$comment->content = Input::get('content');$comment->save();
return Redirect::to(URL::previous() . '#comments')->with('message', 'Comment posted');
56
Chris Roberts Caddis Interactive 57
Caddis InteractiveChris Roberts @thechrisroberts
• Laravel provides a powerful, flexible framework for application development.
• Based on PHP, Laravel has broad support from most hosts.
• Language features and framework methods are on par with or better than other popular frameworks.
FinFrom start to end, Laravel provides a full-featured framework to make your development elegant and efficient
58
Caddis InteractiveChris Roberts @thechrisroberts
Recommended Resources• Laracasts: https://laracasts.com/
• Laravel Podcast and Forums: http://laravel.io/forum
• Code Bright by Dayle Rees
• #Laravel on Freenode
• https://github.com/JeffreyWay/Laravel-Generators
• Homestead: http://laravel.com/docs/homestead
59
Caddis InteractiveChris Roberts @thechrisroberts
Thank you!Chris Roberts [email protected]@thechrisroberts
60
Caddis is hiring let’s talk