Laravel Overview

Installation

sudo composer create-project laravel/laravel newwebsite --prefer-dist
sudo mkdir -m 777 app/storage/cache app/storage/logs app/storage/meta app/storage/sessions app/storage/views

Dependencies

  • composer
  • PHP 5.4+
  • mcrypt (PHP extension)
  • php5-json (depending on OS)
  • Apache/alternative (support also for nginx)
  • MySQL/alternative (support also for Postgres, SQLite, and SQL Server) 

Controllers

<?php

class ProductsController extends AppController
{
    public function engine_index
    {
        $this->Paginator->settings = array(
            'order' => 'Product.name ASC'
        );

        $items = $this->Paginator->paginate('Product');

        $this->set(compact('items'));
    }

    public function engine_add()
    {
        if (!empty($this->request->data)) {
            $this->Product->create();

            if ($this->Product->save($this->request->data)) {
                $this->Session->setFlash('The product has been saved.', 'success');

                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash('The product could not be saved. Please see the errors below.', 'error');
            }
        }

        $categories = $this->Product->Category->find('list');
        $this->set(compact('categories'));
    }

    public function engine_edit($id)
    {
        if (!empty($this->request->data)) {
            $this->Product->id = $id;

            if ($this->Product->save($this->request->data)) {
                $this->Session->setFlash('The product has been saved.', 'success');

                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash('The product could not be saved. Please see the errors below.', 'error');
            }
        }

        $this->request->data = $this->Product->read(null, $id);

        $categories = $this->Product->Category->find('list');
        $this->set(compact('categories'));
    }

    public function engine_delete($id)
    {
        if ($this->Product->delete($id)) {
            $this->Session->setFlash('The product has been deleted.', 'success');
        } else {
            $this->Session->setFlash('The product could not be deleted.', 'error');
        }

        return $this->redirect(array('action' => 'index'));
    }
}

CakePHP Example

Laravel Example

<?php

class ProductsController extends \BaseController
{
    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        $products = Product::orderBy('name', 'ASC')->paginate(15);

        return View::make('engine::products.index')->with(array('products' => $products));
    }


    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function add()
    {
        $product = new Product();

        if (Request::getMethod() == 'POST') {
            $product->fill(Input::except(array('_token')));
            $product->slug = Str::slug($product->name);
            $product->save();

            return Redirect::route('engine.products.index')->with('success', 'The product has been saved.');
        }

        $getCategories = Category::get();

        $categories = array();
        foreach ($getCategories as $category) {
            $categories[$category->id] = $category->name;
        }

        return View::make('engine::products.add')->with(array('product' => $product, 'categories' => $categories));
    }


    /**
     * Store a newly created resource in storage.
     *
     * @param int $id
     * 
     * @return Response
     */
    public function edit($id)
    {
        $product = Product::find($id);

        if (Request::getMethod() == 'POST') {
            $product->fill(Input::except(array('_token')));
            $product->slug = Str::slug($product->name);
            $product->save();

            return Redirect::route('engine.products.index')->with('success', 'The product has been saved.');
        }

        $getCategories = Category::get();

        $categories = array();
        foreach ($getCategories as $category) {
            $categories[$category->id] = $category->name;
        }

        return View::make('engine::products.edit')->with(array('product' => $product, 'categories' => $categories));
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int $id
     * 
     * @return Response
     */
    public function delete($id)
    {
        Product::find($id)->delete();

        return Redirect::route('engine.products.index')->with('success', 'The product has been deleted.');
    }
}

Resource Controllers

php artisan controller:make PhotoController
Route::resource('photo', 'PhotoController');
<?php

class PhotoController extends \BaseController
{

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        //
    }


    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create()
    {
        //
    }


    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store()
    {
        //
    }


    /**
     * Display the specified resource.
     *
     * @param  int $id
     * @return Response
     */
    public function show($id)
    {
        //
    }


    /**
     * Show the form for editing the specified resource.
     *
     * @param  int $id
     * @return Response
     */
    public function edit($id)
    {
        //
    }


    /**
     * Update the specified resource in storage.
     *
     * @param  int $id
     * @return Response
     */
    public function update($id)
    {
        //
    }


    /**
     * Remove the specified resource from storage.
     *
     * @param  int $id
     * @return Response
     */
    public function destroy($id)
    {
        //
    }

}
<?php

class Product extends AppModels
{
    public $belongsTo = array(
        'Category' => array(
            'className' => 'Category',
            'foreignKey' => 'category_id',
        )
    );

    public function getFullName()
    {
        return $this->data['Product']['name'] . ' ' . $this->data['Product']['code'];
    }
}

Models

CakePHP Example

Laravel Example

<?php

class Product extends Eloquent
{
    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'products';

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = array();
    protected $guarded = array('id');

    public function category()
    {
        return $this->belongsTo('Category');
    }

    public function getFullName()
    {
        // Name and code are database field.

        return $this->name . ' ' . $this->code;
    }
}

Views

Forms

@extends('layouts.base')

@section('title')
    Add Product
@stop

@section('content')

{{ Form::model($product, array('method' => 'put', 'route' => array('admin.products.edit', 'product' => $product->id), 'class' => 'col-md-5')) }}
    <div class="form-group">
        {{ Form::label('name', 'Name') }}
        {{ Form::text('name', Input::get('name'), array('class' => 'form-control')) }}
    </div>
    <div class="form-group">
        {{ Form::label('active', 'Active') }}
        {{ Form::checkbox('active', 1, Input::get('active')) }}
    </div>
    <div class="form-group">
        {{ Form::label('description', 'Description') }}
        {{ Form::text('description', Input::get('description'), array('class' => 'form-control')) }}
    </div>
    <div class="form-group">
        {{ Form::label('category_id', 'Category') }}
        {{ Form::select('category_id', $categories, Input::get('category_id'), array('class' => 'form-control')) }}
    </div>
    <div class="form-group">
        {{ Form::submit('Submit', array('class' => 'btn btn-primary')) }}
    </div>
{{ Form::close() }}

@stop

Blade

@if(!empty($variable)
    Hello
@else
    Goodbye
@endif

@foreach($product in $products)
    {{ $product->name }}<br />
@endforeach

@for ($i = 0; $i < 10; $i++)
The current value is {{ $i }}
@endfor

{{ $product->active ? 'Yes' : 'No' }}

{{ time() }}

@include('product.header', array('product' => $product))

Routing

Basic Routing

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

Route::get('/', array('as' => 'home', 'uses' => 'BaseController@home'));

Route::group(array('prefix' => 'engine'), function()
{
    Route::resource('products', 'ProductsController');
    Route::get('products/delete/{id}', array(
        'as' => 'admin.products.delete', 
        'uses' => 'ProductsController@delete'
    ));
});

Route Filters

<?php
// Sample route group with auth requirement
Route::group(array('before' => 'auth', 'prefix' => 'engine'), function() {
    Route::resource('products', 'ProductsController');
    Route::get('products/delete/{id}', array(
        'as' => 'admin.products.delete',
        'uses' => 'ProductsController@delete'
    ));
});

// Sample route that requires the user to have a field "activated_email" that has a value,
// otherwise redirected to a page notifying them to confirm their email.
Router::filter('activated_email', function () {
    if (!Auth::user()->activated_email) {
        return Redirect::to('activate_email');
    }
});

Route::get('dashboard', array(
    'before' => 'auth|activated_email', 
    'uses' => 'UsersController@dashboard'
));

Querying

Fetching Associations

<?php

// This method will optimize the associations. Rather than doing
// a lot of joins like cake would, it will do an IN statement.
$product = Product::with('category')->get();

// Getting the category name
$category_name = Product::find(1)->category()->name;

Query Scopes

<?php

class Product extends Eloquent
{
    // Method call is always prepended by "scope"
    public function scopeRecent($query)
    {
        // This query is returning the most recent 5 items created in the last 5 minutes.
        // We use Carbon to easily figure out the value to plug in.
        return $query
            ->where('created_at', '<=', Carbon::now()->subMinutes(5))
            ->orderBy('created_at', 'desc')
            ->limit(5);
    }
}

// In your controller
$products = Product::recent()->get();

Extras

  • Workbench
  • Queues
  • 3rd Party Support

Migrations

<?php

class CreateProductsTable extends Migration
{

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        if (!Schema::hasTable('products')) {
            Schema::create('products', function ($table) {
                $table->increments('id');
                $table->string('name');
                $table->boolean('active')->index();
                $table->text('description');
                $table->integer('category_id')->index();
                $table->timestamps();
            });
        }
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }

}
sudo php artisan migrate:make create_products_table

Pros / Cons

Pros

  • Widely used, well liked by the PHP community.
  • Easy to get into, compared to others.
  • Strong composer support
  • Documentation / troubleshooting
  • Modern PHP code/standards
  • Querying is really nice and easy

Cons

  • Fascades usage is controversial, some love it, some think it's a bad practice.
  • Form validation in the controller.
  • New major releases often.
  • Workbench tricky at first.

laravel

By Charlie Page

laravel

  • 748