Thursday, October 30, 2014

Laravel 4 – simple website with backend tutorial – Part 1

Laravel 4 – simple website with backend tutorial – Part 1

85 Comments
Getting started with Laravel
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon
Laravel 4 app will be developed at the same time as writing this article, and everything will be up on Github. I’ll try to separate the tutorial parts in branches so it will be easier to follow. Github URL: https://github.com/bstrahija/l4-site-tutorial
EDIT: The second part of Laravel 4 tutorial is available!!!
This is by no means a tutorial for beginners, there are plenty of those ;) I assume you already know the basics on how to install Composer, pull down the Laravel 4 base application. You will need some mid-level knowledge on tools like Composer, Git, working in the terminal
I’m going to put up some links to resources on getting started with Laravel and Composer at the end of this article. Also keep in mind that at this point Laravel 4 is still in BETA, but it’s really stable and scheduled for release during May.

Installing Laravel 4 and all the dependencies

Since Laravel 4 already leverages a lot of third party packages, we’ll expand on that, and add some that could be useful for our application. Here are some of composer packages that we’re going to need:
  • Sentry – user authentication (cartalyst/sentry)
  • Imagine – image manipulation and resizing (imagine/Imagine)
  • Markdown – for converting markdown text to HTML (dflydev/markdown)
So, first let’s start by creating a new L4 app. We’re going to call our app simply “L4 Site”. You can call yours anything you like ;)
1
2
git clone -b develop git://github.com/laravel/laravel.git l4_site
cd l4_site
The next step is to setup our composer file. After adding our dependencies, it should look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "require": {
        "laravel/framework": "4.0.*",
        "cartalyst/sentry": "2.0.*",
        "dflydev/markdown": "v1.0.2",
        "imagine/Imagine": "v0.4.1"
    },
    "autoload": {
        "classmap": [
            "app/commands",
            "app/controllers",
            "app/models",
            "app/database/migrations",
            "app/database/seeds",
            "app/tests/TestCase.php"
        ]
    },
    "scripts": {
        "post-update-cmd": "php artisan optimize"
    },
    "config": {
        "preferred-install": "dist"
    },
    "minimum-stability": "dev"
}
Then just run “php composer install” and wait for all the dependencies to download. This could take a couple of minutes.
When everything is finished downloading we need to check if the app actually works. For this I would recommend to setup a virtual host entry, or if you working on a machine with PHP 5.4 you can utilize the PHP built in server by running “php artisan serve” from the console.
For simplicity sake I’ll take the approach with the build in PHP server which will start the server on the URL http://localhost:8000/.
If you get the Hello World! page then everything is fine, but if you see any errors you should consult the Laravel 4 documentation.

Setup the database and migrations

The next step is to setup the database connection and create our migrations. I’ll be working with a MySQL database, but you can choose whatever database type you want as long as Laravel 4 supports it. If don’t know what migrations and seeding are, you can read more on that here: http://four.laravel.com/docs/migrations
My database is named “l4_site”, and now I am going to enter the database credentials into the database configuration file (app/config/database.php). This is pretty straightforward, but if you run into problems consult the Laravel 4 documentation.
Since we’re leveraging the Sentry package for our user authentication stuff, and Sentry already has some migration setup, we just need to run those migrations by running the following command in our console:
1
php artisan migrate --package=cartalyst/sentry
Sentry should create 4 DB tables: users, groups, users_groups and throttle. To complete installation for the Sentry package consult the Sentry docs: http://docs.cartalyst.com/sentry-2/installation/laravel-4
EDIT: Some people complained there’s not enough info on installing Sentry, so basicaly you need to add the service provider and the alias to your app/config/app.php file:
1
'Cartalyst\Sentry\SentryServiceProvider'
and
1
'Sentry' => 'Cartalyst\Sentry\Facades\Laravel\Sentry',
I hope this clears it up.
Now that we have our authentication tables setup, we need to create tables that will contain the actual content. We will have 2 types of content entries, articles and pages. So the migrations that we need are these:
1
2
php artisan migrate:make create_articles_table --table=articles --create
php artisan migrate:make create_pages_table --table=pages --create
The migrations are created inside the directory “app/database/migrations“. To keep things simple, these are my migrations.
Articles:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
 
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
 
class CreateArticlesTable extends Migration {
 
    public function up()
    {
        Schema::create('articles', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('title');
            $table->string('slug');
            $table->text('body')->nullable();
            $table->string('image')->nullable();
            $table->integer('user_id');
            $table->timestamps();
        });
    }
 
    public function down()
    {
        Schema::drop('articles');
    }
}
and Pages:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
 
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
 
class CreatePagesTable extends Migration {
 
    public function up()
    {
        Schema::create('pages', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('title');
            $table->string('slug');
            $table->text('body')->nullable();
            $table->integer('user_id');
            $table->timestamps();
        });
    }
 
    public function down()
    {
        Schema::drop('pages');
    }
}
Now just run “php artisan migrate” and the tables are created. It’s magic :)

Our models

To actually work with the database we need to create our models. The models that we need are:
app/models/Article.php
1
2
3
4
5
6
7
8
9
10
11
12
<?php namespace App\Models;
 
class Article extends \Eloquent {
 
    protected $table = 'articles';
 
    public function author()
    {
        return $this->belongsTo('User');
    }
 
}
app/models/Page.php
1
2
3
4
5
6
7
8
9
10
11
12
<?php namespace App\Models;
 
class Page extends \Eloquent {
 
    protected $table = 'pages';
 
    public function author()
    {
        return $this->belongsTo('User');
    }
 
}
There’s already a default User model in the “app/models” folder, I just like to namespace it like the others under App\Models. Go ahead and check it out at: https://github.com/bstrahija/l4-site-tutorial/blob/master/app/models/User.php

Seeding the database

For the app to actually contain some data, I like to add some dummy content. This can be achieved easily by using the Laravel 4 seeds. The files should be located in the “app/database/seeds” directory, and here my setup for the app:
app/database/seeds/DatabaseSeeder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
 
class DatabaseSeeder extends Seeder {
 
    public function run()
    {
        $this->call('SentrySeeder');
        $this->command->info('Sentry tables seeded!');
 
        $this->call('ContentSeeder');
        $this->command->info('Content tables seeded!');
    }
 
}
EDIT: Since we use the Sentry package I changed the way the user is created. We now use
1
Sentry::getUserProvider()->create();
for creation.
Also note that the User model is namespaced under App\Models, so you should also update you default model. Just take a look at everything here: https://github.com/bstrahija/l4-site-tutorial/blob/master/app/models/User.php
app/database/seeds/SentrySeeder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
 
use App\Models\User;
 
class SentrySeeder extends Seeder {
 
    public function run()
    {
        DB::table('users')->delete();
        DB::table('groups')->delete();
        DB::table('users_groups')->delete();
 
        Sentry::getUserProvider()->create(array(
            'email'       => 'admin@admin.com',
            'password'    => "admin",
            'first_name'  => 'John',
            'last_name'   => 'McClane',
            'activated'   => 1,
        ));
 
        Sentry::getGroupProvider()->create(array(
            'name'        => 'Admin',
            'permissions' => array('admin' => 1),
        ));
 
        // Assign user permissions
        $adminUser  = Sentry::getUserProvider()->findByLogin('admin@admin.com');
        $adminGroup = Sentry::getGroupProvider()->findByName('Admin');
        $adminUser->addGroup($adminGroup);
    }
 
}
app/database/seeds/ContentSeeder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
 
use App\Models\Article;
use App\Models\Page;
 
class ContentSeeder extends Seeder {
 
    public function run()
    {
        DB::table('articles')->delete();
        DB::table('pages')->delete();
 
        Article::create(array(
            'title'   => 'First post',
            'slug'    => 'first-post',
            'body'    => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
            'user_id' => 1,
        ));
 
        Page::create(array(
            'title'   => 'About us',
            'slug'    => 'about-us',
            'body'    => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
            'user_id' => 1,
        ));
    }
 
}
Now run “php artisan db:seed” in the console, and your database will be populated with the dummy data from the seeds. Nice.

Extra tip on database seeding

I created a couple of custom artisan commands to refresh the app. You can check them out: https://github.com/bstrahija/l4-site-tutorial/tree/master/app/commands
This is useful for me when working on the app, and sometimes the data is modified, or some entries are deleted. Then I can easily reset the database to a fresh state by running:
1
php artisan app:refresh
Also, since the migrate command doesn’t migrate 3rd party packages, I added the Sentry migration to the command.
You can add your own commands, call other package migrations etc.

Tinker with our models

Laravel 4 comes with a nice tool for tinkering with out app.
What we can do now is test if the database was properly seeded. Just run “php artisan tinker” and we get into a simple REPL for our app.
Now to check if our pages and articles were seeded we just run the following inside the REPL:
1
echo App\Models\Page::all();
or
1
echo App\Models\Article::all();
And for each command we should get our database content entries in JSON format.

What is next?

For now we just created our database and models, added some dummy data to the database, and there isn’t really much to see in the browser yet.
In the next part we will start to create our backend panel so prepare yourself for some working with routes, controllers, views and assets.
The backend will be built with the Twitter Bootstrap package, since I find it’s the easiest to integrate.

No comments: