# Eloquent models (part 1)

  • In a previous section, we created model classes for all the database tables
    • All models can be found in the app/Models folder
    • The Eloquent (opens new window) ORM (Object-Relational Mapping) included with Laravel provides a beautiful, simple ActiveRecord (opens new window) implementation for working with your database
      • Each database table has a corresponding model which is used to interact with that table
      • In fact, the model represents a single row in the table
      • Models allow you to:
        • query for data in your tables, as well as insert, update or delete a specific table row
        • protect attributes from mass assignment
        • add relationships between tables
        • transform Eloquent attribute values when you retrieve or set them on model instances (accessors, mutators, attribute casting, ...)
        • add additional attributes that do not have a corresponding column in your database
        • apply scoped filtering
        • prevent attributes to be visible
        • ...

REMARKS

  • In this chapter, we only discuss mass assignment and relations
  • The other methods will be implemented later in part 2

# Model blueprint

  • We have created a little blueprint with the most used (not all) public and private methods for a models
  • Open the model classes inside the App/Models/ folder and:
    • Line 5: add a reference the Illuminate Attribute class
    • Line 13-54 add the blueprint INSIDE the class

# Prevent mass assignable vulnerability

  • Mass assignment vulnerability means that users can modify data items that the user should not be allowed to
    e.g. access passwords, grant permissions, add administrator status to himself, ...
  • Mass assignment means that you're assigning multiple values to attributes in a single operation (insert or update a record)
  • Laravel has 2 protected methods to protect against Mass assignment vulnerability:
    • protected $fillable = []: array of attributes that are mass assignable
    • protected $guarded = []: array of attributes that are NOT mass assignable
  • Use only one of them, not both!

# Add relationships

  • The relations between the primary keys and foreign keys are already defined in MySQL (through the code in the corresponding migrations)
  • It's also necessary to define those relations in the Eloquent models (opens new window)
  • The database of our application only contains one-to-many and many-to-one relations

SUMMARY FOR OUR DATABASE TABLES

Summary models

# Genre 1 <-> ∞ Record

  • If we consider this relation as a one-to-many (1 -> ∞) relationship, we can say that "a genre has many records"
    • In Eloquent, we define this relationship by applying the hasMany() method on our Genre model, with the Record class ('Record::class') as parameter
    • Eloquent will automatically determine the proper foreign key column in the Record model, i.e. genre_id (the name of the owning model, suffixed with _id)
    • The former code should be wrapped in a method records(), which shall be used later on to query all the records of a specific genre









 
 
 
 


// app/Models/Genre.php
class Genre extends Model
{
    use HasFactory;
    
    /** The attributes that are mass assignable ...*/
    protected $guarded = ['id', 'created_at', 'updated_at']

    /** Relationship between models ...*/
    public function records()
    {
        return $this->hasMany(Record::class);   // a genre has many records
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

NAMING CONVENTIONS hasMany()

The relationship method should be named according to the used model (with lower case), and plural case
Full method: hasMany('model', 'foreign_key', 'primary_key')

  • The first parameter is the model to refer to (Record::class)
  • You may omit the third parameter if the primary key of the referred model (Record) is named id
  • You may omit the second parameter if the foreign key of the owning model (Genre) is the the "snake_case" name of the owning model, suffixed with _id
/** Relationship between models ...*/
public function records()
{
    // long version
    return $this->hasMany(Record::class, 'genre_id', 'id'); 
    // short version
    return $this->hasMany(Record::class); 
}
1
2
3
4
5
6
7
8

More info: One To Many (opens new window)

  • Inversely, we can look at the same relation as a many-to-one (∞ -> 1) relationship: "a record belongs to a genre"
    • In Eloquent, we define this relationship by applying the belongsTo() method on our Record model, with the Genre model ('Genre::class') as parameter
    • Eloquent will try to match the genre_id from the Record model to an id in the Genre model
      • The withDefault() method returns an empty Genre model (instead of null) if the genre_id does not match an id in the Genre model, which results in less conditional checks (and is often referred to as the Null object pattern (opens new window))
    • The former code should be wrapped in a method genre(), which shall be used later on to query the genre of a specific record









 
 
 
 


// app/Models/Record.php
class Record extends Model
{
    use HasFactory;
    
    /** The attributes that are mass assignable ...*/
    protected $guarded = ['id', 'created_at', 'updated_at']

    /** Relationship between models ...*/
    public function genre()
    {
        return $this->belongsTo(Genre::class)->withDefault();  // a record belongs to a genre
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

NAMING CONVENTIONS belongsTo()

The relationship method should be named according to the used model (with lower case), and singular case
Full method: belongsTo('model', 'foreign_key', 'primary_key')

  • The first parameter is the model to refer to (Genre::class)
  • You may omit the third parameter if the primary key of the referred model (Genre) is named id
  • You may omit the second parameter if the foreign key of the owning model (Record) is named the name of the relationship method, suffixed with _id
/** Relationship between models ...*/
public function genre()
{
    // long version
    return $this->belongsTo(Genre::class, 'genre_id', 'id')->withDefault();
    // short version
    return $this->belongsTo(Genre::class)->withDefault();
}
1
2
3
4
5
6
7
8

More info: One To Many (Inverse) (opens new window)

# Define the other relations in the Eloquent models

# More naming conventions

  • The "magic" behind Laravel only works when you follow the naming conventions
  • As we've seen earlier in this chapter, if you follow the naming convention for the relations, the return statement can be very short
  • Some other naming conventions that make your live easier for working with Laravel are:

# Table names

  • By convention, the "snake_case", plural name of the class will be used as the table name
  • If your model's corresponding database table does not fit this convention, you must manually specify the model's table name by defining a protected $table property
  • Some examples:
Model Database table $table property
Flight flights (not needed)
MainCountry main_countries (not needed)
User gebruikers protected $table = 'gebruikers'

# Primary keys

  • By convention, the primary key column must be named id
  • If the primary key does not fit this convention, you must manually specify the primary key by defining a protected $primaryKey property
Table Primary key $primaryKey property
Flight id (not needed)
Flight flight_id protected $primaryKey = 'flight_id'
Last Updated: 10/26/2022, 12:45:26 AM