Build Web Apps from Scratch with Laravel – The Eloquent ORM

Build Web Apps from Scratch with Laravel – The Eloquent ORM

Tutorial Details
  • Topic: Laravel PHP Framework (http://laravel.com)
  • Version: Laravel v3.2.1
  • Difficulty: Intermediate
  • Estimated Completion Time: 1 hour

In this Nettuts+ mini-series, we’ll build a web application from scratch, while diving into a great new PHP framework that’s rapidly picking up steam, called Laravel.

In this lesson, we’ll be working on an integral part of any web application: the Models. Along the way, we’ll learn about Laravel’s amazing ORM implementation: Eloquent.


Review

Welcome back to our Web Applications from Scratch with Laravel series! In the first tutorial of the series, we learned a lot about Laravel and its philosophy:

  • What Laravel is
  • What makes Laravel different from other PHP frameworks
  • Where to download Laravel
  • How to setup Laravel
  • How Laravel’s Routing system works
  • Some other features in Laravel’s Routing system
  • How to create your first Laravel Controller
  • Some additional features with Laravel’s Controllers
  • How to create your first Laravel View
  • How to use Laravel’s Blade Templating Engine

If you haven’t read it yet, you should take a look at the previous tutorial and give it a read – this will make it easier to understand the philosophy behind Laravel and most of what we discuss in this tutorial.

In this second part of the Laravel series, we’ll be building a crucial part of our test web application, Instapics, which is the Model implementation. Without furhter ado, let’s get started!


What are “Models”?

I’ve already talked a bit about what Models are in one of my previous articles, Zend Framework from Scratch – Models and Integrating Doctrine ORM, so to avoid repeating myself, I’ll write the gist of what I wrote before here. Feel free to refer to the other tutorial and read more about what Models are there.

Summary:

  • Models are representatives of the Database, and should be where all the business logic of an application resides
  • Controllers communicate with Models and ask them to retrieve information they need
  • This information is then passed by a Controller to the View and is rendered
  • It’s very rare that a Model directly interacts with a View, but sometimes it may happen when necessary
  • Models can talk with other Models and aren’t self-contained. They have relationships that intertwine with each other
  • These relationships make it easier and quicker for a Controller to get information, since it doesn’t have to interact with different Models – the Models can do that themselves

Models in Laravel, or in most frameworks, are developed the same way. The difference is that Laravel give us an easy way of building these models, by providing us with general-purpose methods that most models would need – the Eloquent ORM.


The Eloquent ORM

An ORM is an object-relational mapper, and Laravel has one that you will absolutely love! It is named “Eloquent,” because it allows you to work with your database objects and relationships using an eloquent and expressive syntax.

The Eloquent ORM is Laravel’s built-in ORM implementation. In my opinion, it’s one of the best ORM implementations I’ve seen so far – rivaling even Doctrine ORM. It’s incredibly elegant, making use of industry-standard conventions to lessen configuration.

Conventions

For example, using an Eloquent model assumes that the table the model is representing has an id field. The id is the primary key for any record, and is used by most of Eloquent’s methods.

Another thing that Eloquent correctly assumes is that your table name is the plural form of your model. For example, your User model will reference the users table. As this might not always be the standard for some, Laravel provides a way to override this: simply use the $table flag:

class User extends Eloquent {
    public static $table = 'my_users';
}

This will instruct Laravel not to use the convention and instead use the specified table.

Lastly, Laravel can also automate the creation and updating of timestamps for us. To do so, add a created_at and/or updated_at column in the table, and set the $timestamp flag in the model:

class User extends Eloquent {
    public static $timestamps = true;
}

Eloquent will see the flag, and automatically set the created_at field on creation, and update the updated_at field each time that a record is updated. Pretty cool, huh?

Quick Retrieval

Retrieving records is a snap with Eloquent’s retrieval methods. For example, you need to find a specific user record? Just do:

$user = User::find($user_id);

This returns a User model that you can do operations on! Need to use conditionals? Let’s imagine that you want to retrieve a user by email address. To accomplish this task, you might do something like:

$user = User::where('email', '=', $email)->first();

Alternatively, you could use Laravel’s dynamic methods:

$user = User::where_email($email)->first();

Easy Inserts & Updates

Inserting and updating models using Eloquent can be accomplished in three steps.

  • Step 1 – Get/Create the model.

            $user = new User();
            //or get an existing user
            $user = User::get($user_id);
            
  • Step 2 – Set the data

            $user->email = 'nikko@instapics.com';
            $user->password = 'test1234';
            
  • Step 3 – Save

            $user->save();
            
  • Done!

And finally, Defining Relationships.

Eloquent makes the process of defining relationships and retrieving related models simple and intuitive.

Damn right it does! Eloquent supports three types of relationships:

  1. One-to-One
  2. One-to-Many
  3. Many-to-Many

To define a relationship between models, you’ll need to create a method in both models that “describes” their relationships. For example, let’s say a User has_one User_Profile. You can do that by defining a user_profile method in the User model:

class User extends Eloquent {
    public function user_profile()
    {
        return $this->has_one('User_Profile');
    }
}

Because User is our “dominant” model here (i.e. a user has a profile, and not a profile has a user), we define that a User_Profile belongs_to a User:

class User_Profile extends Eloquent {
    public function user()
    {
        return $this->belongs_to('User');
    }
}

Once we’ve defined these relationship, we can then do:

/*
  Get the User_Profile object of a User
  This executes two SQL queries:
  
  SELECT * FROM `users` WHERE `id` = $user_id
  SELECT * FROM `user_profiles` WHERE `user_id` = $user_id
*/
$user = User::find($user_id);
$user_profile = $user->user_profile;

/*
  We can also do it the other way around
*/
$user_profile = User_Profile::where('user_id', '=', $user_id)->first();
$user = $user_profile->user;

One thing worth noting here is another convention: Eloquent assumes that the foreign key used in User_Profile is the referenced table’s name + _id. Again, if you want to change this behaviour, you can override it:

class User extends Eloquent {
    public function user_profile()
    {
        return $this->has_one('User_Profile', 'user_profile_user_id');
    }
}

Let’s say that we want to define the relationship between a User and his Photo uploads. This is a One-to-Many relationship, unlike the User-to-User Profile relationship which was One-to-One. We know that one User has_many Photo uploads, so:

class User extends Eloquent {
    public function photos()
    {
        return $this->has_many('Photo');
    }
}
...
...
...
class Photo extends Eloquent {
    public function user()
    {
        return $this->belongs_to('User');
    }
}

The main difference here with has_one is that the function we’ll use to retrieve a User‘s photos will now return an array of Photo objects. So, if we wanted to fetch all of a User‘s photos, we could do:

$photos = User::find($user_id)->photos;
foreach($photos as $photo) {
    ...
    ...
    ...
}

Nope, referring to photos as a property isn’t a typo. Laravel gives us this nice bit of sugar. We could also do:

$photos = User::find($user_id)->photos()->get();

Mant-to-Many Relationships

This one is a bit tricky, but once implemented, it makes it easy to handle Many-to-Many relationships between models. Let’s imagine, for example, that you, again, have a User model, and each of these Users can have multiple Groups. A Group can also have multiple Users. We’ll use three tables to represent these particular relationships:

  • Users – table where all our users are
  • Groups – table where all our groups are
  • Group User – table which lists down all users in a group

The table structure convention Eloquent will look for will be something like this:

  • users
    • id
    • …other columns
  • groups
    • id
    • …other columns
  • group_user
    • id
    • user_id
    • group_id
    • …other columns

One other convention to note here is that the intermediate table, group_user, is the singular names of the two tables that it is connecting, arranged alphabetically with an underscore. Like always, we’re free to override this.

Here’s how the code will look inside each of the models for these three tables:

class User extends Eloquent {
    public function groups()
    {
        //if we wanted to override the default naming convention
        //for the intermediate table, we can do it like so:
        //return $this->has_many_and_belongs_to('Group', 'group_listings');
        
        return $this->has_many_and_belongs_to('Group');
    }
}
...
...
...
class Group extends Eloquent {
    public function users()
    {
        //if we wanted to override the default naming convention
        //for the intermediate table, we can do it like so:
        //return $this->has_many_and_belongs_to('User', 'group_listings');
        
        return $this->has_many_and_belongs_to('User');
    }
}
...
...
...
class Group_User extends Eloquent {
    public function group()
    {
        return $this->has_one('Group');
    }
    
    public function user()
    {
        return $this->has_one('User');
    }
}

With this in place, we can then take advantage of Eloquent’s relationship functions:

//Get a user's groups
$groups = User::find($user_id)->groups;

//Get all users in a group
$users = Group::find($group_id)->users;

Step 1 - Creating the Instapics Database

Instapics

Continuing with our web application, Instapics, let’s start off by creating the database of our application. To do so, let’s write down the desired functionalities of the application:

  • Users can login and register for an account
  • Users can follow other users to see photos they have uploaded
  • Users can upload their own photo and apply a filter to it
  • Users can comment and like photos

From this, we can deduce the database tables we’ll need:

  • users

    • id (One-to-One with user_profiles.user_id, Many-to-Many with self using intermediate table relationships.follower_id and followed_id, One-to-Many with photos.user_id and photo_comments.user_id)
    • email
    • password
    • created_at
    • updated_at
  • user_profiles

    • id
    • user_id (One-to-One with users.id)
    • name
    • profile_photo
  • relationships

    • id
    • follower_id (One-to-One with users.id)
    • followed_id (One-to-One with users.id)
    • created_at
    • updated_at
  • photos

    • id (One-to-Many with photo_comments.user_id)
    • user_id (One-to-One with users.id)
    • location
    • description
    • created_at
    • updated_at
  • photo_comments

    • id
    • user_id (One-to-One with users.id)
    • photo_id (One-to-One with photos.id)
    • message
    • created_at
    • updated_at

Let’s go ahead and create these tables. For this project, I’ll be using MySQL; feel free to copy and paste these commands.

CREATE DATABASE `instapics`;
USE `instapics`;

CREATE TABLE `instapics`.`users` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `email` VARCHAR(100) NOT NULL,
  `password` VARCHAR(100) NOT NULL,
  `created_at` DATETIME NOT NULL,
  `updated_at` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `Index_email`(`email`)
)
ENGINE = InnoDB
CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `instapics`.`user_profiles` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` INTEGER UNSIGNED NOT NULL,
  `name` TEXT NOT NULL,
  `profile_photo` TEXT NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `Index_user_id`(`user_id`),
  CONSTRAINT `FK_user_profiles_user_id` FOREIGN KEY `FK_user_profiles_user_id` (`user_id`)
    REFERENCES `users` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
)
ENGINE = InnoDB
CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `instapics`.`relationships` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `follower_id` INTEGER UNSIGNED NOT NULL,
  `followed_id` INTEGER UNSIGNED NOT NULL,
  `created_at` DATETIME NOT NULL,
  `updated_at` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `Index_follower_id_followed_id`(`follower_id`, `followed_id`),
  CONSTRAINT `FK_relationships_follower_id` FOREIGN KEY `FK_relationships_follower_id` (`follower_id`)
    REFERENCES `users` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_relationships_followed_id` FOREIGN KEY `FK_relationships_followed_id` (`followed_id`)
    REFERENCES `users` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
)
ENGINE = InnoDB
CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `instapics`.`photos` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` INTEGER UNSIGNED NOT NULL,
  `location` TEXT NOT NULL,
  `description` TEXT NOT NULL,
  `created_at` DATETIME NOT NULL,
  `updated_at` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `FK_photos_user_id` FOREIGN KEY `FK_photos_user_id` (`user_id`)
    REFERENCES `users` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
)
ENGINE = InnoDB
CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `instapics`.`photo_comments` (
  `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_id` INTEGER UNSIGNED NOT NULL,
  `photo_id` INTEGER UNSIGNED NOT NULL,
  `message` TEXT NOT NULL,
  `created_at` DATETIME NOT NULL,
  `updated_at` DATETIME NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `FK_photo_comments_user_id` FOREIGN KEY `FK_photo_comments_user_id` (`user_id`)
    REFERENCES `users` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `FK_photo_comments_photo_id` FOREIGN KEY `FK_photo_comments_photo_id` (`photo_id`)
    REFERENCES `photos` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
)
ENGINE = InnoDB
CHARACTER SET utf8 COLLATE utf8_general_ci;

Alternatively, you could use migrations, but we’ll review those in a future lesson.


Step 2 – Setup Laravel’s Database Configuration

Before doing anything with Laravel models, we need to setup our Laravel installation’s database configuration. Open application/config/database.php, to find some of these settings:

  • profile – setting this to true will log all SQL querie times into the Laravel logs. Leave this as true for now.
  • fetch – the type of returned data from PDO. Default value is PDO::FETCH_CLASS and should be left like so.
  • default – this is the name of the connection settings used by the application. The name refers to the index in the $connections array just below
  • connections – an associative array of the possible connections for your application.

    • driver – the database server type. This can be pgsql, sqlite, mysql or sqlsrv
    • host – the host name of your database server
    • database – the database name
    • username – username to use on the database server
    • password – password to use on the database server
    • charset – charset to use on the database server
    • prefix – table prefix on the database, if any
  • redis – if you plan on using Laravel’s Redis library, you can set up the server information here.

For the purposes of this tutorial, we’ll be using MySQL. Your database.php file should look something like this (I removed the comments, but they should be fine to keep):

return array(
	'profile' => true,
	'fetch' => PDO::FETCH_CLASS,
	'default' => 'mysql',
	'connections' => array(
		'mysql' => array(
			'driver'   => 'mysql',
			'host'     => 'localhost',
			'database' => 'instapics',
			'username' => 'root',
			'password' => '(yourpassword)',
			'charset'  => 'utf8',
			'prefix'   => '',
		),
	),
	'redis' => array(
		'default' => array(
			'host'     => '127.0.0.1',
			'port'     => 6379,
			'database' => 0
		),
	)
);

Step 3 - Creating Your First Laravel Model

Begin by creating a Laravel model inside the application/models folder. Create user.php inside, and add the following code:

class User extends Eloquent {

}

Now, based on our review of what the User‘s relationships are, we need to code the relationship methods for all of them:

class User extends Eloquent {
    
    //setting $timestamp to true so Eloquent
    //will automatically set the created_at
    //and updated_at values
    public static $timestamps = true;
    
    public function user_profile()
    {
        return $this->has_one('User_Profile');
    }
    
    public function followers()
    {
        return $this->has_many_and_belongs_to('User', 'relationships', 'followed_id', 'follower_id');
    }
    
    public function following()
    {
        return $this->has_many_and_belongs_to('User', 'relationships', 'follower_id', 'followed_id');
    }
    
    public function photos()
    {
        return $this->has_many('Photo');
    }
    
    public function photo_comment()
    {
        return $this->has_many('Photo_Comment');
    }
}

Noticeably, we make use of some advanced Many-to-Many functionality here, due to the table structure of our follower model (i.e. the users table references the relationships table which references the users table again). The has_many_and_belongs_to function has the following method signature:

/**
 * Get the query for a many-to-many relationship.
 *
 * @param  string        $model
 * @param  string        $table
 * @param  string        $foreign
 * @param  string        $other
 * @return Relationship
*/
public function has_many_and_belongs_to($model, $table = null, $foreign = null, $other = null)

This actually lets us create a model that has a Many-to-Many relationship with itself (i.e. Users follow other Users). We use followers and following method names on the User model to enable us to get a User’s followers or get all the users that a single User is following, respectively.

Following the User model, create the other models. When you finish, you should have:

  • application/models/photo.php
  • application/models/photo_comment.php
  • application/models/relationship.php
  • application/models/user.php
  • application/models/user_profile.php

These files will be in the tutorial’s Git repository, so if you prefer to download them, you can find them here: https://github.com/nikkobautista/laravel-tutorial


Step 4 - Create the User Functions for Instapics

Let’s begin using our models by creating some of the user functions we’ll be needing in the application. First up: user registration. From the previous tutorial, we’ve already created a Registration/Login Form on the home page. Right now, it’s not doing anything, but let’s hook it up to a User controller, authenticate action. Create application/controllers/user.php with the following code:

class User_Controller extends Base_Controller
{    
    public function action_authenticate()
    {
        
    }
}

Open application/views/home/index.blade.php and look for the login form. Update the form on Line 18 to submit to the action_authenticate() method:

<form class="well" method="POST" action="user/authenticate">

Going back to the User_Controller, let’s place some code in action_authenticate():

class User_Controller extends Base_Controller
{    
    public function action_authenticate()
    {
        $email = Input::get('email');
        $password = Input::get('password');
        $new_user = Input::get('new_user', 'off');
        
        if( $new_user == 'on' ) {
            try {
                $user = new User();
                $user->email = $email;
                $user->password = Hash::make($password);
                $user->save();
                Auth::login($user);
            
                return Redirect::to('dashboard/index');
            }  catch( Exception $e ) {
                echo "Faield to create new user!";
            }
        } else {
            $credentials = array(
                'username' => $email,
                'password' => $password
            );
            if( Auth::attempt($credentials)) {
                return Redirect::to('dashboard/index');
            } else {
                echo "Failed to login!";
            }
        }
    }
}

Let’s break-down what we’ve done here so far:

  • We use the Input library to get the inputs from the submitted form
  • If the $new_user flag was checked, we create a new User, using the Hash library to generate an encrypted password.
  • Log in the new User with the Auth library
  • If the $new_user flag was unchecked, we create a $credentials array, and use it with the Auth library.
  • If Auth::attempt is true, it means the credentials were correct and we’re logged in
  • Else, it means the credentials were wrong.
  • In both scenarios, redirect to the Dashboard controller, index action when successful, and echo a failure message if not.

The Input library

The basic function of the Input library is to enable retrieval of form data. For example, in the User controller, we used Input::get('email'); to get the email value from the form. It’s important to note that the get method is used for all types of requests and not just the $_GET array.

You can read more about the Input library here: http://laravel.com/docs/input#input

The Auth library

Laravel comes with its own authentication mechanism, the Auth library. It can do the following features with regards to user authentication.

Creating a hashed password

We can make use of the Hash library like so:

$password = Hash::make($plaintext_password);

This method creates a salted and hashed password for a user, using the encryption key we set in the configuration file. To check if a hash is correct, you can use:

if( Hash::check($plaintext_password, $hashed_password) == true ) {
    echo 'Password is correct.';
}

Logging in a user

For this, we use the Auth library’s attempt method. Before that, though, we build a $credentials array, which is an associative array with a username and password indexes:

$credentials = array(
    'username' => 'yourname@youremail.com',
    'password' => 'yourpassword'
);
if( Auth::attempt($credentials) == true ) {
    echo 'User is logged in';
} else {
    echo 'Credentials failed';
}

It’s important to keep in mind that once an attempt is “successful”, the user is automatically logged in.

Loggin a user in/out

Sometimes, we’ll need to login a user without using the attempt method (such as when logging in a user from a link inside an email, or post-registration). We can do that with the Auth::login method:

Auth::login($user); //where $user is a User object
Auth::login(42); //where 42 is the User's ID

On the other hand, we also have an Auth::logout method for logging users out:

Auth::logout();

This will terminate the user’s session.

Retrieving the logged in user’s data

The Auth::user method allows us to retrieve the logged in user object, as well as any information attached to it:

$email = Auth::user()->email;
$created_at = Auth::user()->created_at;

Configuring the Auth library

The Auth library has to be configured before using it (though the defaults will work with most projects, like this one). The configuration variables are:

  • driver – this can be either eloquent or fluent. Developers can write their own drivers by extending the Driver class in laravel/auth/drivers.
  • username – this is the column name of whatever represents your user’s “username” in the database table.
  • model – when using Eloquent, this is the model class that the Auth library uses
  • table – when using the Fluent authentication driver, this determines the database table for the users in the application

Our project, Instapics, uses the default values in the auth.php configuration file, so we don’t need to change anything in it.

Going back to the project, try testing out the login/registration features of Instapics! Pretty nifty, huh? You’ll notice though that we don’t have anything in the Dashboard controller yet, so let’s work on that next.


Step 5 - Create the Instapics Dashboard

The first thing we need to do is create the Dashboard controller, with the index action. Create the file application/controllers/dashboard.php and put in the following code:

class Dashboard_Controller extends Base_Controller
{
    public function action_index()
    {
        $photos = Auth::user()->photos()->order_by('created_at', 'desc')->order_by('id', 'desc')->get();
        return View::make('dashboard.index', array('photos' => $photos));
    }
}

Now we need to create the Dashboard’s index page. Create application/views/dashboard/index.blade.php and append the following:

@layout('layouts/main')

@section('navigation')
@parent
<li><a href="user/logout">Logout</a></li>
@endsection

@section('content')
<div class="row">
    <div class="span3">
        <div class="well sidebar-nav">
            <ul class="nav nav-list">
                <li class="nav-header">Followers</li>
            </ul>
            <div style="margin-left: 10px">
                @forelse (Auth::user()->followers as $follower)
                    <div style="float: left; width: 30px; margin: 0px 3px 3px 5px;">
                        <img src="http://d2o0t5hpnwv4c1.cloudfront.net/2069_laravel_2/http://gravatar.com/avatar/{{ md5(strtolower(trim($follower->email))) }}?s=25&d=retro" alt="Follower" title="{{ $follower->email }}" />
                    </div>
                @empty
                    <div>You have no followers.</div>
                @endforelse
                <div style="clear: both"></div>
            </div>
            
            <ul class="nav nav-list">
                <li class="nav-header">Following</li>
            </ul>
            <div style="margin-left: 10px">
                @forelse (Auth::user()->following as $following)
                    <div style="float: left; width: 30px; margin: 0px 3px 3px 5px;">
                        <img src="http://d2o0t5hpnwv4c1.cloudfront.net/2069_laravel_2/http://gravatar.com/avatar/{{ md5(strtolower(trim($following->email))) }}?s=25&d=retro" alt="Following" title="{{ $following->email }}" />
                    </div>
                @empty
                    <div>You are not following anybody.</div>
                @endforelse
                <div style="clear: both"></div>
            </div>
        </div>
    </div>
    <div class="span9">
        <h1>Your Photos</h1>
        @forelse ($photos as $photo)
        <div class="well" style="text-align: center">
            <img src="http://d2o0t5hpnwv4c1.cloudfront.net/2069_laravel_2/{{ $photo->location }}" alt="{{ $photo->description }}" title="{{ $photo->description }}" />
            <p>{{ $photo->description }}</p>
        </div>
        @empty
        <div class="alert alert-info">
            <h4 class="alert-heading">Awww!</h4>
            <p>Seems like you don't have any photos yet. <a href="#">Upload a new one?</a></p>
        </div>
        @endforelse
    </div>
</div>
@endsection

Refresh the dashboard page, you should see this:

Instapics Dashboard

Looking a bit bare? Add this to the Dashboard controller, and run it by accessing dashboard/insert_test_data on your browser:

public function action_insert_test_data()
{
    $logged_in_user = Auth::user();
    
    for( $x = 0; $x < 10; $x++ ) {
        $email = rand().'@gmail.com';
        $user = new User();
        $user->email = $email;
        $user->password = Hash::make($email);
        $user->save();
        
        $logged_in_user->followers()->attach($user->id);
        if( $x > 5 ) {
            $logged_in_user->following()->attach($user->id);
        }
    }
    
    $photos = array(
        array(
            'user_id' => $logged_in_user->id,
            'location' => 'http://farm6.staticflickr.com/5044/5319042359_68fb1f91b4.jpg',
            'description' => 'Dusty Memories, The Girl in the Black Beret (http://www.flickr.com/photos/cloudy-day/)'
        ),
        array(
            'user_id' => $logged_in_user->id,
            'location' => 'http://farm3.staticflickr.com/2354/2180198946_a7889e3d5c.jpg',
            'description' => 'Rascals, Tannenberg (http://www.flickr.com/photos/tannenberg/)'
        ),
        array(
            'user_id' => $logged_in_user->id,
            'location' => 'http://farm7.staticflickr.com/6139/5922361568_85628771cd.jpg',
            'description' => 'Sunset, Funset, Nikko Bautista (http://www.flickr.com/photos/nikkobautista/)'
        )
    );
    $logged_in_user->photos()->save($photos);
}

When you refresh the page, you’ll see what it looks like with the sample data inserted:

Instapics Dashboard w/ Sample Data

Conclusion

In the second part of our Laravel series, we learned:

  • Some background on what “Models” are
  • What the Eloquent ORM is
  • How to set up Laravel’s database configuration
  • How to create your first Laravel Model
  • The basic functions of the Auth and Input libraries
  • Making use of the Eloquent ORM in a view

Eloquent really is an awesome ORM implementation – it’s fast and has tons of features that make database interactions in any application as simple as possible.

Next in our Web Applications from Scratch with Laravel series, we’ll learn more about using Laravel’s filters, Laravel’s Validation library, and how to work with files in Laravel!

What do you think about Laravel’s Eloquent ORM? Is it something that you find useful? Let me know in the comments! And, if you’re a Tuts+ Premium member, stay tuned for our upcoming Laravel Essentials course!

Tags: laravel
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Randall

    Thank you for adding more Laravel content. I have learned so much about codeigniter from Netuts and am looking forward to learning more about this awesome framework!

    • http://www.jeffrey-way.com Jeffrey Way

      Thanks, Randall!

      • Kevin

        Today, who is better? Laravel or Codeigniter?

      • Alex

        Laravel. CodeIgniter isn’t being updated. Phil actually wrote an article on it. If you like CodeIgniter I suggest checking out FuelPHP which has made significant strides similar to Laravel and is the evolution of CodeIgniter.

      • http://philsturgeon.co.uk Phil Sturgeon

        They are different. I love Eloquent, can’t wait to use it in my CodeIgniter applications.

    • http://nikkobautista.com Nikko Bautista
      Author

      Wait for our Premium course! You’ll love it :)

      • Adil

        Hey Nikko,

        Any idea regarding the release date of the Premium course? A guesstimated date would also work for me :)

        Thanks

  • Niall O’Brien

    Nice tutorial, how many tutorials in total can we expect?

  • http://samuel.blog.br Samuel Mesquita

    is very nice to see nettus creating content on laravel, this will make the community grow and consequently improve the framework :D.

    Congratulations Nettus+

  • http://gabrielmolter.com.br Gabriel Molter

    I think i will use it.

  • Juan

    Can you tell us more about how so encrypt the data isntead save it using plain text?

    I really like Laravel, as a developer I use Codeigntier and Symphony because they hace a strong company behind them and they won’t vanish some day, Who’s behind Laravel?

    • Daniel Petrie

      UserScape is behind Laravel

    • Pedro Borges

      UserScape is behind Laravel, but not from it’s beginning. Read more about how that happened at ianlandsman.com/2012/02/22/laravel.

    • Jesus Bejarano

      Let me tell you a history, is about when Codeigniter was a very young , people start looking at it and then its became very popular around the web development world, companies from all the world start to adopting it and its popularity raise, raise and raise. Is this history familiar to you sir?.

    • http://nikkobautista.com Nikko Bautista
      Author

      I mentioned in the tutorial the Hash library – you can use that :)

      $hashed_string = Hash::make($unhashed_string);

      • cahva

        Hashed passwords? Nah, its not necessary ;-) (sorry, I just had to)

      • http://my.crynobone.com crynobone

        @cahva I see what you did there. (sorry, I just had to)

  • Amit Erandole

    Looking forward to that premium course @jeff_way. I hope you make this one into a comprehensive series that covers working with javascript frameworks like backbone.js

  • Hannes

    I love this series =D

  • samir

    it’s all about oop and mvc?!!?
    i hope that we will see a tutorial wich explain these thinks?
    thank you

    • Tom

      There have been 200,000 tutorials which explain these things all over the internet for 20 years. Look around for them.

  • Shane Osbourne

    Thanks for the great tutorial.

    I’ve picked Laravel for a new project after hearing Jeffrey Way’s praise for the framework & now your tutorials are helping me understand it faster than I could figure it out on my own.

    Great work guys.

    Shane.

  • http://www.infinityfish.com/ eric mabo

    Thanks for this tutorial series. Laravel is great. I started using Codeigniter a few months ago, after working with Symfony2. I must say that I am very impressed with this framework. Documentation is great. I think tutorials like this one will only make Laravel much more popular.
    I hope you will use Controllers for routing. This is easier especially for folks from the codeigniter world.

    • Kapil Verma

      You can easily use controllers for routing .. but having named routes is always so much better .. check those out

  • http://netsquare.nl Lars

    Verry nice! I hope you guys will 1 day start a series on the Yii framework tho.

    • http://okeowoaderemi.com Okeowo Aderemi

      Word because Yii is pretty much very easy to grasp, and also Gii is another cool aspects when it comes to scaffolding.

  • http://www.thibz.com ThibZ

    Finally a tribute to this awesome framework =)

  • http://inkwell.dotink.org Matthew J. Sahagian

    Hello all, back again with more criticism! I’ll keep these ones short.

    Firstly, I’m not a huge fan of frameworks deciding a lot about my schema. I’m ok with naming conventions so long as their sane and use best cross-database practices (which laravel seems OK on). But what’s this little gem?

    //setting $timestamp to true so Eloquent
    //will automatically set the created_at
    //and updated_at values

    Wouldn’t it be better to have something like $created_at_column and $updated_at_column so we could determine our own column names for these?

    Now for the actual ORM stuff. I much prefer accessor methods over magic properties. This is for two reasons really, although it’s not impossible to create some hooks or callbacks when certain columns are retrieved, it’s a lot easier to overload an accessor method for specific behaviour if one needs to. It also keeps that particular code relevant.

    I am, of course, making an assumption here that laravel is using __get() in order to make $record->id for example map to the internal result. Not that I would overload getting the ID, but let’s say I had something else that I *did* want to overload. For example, perhaps to save some space I store only a relative path to an image or something, but I want the $record->path to return the full path so that other systems using that model don’t have to account for getting the images root directory and concatenating them to… in order to do this with standard __get() logic I’d have to overload __get() check the property name, call the parent if the property is not ‘path’ and add my custom logic if it *is* path. If I have 10 overrides now I have 10 if statements going on in my __get() even if all they do is return the value of a more isolated method.

    This can easily be avoided by using an accessor like ->getPath(). Rather than overloading __get() with a bunch of if ($property == ‘whatever”) { return $this->getPath(); } to run that logic, I can just overload getPath() directly. In short, the data itself should be private… there should be a protected method allowing you to get the private data from within that class or descendents, and there should be a public method allowing the outside world to interface with it.

    Now a question which I could not get answered in the IRC channel last night.

    Laravel has the basics of ORM down, specifically active records, record sets, and their relationships. Does it do any additional ORM mapping like creating date objects for date fields or anything similar? I’ve been spoiled by Flourish in this regard where getting a date affords me a nice fDate() object…. if this is not the case, how easy would it be, for example, to get created_at back as a PHP DateTime object or, if Laravel has one, one of it’s Date objects?

    Or do I have to return to this?

    public function __get($property)
    {
    if ($property == ‘created_at’) { return new DateTime(parent::__get($property)); }
    else { return parent::__get($property); }
    }

    ** Code is formatted because I’m too lazy to encode it and put it in proper tags.

    • Kapil Verma

      Umm … the constructor?? … every orm object, is in the end constructed from the retrieved rows, it’d be pretty easy to do any modifications there … and you can override the save function to do any manipulations before saving … so there you go .. some reading of code will tell you that every attribute is stored in $this->attributes array and all relationships are stored in $this->relationships array … the more i learn about eloquent .. the more awesome i find it .. i mean how well you can do oop with this orm is just fkin amazing(extend and add/override relations, change table names and what damn not) … i find ruby activerecord bloat/inelegant/overkill after working with eloquent .. oh and have you looked at the awesome eager loading?? conditions inside eager loading and on the main model too … not a bad word about eloquent please, i’m in fkin love with it

      • http://inkwell.dotink.org Matthew J. Sahagian

        So if I construct new User, then to $user->avatar_path = then do $avatar = $user->avatar_path how would the constructor be able to handle that transformation? Using separate accesor methods would allow me to use setAvatarPath() which could determine if the string begins with the root directory, and remove it before actually setting it in the database, then getAvatarPath() would re-append it. This is transparent in all circumstance, not only in circumstances where I first store the object and then reload. Furthermore, even if I save the object, presumably it is still the same constructed object which is assigned to my variable, so the constructor is never re-run.

        The example I gave specifically saves *less* information. I only want the information appended when I get it, i.e. when it comes out of the database, not when it goes in.

        I’m not impressed with how fkin amazed you are with it. As mentioned in my previous post, ORM done correctly (at least for ActiveRecord pattern) is Flourish (which is why I use it). I’m not overly familiar with Ruby’s implementation so I’ll refraint from commenting on that.

        Can you address the concern above or just tell me how fkin awesome it is?

    • Kapil Verma

      On further reading of eloquent’s ‘oh so well written’ code, you can find out that attributes are actually get and set using get_attribute and set_attribute methods .. so .. there you go !!! job is even much easier for you (by the way .. you won’t ever need 10 if-else, there’s switch in php , equivalent in amount of code to the 10 getters you might have defined if there’d have been getters in eloquent)

      • http://inkwell.dotink.org Matthew J. Sahagian

        Whether you’re using if/else or switch is not the issue here. I still need to overload __get() or __set() and call get_attribute or set_attribute depending on what the column is. Which means the custom logic required in order to transform these values as they are pushed and pulled spans 2 methods and is clean(er)… or spans 1 method and is not cleanly isolated at all. That’s a poor dichotomy to face.

    • Kapil Verma

      Well, now i am having a oh my fkin goodness moment … suppose you have an attribute called ‘weird_string’ in your model … you can define a function get_weird_string() and that specific function would be used to get the value of ‘weird_string’ attribute!!! awesome, ain’t it :D …same with the setter

    • Kapil Verma

      Oh no you don’t have to overload __get() or __set(), they do the overloading job for you .. admit it eloquent is fkin awesome :P

      • http://inkwell.dotink.org Matthew J. Sahagian

        So what you’re saying is __get() and __set() already look for get_ and set_ methods and call that if they exist? So there I can do either of the following with no modification?

        $path = $user->get_avatar_path();
        $path = $user->avatar_path;

        And they will be exactly the same *unless* I overload get_avatar_path()?

      • Kapil Verma

        yup you got that right ;)

      • Jesus Bejarano

        I hope that you are happy, you just left a magician without a job :(

    • Jesus Bejarano

      A framework with magic ? ahaha , the only diference between a magician and a”magic” framework like RoR or Laravel, is that the magician will never reveal his secrets , but the framework leave their secrets to the naked eye in their source code.

      • Kapil Verma

        php magic-methods != magic in a framework … actually i dont think you can do magic in php.. you can either write clever php or write java in php .. laravel is clever php

    • http://nikkobautista.com Nikko Bautista
      Author

      Hey Matthew

      I’m always glad when you comment cause you bring a whole lot of knowledge with your arguments, not like other people who just bash on the framework without anything to provide :)

      Anyway, with regards to this, I hope I can give you a few answers:

      “Wouldn’t it be better to have something like $created_at_column and $updated_at_column so we could determine our own column names for these?”

      I agree, the created_at and updated_at convention might not be the same for some people (I personally used to use date_created and date_updated), but looking through the code, it wouldn’t be that hard to implement your suggestion and ask for a pull-request on that. I might take this on later.

      With regards to your qualms about the model accessor methods – you can still create your own methods inside the model. If you wanted to get the full path of an object, you can do something like:

      public function getFormattedPath($format = ‘full’) {
      $saved_path = $this->path;
      switch($format) {
      ..do whatever to $saved_path
      }
      return $saved_path;
      }

      This will encapsulate that whole functionality into one method, as opposed to lopping it in with the get method Eloquent uses. Which personally I find better since you won’t get confused – $object->path will always return the saved path, but for viewing/other purposes, you can go $object->getFormattedPath() and get what you want.

    • Oscar B.

      Hi. I’m interested in what you are saying about the lack of accessors. Have you tried Symfony2 (+bundles) + Doctrine2? If yes, what is your opinion?

      Regards.

      • http://inkwell.dotink.org Matthew J. Sahagian

        Oscar, I have gone ahead and better collection my thoughts in a blog post on a new (and hopefully ongoing) blog. It should clarify what I think is confusing in these comments based on the speed in which we were responding to one another, etc.

        I have not tried Symfony 2. Most frameworks lose my interest much earlier than Laravel has, so usually I don’t dig too deep. Laravel has some fundamentals right, in my opinion, and it has endeared me to research it more and provide the most constructive criticism I can.

        You can view the post here:

        http://scriptogr.am/mattsah/post/accessor-methods-not-just-personal-preference

        With regards to Doctrine2. I have not looked at that, but my understanding is that Doctrine2 is more data mapper than active record pattern… so hypothetically it should not suffer from these issues as easily.

  • http://inkwell.dotink.org Matthew J. Sahagian

    Ok, so now I am forced to create my accessor methods for those properties which I have to transform, while other properties which I don’t care to transform either require me to create useless accessor methods for consistency…

    Inconsistent:

    $user->get_avatar_path(); // gets the canonical avatar path
    $user->id; // gets the id

    Or I’m forced to overload __call() and do something the like the following:

    $method_parts = explode($method, 2);

    if ($method_parts[0] == ‘get’) {
    return $this->get_attribute($method_parts[1]);
    }

    When “eloquent” could have done this to begin with and saved me the time. Furthermore, now to be *truly* consistent I have to do this across every model.

    • Kapil Verma

      No you are not forced to override __call also … done for you already inside eloquent .. and its not inconsistent in any way .. you need custom setters/getters only for edge cases, so not inconsistent in any way i’d say

      • http://inkwell.dotink.org Matthew J. Sahagian

        So now in my project documentation I have to say the following?

        To get the id you just need to do $model->id…. but some properties have custom overrides, so you need to do $model->get_…

        That seems the very definition of inconsistent to me. If __call() is already set up so that I can *always* call ->get_ and ->set_ then fine… but why even offer the -> accessor then?

    • Kapil Verma

      read the code man .. there’s some clever stuff in it . you really don’t need to do all that you are saying … just defining get_weird_string() and set_weird_string($val) does the job

      • Kapil Verma

        After defining those methods you can just do a $model->weird_string and get the return value of getter and when you do $model->weird_string = $val; the setter would be used

      • http://inkwell.dotink.org Matthew J. Sahagian

        Ahh yes, now I have to read the code of the framework in order to understand how to fully use it. Thanks.

      • Kapil Verma

        Well, if reading code makes you a better dev, then why not !! .. (also, if you are so picky about reading some amount of simple, well written code, i’ll just add it to the docs tonight (open source, you see))

      • http://inkwell.dotink.org Matthew J. Sahagian

        I highly doubt reading Laravel’s code would make me a better dev. That being said, I have no doubt it’s fkin awesome.

    • http://nikkobautista.com Nikko Bautista
      Author

      If you didn’t create your own accessor methods, you’ll have to create the functionality in the pre-made accessor method anyway, so I don’t see why you’re complaining about writing that code – is it because the accessor methods aren’t pre-made for you?

      With other properties, why would you feel compelled to create useless accessor methods? I don’t see the point there, that’s just wasted code. If you don’t need it, then don’t code it in. If you need it, then make a custom accessor method.

      While Laravel itself doesn’t have a scaffolding tool built-in, there is a scaffolding tool called Bob the Builder (http://bundles.laravel.com/bundle/bob) which can automate model generation for Eloquent. I’m pretty sure accessor methods can easily be added into this if it’s really a big issue, but so far not a lot of people have complained about it yet.

      • http://inkwell.dotink.org Matthew J. Sahagian

        No, I wouldn’t expect the accessor methods to be premade. I’d expect them to use __call().

        Again, the first issue is inconsitency in the model. What you seem to be saying is use $model->property to get properties that don’t need special functionality, and use $model->accessor_method_for_property() to get properties that do need special functionality. My point above on this was that it’s inconsistent, particularly since Laravel will not prevent one or the other. Let’s say I create a bundle whereby 2 out of 10 properties (not to mention properties on every other model) have some custom logic. I have, at least in the context of my model, several options, none of which are very ideal.

        Option 1:

        I can spend the time to document the inconsistency. Saying for x, y, z property you can use the standard $model->property method to get the property, but for properties a and b you need to use $model->get_a() and $model->get_b() respectively.

        Option 2:

        I can create accessor methods for all properties (even if they don’t require any sort of custom logic when retrieving or setting), then my documentation becomes much simpler and all I need to do is say, “When using $model of type ‘Model’ use the get_() and set_() methods” instead of the standard and more familiar $model->property.

        Option 3:

        I can being modifying the magic methods to handle this much more automatically.

        The definition of “useless” here is obviously subjective. For me accessor methods via __call() and preventing access via __get and __set is not useless. It creates a consistent, easily overloaded, and easily documented pattern for getting and setting all properties.

        Kapil above seems to state that Laravel can use either out of the box, i.e. I can do $model->id to get the ID or $model->get_id() without any modification. If this is true then the inherent problem of how easy it is to overload them goes away, however the concerns about inconsistency and or confusing / unnecessarily verbose documentation does not. If this is true, my suggestion would be to make ->get_id() the way which is promoted in Laravel’s documentation, and to inevitably explicitly remove for ->id type access.

      • http://nikkobautista.com Nikko Bautista
        Author

        This seems to be boiling down to a matter of preference rather than standard. Personally, I don’t think there’s an inconsistency here. The Eloquent ORM’s $model->property is to be used for getting the saved data from the database, and using any other method to get a certain property would be for implementing custom logic to it. The documentation explains this functionality (getting data via $model->property) quite well, and usually it’s most people would need. The ability to add custom logic to this can be done in many different ways that for it’s trivial for any good programmer. I don’t see why it’s a flaw that it’s not touted as the way to do it.

        I would agree though, that the documentation can be updated to explain how to customize models for custom logic that needs to be implemented on certain properties. Other than that, the default functionality is fine IMO.

      • http://nikkobautista.com Nikko Bautista
        Author

        There’s actually something in the documentation that explains this:

        http://laravel.com/docs/database/eloquent#getter-and-setter-methods

      • http://inkwell.dotink.org Matthew J. Sahagian

        @Nikko

        I think calling it personal preference is a bit of an oversight on the implications of an ORM and for that matter a Model. The implication of what you’re saying seems to be really reducing models to little more than a database abstraction layer. While that may be a component of ORMs and ActiveRecord in particular, it is not the only component.

        One could argue that “getting the data” is all one ever *needs*. But that’s not the sole point of an ORM, the point is getting that data in an object oriented manner. Dates are a perfect example of this, whereby accessing the data as it is saved in the database, essentially results in a string representation of the date. This is true of every database and database driver I know for PHP… it is certainly what I expect of even a very fluid database abstraction layer, but that’s not really what I expect of an ORM, and certainly not what I expect of the model.

        Not only is the ability to add logic around setting and getting data a prominent and important feature of a robust and useful ORM, but the existence of logic around setting and getting data is essentially the entire point of an ORM vs. what is simply a nice abstraction layer.

        Your next major point seems to be that this is trivial for any good programmer. This may be true, however, it’s not so well in my book. The point of a framework can very much differ for developers of different levels. For good developers, frameworks generally represent a means to no longer be bothered by the trivial and mundane tasks. For poor developers, they often represent a means to make things which might seem trivial to good developers, trivial to them as well. By simply saying “this is trivial to do if you want to do it and if you’re a good programmer” you seem to be defeating both of these.

        Consistency is key to making things accessible, clearly documented, and flexible. One of the major arguments against ActiveRecord is the fact that the pattern itself is somewhat antithetical to what a model is supposed to be. This article, I hope, is not the full depth of Eloquent (and I wouldn’t expect it to be)… if it is there are even bigger issues in my mind. But that being said, having an ActiveRecord pattern that seems to willingly support that antithesis is worrisome. Transforming relational data and data structures to objects and object relationships is the requisite point of an ORM, the fact that “not a lot of people have complained about it” is not a reflection of the fkin awesomness of Eloquent (to paraphrase Kapil), it’s not likely a reflection of Eloquent at all, but more than likely a reflection of the user base and the position that Laravel is in. Being overly defensive (and I’m not saying you are, but Kapil certainly seems to be) in the face of such criticisms will not push Laravel forward into new positions and larger user bases, but quite the contrary, will likely keep it where it is.

  • Max

    Correct me if I’m wrong, but I don’t remember adding the form to the views/home/index blade in Part 1.

    • http://nikkobautista.com Nikko Bautista
      Author

      Sorry about that – I think the HTML example I had on part 1 wasn’t updated with the correct HTML. Just do a git-pull on the repository to get the latest code and copy-paste from there :)

      I’ll see if I can get the code in Part 1 updated.

      Sorry!

  • http://ginius.nl Gijs

    Damn! This framework is strong!

    Nice tutorial and thanks for explaining it.

  • http://l33.me Lee Graham

    Great tut! In one of your future posts in this mini-series you should include: https://github.com/benedmunds/Laravel-MongoDB

  • Matthew’s Friend

    Matthew, you need a friend dude. Come over, I’ll give you a hug and make all your anger and frustrations disappear. Just chill dude.

  • http://ktee8.com/ Ktee8

    Thank you so much for sharing this. Very interesting framework and I finished the first part of the first lesson of this series; but it’s still confusing and hard for an amateur like me.

    I should wait for the premium course, that might be video tutorial and exciting!!

    • http://nikkobautista.com Nikko Bautista
      Author

      Can you let me know what you find hard about it? I’d like to know in which areas I can make the tutorials more beginner-friendly :)

      Thanks!

      • http://ktee8.com/ Ktee8

        No, it’s not on your side. I’m just new to the world of PHP and still at the level where I don’t even know what I don’t understand:)

        I just wanted to say I like this topic and video tutorials must be better easy to understand for me.

        Still I will keep on trying this series and let you know if I notice something.

        Thank you so much for your caring and kindness.

  • tony yip

    I really like this framework however i still not able to use it for my project until the framework can supports firebird database. Anyone know how to make it work with firebird database (i have to use firebird database due to legacy system)?

    Thanks for your tutorial, great work.

    • http://nikkobautista.com Nikko Bautista
      Author

      You’ll have to create a driver for it. It’s a bit complicated – I suggest you create a forum post on their forums or join the IRC channel to get more help on how to do this.

  • Chris

    I tried the tutorial and followed it word for word and got the error :

    Fatal error: Call to a member function photos() on a non-object in /####/application/controllers/dashboard.php on line 6

    I then downloaded the code from git and got the same error i double checked everything and can’t figure it out

    • http://nikkobautista.com Nikko Bautista
      Author

      Hi Chris,

      That means you’re not yet logged in.

      Go to the home page (/home) and login first.

      • Chris

        I got it i assumed when you registered you were automatically logged in but yeh when i tried logging in with the account after registering it worked

      • chuck

        yes but in User_Controller why do you send the user to dashboard/index when you create a new user?

        15 Auth::login($user);
        16
        17 return Redirect::to(‘dashboard/index’);

        The ERROR that Chris (and everyone else who does the tutorial) gets comes because when the controller redirects to dashboard/index, somehow the user is logged out even with Auth::login($user) on line 16 before the redirect?

        I can’t figure it out?

        should it redirect to the home/index? is something wrong with Auth::login($user)?

      • Rich Lovelock

        I don’t think this is a logged in issue, I have something similar. It appear to be with using Auth::user()->photos() rather than User::find($user_id)->photos();

        I’m getting the following error after:
        Unhandled Exception
        Message:

        Undefined property: stdClass::$followers and again I think it’s because the code in the view is doing Auth::user()->followers not User::find($user_id)->photos. The Auth method doesn’t seem to return the same user object as User->find() does.

      • Rich Lovelock

        Yes, Auth::user() just returns a stdclass from which you can grab the properties from the user table, not a user object

  • christian

    really.. has_(many)_and_belongs_to_(many) sounds awfully familiar..

    by “eloquent”, are you referring to an eloquent copy of ActiveRecord::Base?

    • http://www.jeffrey-way.com Jeffrey Way

      Even if that’s the case, I’m okay with it!

    • Kapil Verma

      Dunno if its just me .. but i find ruby-activerecord (very) bloat when compared to Eloquent .. i think thats a syndrome of being part of rails .. everything rails related tries to do too much for you .. Eloquent, for me hits a sweet spot

      • Christian

        Dunno if its just me.. but I am getting awfully tired of every tom, dick and taylor in the php community creating a framework; especially when copying from already eloquent solutions and then literally naming them “Eloquent”.

        Seriously, there must be hundreds php-based frameworks now, and as we (as a community) further fracture ourselves, the RoR, Django, Sinatras of the world reap the benefits of a focused, centralized effort.

        Btw, all of the big “framework players”, are as, or far more bloated than rails.

  • http://- GD

    Fatal error: Call to a member function photos() on a non-object in C:\wamp\www\instapics\application\controllers\dashboard.php on line 7

    Also I am not sure that I understand your very last line that creates this error.

    photos = Auth::user()->photos()->order_by(‘created_at’, ‘desc’)->order_by(‘id’, ‘desc’)->get();

  • http://- lollypopgr

    The dashboard template is not as the screen shot. You have to remove code in order for this to work. Please check the blade file.

  • Dave

    I think you have a issue in your code setup

    In the tut
    <pre name=”code” class=”php”>
    // application/models/user_profile.php

    class User_Profile extends Eloquent {
    public function user()
    {
    return $this->belongs_to(‘User’);
    }
    }
    </pre>

    In the repo
    <pre name=”code” class=”php”>
    // application/models/user_profile.php

    class User_Profile extends Eloquent {

    public function user()
    {
    return $this->has_one(‘User’);
    }

    }
    </pre>

    Either way calling
    <pre name=”code” class=”php”>
    // application/routes.php
    Route::get(‘userprofile’, function()
    {
    echo ‘<pre>’;

    $user = User::find(1);
    $user_profile = $user->user_profile;
    print_r($user_profile);

    echo ‘</pre>’;
    });
    </pre>
    Creates a fatal error: Class ‘User_Profile’ not found

    It seems the underscore in the class name is the issue

  • fransdihan

    OK this is looking awesome, but what about performance? ORM in Java and .NET has a lot of compiling and cache to compensate performance.

  • http://clouddueling.com Michael Calkins

    I’m doing a ton of work with many to many relationships ty so much!
    Please more Eloquent examples or lessons. This is the kind of thing that makes me want to go premium ;D

  • J

    I’m awfully confused as to why this tutorial has us use sql commands instead of the options available in Laravel, considering that’s an essential point of the framework.

    • http://nikkobautista.com Nikko Bautista
      Author

      I’ll be covering Migrations and the Schema library in a future tutorial :) Better to teach these things incrementally then to add a lot in a single tutorial.

  • l

    application/models/user_profile.php

    or

    application/models/userprofile.php /on github/

    ?

    • erat

      …and ‘Class User_Controller’ instead of ‘Class User’…

      Please, NetTuts, review the steps in your tutorials and make them consistent across the board. Losing consistency is bad no matter where it happens, but in Part 2? We’ve barely started and the tutorial already has issues.

      I appreciate the offering, but this is just sloppy. You’re in the business of offering tutorials. It’s what you’re supposed to be good at. I can’t imagine paying for a premium membership if this is the level of attention the tutorials get.

      Please, fix the inconsistencies or take down the tutorial.

      • Drake

        If you want to learn to code, you should be able to find such mistakes yourself, so fix them yourself and be happy someone makes some awesome tutorials completely free.

  • Suman Ghosh

    Hi there. I have been following the tutorial and now i am facing a problem.
    when registering a new user, it saves the data in the database and tries to login and redirects me to dashboard controller’s index method. but it shows me that…

    Object of class User could not be converted to string”

    now when i go back to the home index and login again with the provided credentials, it works fine.
    in the code after registering you try to login the user with the data but i am not sure if it does.

    i tried to check if the user is logged in in dashboard/index method but it again gives me the same error. the error is gone after going back to home/index and loggin in explicitly.

    please help me up with a fix.

  • Gavin

    I’m getting the following error-

    Unhandled Exception

    Message:

    syntax error, unexpected T_ENDFOREACH
    Location:

    C:\xxx\xxx\xxx\xampp\htdocs\laravel\laravel\view.php(359) : eval()’d code on line 19

  • reineskye25

    Hi. is it best practice to put eloquent orm calls in the controllers? or should I put in the controllers.

    Like:

    User::order_by(‘name’)->get()

  • Mohamed Cherif BOUCHELAGHEM

    It seems uses a lot of singletones!! What about performane? is it better and faster than Yii?

  • http://miguelcosta.nanet.pt Miguel Costa

    Hello Nikko,
    first off all nice work :D I’m loving your tuts ;)

    I have spotted a small error in this tut:

    “Easy Inserts & Updates”

    $user = new User();
    //or get an existing user
    $user = User::get($user_id);

    were you used User::get() it should be User::find($user_id). Get will get you a column… SELECT `[$user_id]` FROM (…)

    cheers

  • mahami

    great tutorial, thanks.

  • john

    good tutorial Nikko

  • Andy

    It’s a very great tutorial. Thanks Nikko. While I am learning this tutorial, I have a problem. My logout link is http://localhost/laravel/public/dashboard/user/logout instead of http://localhost/laravel/public/user/logout Any suggestion to fix it? Thank you very much.

  • fortran

    Hi I have the following problem: a table “Users” with the following field: id;firstname;secondname;city;date; and I want to select only id;irstname and secondname the fields with this cod: Users::find(1) how to do it

    • Gabriel Vítor

      You can do this: Users::find(1)->get(array(‘firstname’,'secondname’));

  • Poul

    Think i missed something, i can’t seem to find the section where we created the view for the login/registration part. Any pointers ?

    • erat

      You’ll have to snag the form code from views/home/index.blade.php in the Github repo for the tutorial.

  • Jay Sol

    Greattttt tutorial,, thanku so much :)

  • jbitautas

    I’ve pretty much worked through every single available tutorial on this site (and others) and have read ‘Laravel Starter’ and currently starting on ‘Code Happy’.

    In my opinion, this is one of the more confusing Laravel tutorials on the Envato sites. The author mixes example code unrelated to the Instapics application to explain concepts, but then abruptly jumps back into the Instapics application and kind of zooms through aspects of creating the Instapics site. As I step through it, I get confused what is being taught as a sidenote and what is necessary to complete the tutorial.

    He also goes against some of the conventions and best practices of Laravel taught across the Tuts site such as using migrations, and using the Form class instead of vanilla HTML to create forms.

    One part where I thought it would have been extremely valuable for the author to get deeper into was using foreign keys in the database. I haven’t seen foreign keys used in any Laravel tutorials that I’ve found, but instead of using migrations he uses SQL. That’s okay, because I figured it out myself using the Laravel documentation, but I think this would have been very confusing for a beginner and worth going into.

    No disrespect, just an opinion I thought I’d share. I’m curious if anyone else felt the same?

    • The Awesome Coder

      Yes u are absolutely rit . I felt the same way

  • Dissappointed

    Multiple errors in the tutorial, reported 7 months ago and still not fixed? Is this what we should expect from NetTuts?

  • Holoverse

    I try and try this tutorial over and over again but can not figure it out.

    I always get…Call to a member function photos() on a non-object

    Everytime no matter what I do…
    wether its Auth::user()->photos()
    or User::find($id)->photos()

    Ive downloaded your code 4 times now, still cant get it to work.
    It works once, but if I logout and log back in, it stops.
    Or if I sign a new user up, who won’t have any phtoos to start with, it doesnt work.

    What the hell am I doing wrong!