Laravel 5: Eloquent – accessors & mutators

Eloquent: accessors & mutators

Accessors and mutators allow you to format Eloquent attribute values when you retrieve or set them on model instances.
For example, you may want to use the Laravel encrypter to encrypt a value while it is stored in the database, and then automatically decrypt the attribute when you access it on an Eloquent model.

Accessors

If you want to access a field (column) in database table given Model works with, you can create accessor method in that Model.

Follow strict rules while creating method name.

There are 3 pieces that create method name:

  1. piece one: word ‘get
  2. piece two: name of column in database table you want to access starting with Capital letter
    e.g. ‘Username‘, for table column name ‘username
  3. piece three: word ‘Attribute

So, as a result, we get this name: getUsernameAttribute.

Now lets see that method.

Note argument $value .
Laravel will use it to inject into method appropriate value fetched from database table, so you can do your intended magic with it and return it, so you can access it somewhere (e.g. in Controller) in your project, like this:

That is all, there is to it.

Of course, this simple example just shows simple application, but many interesting things can be done using it.

Also, read about similar functionality here and here.
 Mutators
Defining A Mutator

Rule is very simple and very similar to that of Accessor.
It is because Accessor is similar to Mutator.

Difference is this:

  • Accessor: pulls data from database and allows to work on it in your code
  • Mutator: takes data you attach to column name, transform it to your likings (mutates it – hence mutator) and attach it to $attributes array for further action, e.g. updating its value in database

You create Mutator method in model, that allows you to access desired column in desired table.

How to create method name.
Same as in Accessor’s case, you have to follow structural rules.

There are 3 pieces that create method name:

  1. piece one: word ‘set
  2. piece two: name of column in database table you want to access starting with Capital letter
    e.g. ‘Username‘, for table column name ‘username
  3. piece three: word ‘Attribute

So, as a result, we get this name: setUsernameAttribute.

Now lets see that method.

And this how you may use it, e.g. in a Controller:

Date Mutators
tell Laravel which columns are dates

By default, Eloquent will convert (mutate) the created_at and updated_at columns to instances of Carbon, which extends the PHP DateTime class to provide an assortment of helpful methods.You can define more columns as dates.
Here is how:

Read more here.

tell Laravel, how you wish to format date columns on tables processed by Model

By default, timestamps are formatted as ‘Y-m-d H:i:s‘.
If you need to customize the timestamp format, set the $dateFormat property on your model.
This property determines how date attributes are stored in the database, as well as their format when the model is serialized to an array or JSON

Read more here.

Usage

Now we can save date in proper format to database:

… or access using one of multitude useful Carbon methods:

Attribute Casting

The $casts property on your model provides a convenient method of converting attributes to common data types.
So, you can cast data from given column to bool, even if it is stored as 0/1.

Important:
This casting works upward, meaning it will mutate/cast data into selected format, when it comes FROM server.
So, it is useless for inserting/updating data.

Since PDO is responsible for testing data, many people do not bother. But old-times like me like to cast data downward (to server), so data send for storage in database, or even for processing is in expected format.
Attribute casting will not help us here.

The supported cast types are:
integer, real, float, double, string, boolean, object, array, collection, date, datetime, and timestamp.

Sample use:

Read more here.

Array & JSON Casting

I am stealing below text from Laravel docs – as there is just no better way to put it.

The array cast type is particularly useful when working with columns that are stored as serialized JSON. For example, if your database has a JSON or TEXT field type that contains serialized JSON, adding the array cast to that attribute will automatically deserialize the attribute to a PHP array when you access it on your Eloquent model.

In other words, if have serialized JSON stored in field, casting that field to array will get that serialized JSON and serialize it to array, so you start using data right away without doing it over and over by hand, e.g.:

… allows to use ‘options’ data right away – be it access, or storage:

 

Laravel 5: Eloquent – querying relationship

Eloquent: querying relationship

All types of Eloquent relationships also serve as query builders, allowing you to continue to chain constraints onto the relationship query before finally executing the SQL against your database.
They are lazy loaded. They can be eager loaded to avoid n+1.

Getting data
Use dynamic property

Run get() on method

Chain builder methods

querying relationship existence
get only sellers that sell any ebooks

get only sellers that sell more than 2 ebooks (constraint)

get only posts that have comments with some votes on them

get  all posts with at least one comment containing words like foo%

There is also ‘orWhereHas‘ property available.

get seller that does not sell any ebooks

get ebooks which are not written by author with name starting at ‘Isaac’

count ebook titles (models) sold by given seller

count many models with constraints

eager loading

To check how many queries your code produces, use this.

Lazy loading – this code will produce multiple queries

Eager loading – this code will produce only 2 queries

Eager loading on multiple relations

Nested eager loading (dot notation)
Here we get authors with their ebooks.

Eager loading with constraints

All builder methods are available here.

Lazy eager loading

Turn lazy load code into eager, if some condition is met.

Additional constraints:

Inserting & Updating Related Models
Save

Save many

Create

Belongs To Relationships:
associate

This method will set the foreign key on the child model.

dissociate

This method will set the relationship’s foreign key to null.


More – see Laravel docs.

 

Laravel 5: Eloquent – relationship types: many to many polymorphic relations

Eloquent: relationship types – many to many polymorphic relations

Difference between one-to-one polymorphic relations and many-to-many polymorphic relations – see here.
How to prepare models to be able to easily access and store data in tables.
This page describes practical use of methods:
  • morphToMany and
  • morphedByMany

Just scroll down.

Important!!!
Go here and read about morphMap  and ‘gotchas
This is in case, you will do everything on this page and result is going to come empty.

First DB tables used in examples.

Main table: messages (Messages model)

Pivot table: message_attachables

Related table sample: tutor_aids (TutorAid)

morphedByMany

You are looking for all Tutor Aids that are related (linkd to) selected message.

This method should be located on main model – in this case Messages,
as you are looking for related data for selected message.

example:

First argument is what you want to fetch – in this case: TutorAid::class.
Second ‘message_attachable’ is a prefix of message_attachable_id and message_attachable_type.
It allows to identify table and some other stuff.

usage example:

usage explained:

You are selecting message first by primary id: Message::find(2);

Now, you are looking for all TutorAids: ->getTutorAids

that are matched with model TutorAids in pivot table message_attachables.

Look at table message_attachables
Message with message_id = 2 that is marked by model TutorAid is listed twice.

morphedByMany will now look into \App\Models\Tutor\TutorAid::class (table tutor_aids)
using message_attachable_id data (which matches primary id in TutorAid) and fetch for us details of these tutor aids.

Additional data that can be fetched

Collection comes here with some additional data, like:

  • pivotParent: message data (table messages, model Message) and
  • pivot table data (table message_attachables, Model MessageAttachables)

Access message data:

note: getTutorAids[0]

Collection comes usually as an array, so you either loop it, or access it using key,
to specify which you are interested in.

Using process describes above, you can define Message relation to other models
from column message_attachable_type like:

  • TutorContent
  • TutorTest

… and create methods on Message model:

  • getTutorContents()
  • getTutorTests()

 

morphToMany
This method is placed in models listed in column message_attachable_type:
  • TutorContent
  • TutorTest
  • TutorAid

This method allows to work in reverse and will get us all mesages (model Message)
that are related to one of three models listed above.

Here is morph method placed in TutorAids model:

As you see, first argument is different, than in morphedByMany, as we are looking now for related messages.

usage example:

Just to explain above code – we are getting all messages for TutorAid #538.

If you look into sample table: message_attachables in column: message_attachable_id,
you will find TutorAid #538 twice.
Related message_id are: 2 and 194.

Now morphToMany will look into Model Message (table messages) and fetch for us
two messages with primary id: 2 and 194.

sample data fetched:

Also, we can get pivotParent (tutor_aids) and pivot (message_attachables) tables data.

Now, you can repeat this process on models:

  • TutorContent
  • TutorTest

and get methods getMessages related to those models.

 

Laravel 5: Eloquent – relationship types: many models to many models example

Eloquent: relationship types: many models to many models example

I will explain here:

  • how parameters in polymorphic relations work
  • how to relate many models on many models
many-to-many: one model with many

Most basic use of polymorphic relation is when you have single model commanding data of many models.

We have main model Seller working with models Ebook and Reader.

For such relationship, we build piwot table looking like this:

‘seller_id’
We have out column ‘seller_id’ that is compared against column ‘id’ of table ‘sellers’ – one model Seller is working with.

‘flagable_id’
Name is unimportant, could be selable_id, or anything else.
This column works with ‘id’ column from table defined in ‘flagable_type’, e.g. table ‘ebooks’.

‘flagable_type’
This column describes which model we are comparing against.


many-to-many: many models with many

But sometimes, you may want to work many tables against many tables, e.g.:

In this case we build more than one column for main models:

  • seller_id (model Seller, table sellers)
  • distributor_id (model Distributor, table distributors)

The whole trick is how you define relationship methods in your related models.

Just see sample models below, read comments and see tables.

Pivot (with extra column for distributor):

Table sellers:

Model Seller:

Table distributors:

Model Distributor:

Table ebooks:

Model Ebook:

Table readers:

Model Reader:

Usage:

Getting pivot data:

 

Laravel 5: Eloquent – relationship types: polymorphic relations

Eloquent: relationship types – polymorphic relations

DB tables used in examples: here.
Tables you should look for:
— ebooks table (Ebook model)
— readers table (Reader model)
— comments table (Comment model) (quasi-pivot)

polimorphic

Lets explain idea behind polymorphic relations

Laravel’s polymorphic relations are actually, what I did many times over in my projects.
I just did not call them so dramatically.

Figure A: my old way

You have Products and Services.
Both stored in separate tables.
I could have each assigned separate Comments table.
But that would require joining tables for any common output of comments for both.
So, what I did, I used single table looking something like this (simplified):

In above table

  • type_id was a foreign_key for a table specified in
  • type column.

Figure B: Laravel polymorphic relation

Now, lets look at Laravel polymorphic relation table structure:

See similarity?

Above table has also 2 relevant columns:

  • commentable_id column holds foreign_key for
  • table attached to model defined in commentable_type column

Conclusion

So as you see – by comparing both tables, this hifi name – polymorphic relation – is just another spirit killing off the high shelf jargon.
While in reality, the whole idea is a simple stuff, that’s been around for ages.

What needs to be explained in detail, is how to use it inside of Laravel framework.

Gotchas – must be taken care of – or your coiffure may get damaged!!!

REMEMBER !!

As of Laravel 5.3 you MUST setup morphMap array.
If you do not do this, Laravel will not properly process your Model names from column ‘commentable_type‘.
In commentable_type, you have just their name, while Laravel needs them as fully qualified name (with namespace), like:

So, unless you want to store fully qualified name, you need morphMap.

If you do not set morphMap, then all comments calls will fail quietly – very frustrating!
And all calls for ‘commentable‘ will return that your model from ‘commentable_type‘ field cannot be found.

How to set it:
To boot() method of AppServiceProvider add this code (except for ‘use‘ that goes on top):

Of course ‘App\’ section must be your true namespace to your model.

In Laravel 5.2 you had $morphClass property which you used in Model like this:

Not anymore.

Polymorphic relations Models

I am going to use these three tables:

  • comments
  • ebooks
  • readers

Models below will have simplified relations without all attributes.
Just see this file for more (it seems to be cleaner than API):

Comment model

This is a main model that holds data common to many models and has foreign keys and model names columns in its table, like commentable_id and commentable_type.

Reader model

This is one of related model, that has some data in table overseen by main model.

Ebook model

This is one of related model, that has some data in table overseen by main model.

How to handle data in polymorphic relations
get model instance of related model by using its foreign key in polymorphic model column ‘commentable_id’

get comments for given related model by using its foreign key in polymorphic model column ‘commentable_id’

Save comment for Ebook, or Reader

 

Laravel 5: Eloquent – difference between polymorphic relations

Eloquent: difference between polymorphic relations

Difference between simple polymorphic relations and many to many polymorphic relations comes down to pivot table.
simple polymorphic relations
This polymorphic relation can work only on one-to-one basis.

You have one table (model) handling data for two, or more models.
Data is assigned to to data from another table (model), but it cannot serve multiple models.

Lets see these 3 tables to demonstrate example.

ebooks table:

readers table:

comments table:

Comments table, is a quasi-pivot table.
Quasi, because besides pivot columns: commentable_id and commentable_type it has also data table: body.

Since data is firmly attached to pivot values, it can serve only single dataset (model instance).

Example:
Dataset 2:
Reader (row #2 from comments table) can only hold comment for item with id 2 from readers table – which is Kindle.
Dataset 3:
Ebook (row #3 from comments table) can only hold comment for item with id 2 from ebooks table – which is 2001: A Space Odyssey by Arthur C. Clarke.

So, this polymorphic relation can work only on one-to-one basis and quasi-pivot table with data-load is just a convenient data holder for multiple models.

See here how to use it.

many to many polymorphic relations
This polymorphic relation can work only on many-to-many basis.

You have one table (model) handling data for multiple models via pivot table, which allows data to serve multiple models.

Lets say we have some multiple tables:

  • ebooks and
  • readers

Data from our multiple tables can be tagged by data from single table.
Ebooks and readers can be sold by many sellers, like:

  • ebay
  • amazon
  • allegro

Ebooks are held by table like an example one a bit above on this page.
Readers are held by table like like an example the one just above.

Sellers are held by separate table, that look like this:

Now, each ebook / reader can be sold by multiple retailers.
So, to connect them together, we need some sort of pivot table.
Here is our sample pivot table:

Lets explain table above:

  • seller_id
    holds foreign key from sellers table
    its name consists of:

    • lowercase name of model working with sellers table, in this case ‘seller’
    • suffix ‘_id’
  • saleable_id
    this is a foreign key from table described by model in next column
  • saleable_type
    name of table joined described by model name

See here how to use it.

 

Laravel 5: Eloquent – relationship types: has many through

Eloquent: relationship types – has many through

DB tables used in examples: here.

hasManyThrough

Has-many-through:
Resembles a bit pivot table relationship. Only difference is that some existing table is used as a logical connector between two tables that lack direct connection.
Sample table structure

Lets say we want to check how many votes comments for given post got.
There is no direct connection between ‘posts‘ and ‘votes‘, so we will have to use some intermediate table to connect these two.

Here are structures of tables with relevant columns.

Distant relation between models: hasManyThrough()

So, we will use ‘comments’ table as our intermediate (quasi-pivot) table, using its keys: id, post_id as hooks, to inter-relate models post and vote.

Our hasManyThrough() location and sample

This method goes into our main model: POST.

Lets explain hasmanyThrough() method arguments:

Legend:

  1. main model: Post
  2. intermediate model: Comment
  3. final model: Vote

Now, arguments from hasmanyThrough() relationship and how they relate to each other.

argument #1 (comments.post_id)
field from intermediate: intermediate model relationship to main model – should relate with arg. #3

argument #2  (votes.comment_id)
field from final: final model relationship to intermediate model – should relate with arg. #4

argument #3  (post.id)
field from main: main model relationship to intermediate model – should relate with arg. #1

argument #4  (comments.id) (available since L5.5 – before defaulted to primary)
field from intermediate: intermediate model relationship to final model – should relate with arg. #2

 

how to use it
Access data via Post object.
We can use Eloquent dynamic property.

Above example allows to get Vote object data for given instance of Post via intermediate Comment model.

 

Laravel 5: Eloquent – relationship types: many to many

Eloquent: relationship types – many to many

DB tables used in examples: here.

many2many

Many-to-many:
This relation defines many to many situation.
Posts can have more than one tag, e.g. it could be described by tags: laravel, framework, php etc.
But also given tag can describe more than one post, e.g. tag ‘laravel’ could describe dozens of posts about Laravel.
Pivot table

This kind of table usually has only 2 fields (columns) and each holds primary id for each pivoted table as a foreign key.
Lets see this image:

many2many2

So, when create pivot table, the general idea is to prefix ‘_id‘ with lower case of pivoted model name.
e.g. in this case we pivot models: POST and TAG, so we get post_id and tag_id.

Laravel also expects pivot table to named by taking alphabetically lowercase names of pivoted models.
In our case, we would get this name: post_tag.

Of course you can have custom names for foreign keys in pivot table and you can name pivot table anything you want, but then you have to specify them in method belongsToMany() – read below.

Post can have MANY tags and vice versa: belongsToMany()
base notation

explanation:
ModelName in this case is: Post, or Tag – depending, in which we use this.

  • method location – one method is located on each of joined models
  • argument #1 – object name
    It can be given as:

    • object name with path: App\Models\ModelName
    • object name: ModelName – required use App\Models\ModelName
    • class name: ModelName  – required use App\Models\ModelName
  • argument #2pivot_table
    This table is used to join models involved – read more above in section about pivot table.
  • argument #3 and #4 – foreign_key_defined_model / foreign_key_joined_model
    This is one of foreign keys – as third, you usually give foreign key from pivot table, that belongs to model you place method belongsToMany().
    example: if method belongsToMany() is defined on model Post, then foreign_key_defined_model is ‘post_id‘ and foreign_key_joined_model is ‘tag_id‘ as this is a joined model.
    When you place belongsToMany() on model Tag, then you switch foreign_key_defined_model to ‘tag_id‘ and foreign_key_joined_model to ‘post_id‘.
how it looks like – example:
POST model:

 TAG model:

how to use it
Access data via Post object.
We can use Eloquent dynamic property.

Access data via Tag object.
We can use Eloquent dynamic property.

Extra columns in pivot table

Timestamps maintenance

If your pivot table has timestamps and you want to maintain them automatically, do this:

If you want to add constraint using extra pivot tables, use this:

If you are comparing against array use this:

It works like in_array().

 

Laravel 5: Eloquent – relationship types: one to many

Eloquent: relationship types – one to many

DB tables used in examples: here.

one2many

One-to-many:
One post has many comments, but given comment belongs to single post.
ONE post has MANY comments: hasMany()
base notation

explanation:

  • method location – this method goes into parent Model – Post in this case
  • argument #1 – Comment: this is child object name
    it can be given as:

    • object name with path: App\Models\Comment
    • object name: Comment– required use App\Models\Comment
    • class name: Comment::class  – required use App\Models\Comment
  • argument #2foreign_key relation
    what is foreign key: column in table ‘comments‘ used to relate to table ‘posts‘, in other words: holding ‘posts‘ table main id
    this is optional, if foreign key name is a snake case of parent model name and suffix ‘_id’, in this case: post_id
    if your foreign_key name is different, you have to state it as argument #2
  • argument #3 – local_key relation
    what is local_key: it is primary key in posts (parent model) table
    Laravel expects it to be named id, if it is not, local_key must be given in hasMany method
how it looks like – example:

Inverse: ONE comment belongs to ONE post: belongsTo()
base notation

explanation:

  • method location – this method goes into child Model – Comment in this case
  • argument #1 – User: this is parent object name
    it can be given as:

    • object name with path: App\Models\Post
    • object name: Post– required use App\Models\Post
    • class name: Post::class  – required use App\Models\Post
  • argument #2foreign_key relation
    this is an argument on model, where this metod resides in – in this case: Comment model
    what is foreign key: column in table ‘comments’ used to relate to table ‘posts’, in other words: holding posts table main id
    this is optional, if foreign key name is a snake case of parent model name and suffix ‘_id’, in this case: post_id
    if your foreign_key name is different, you have to state it as argument #2
  • argument #3 – other_key relation (equivalent to local_key in hasMany)
    this is an argument on model, which is given in belongsTo statement – in this case: Post model
    what is other_key: it is primary key in users (parent model) table
    Laravel expects it to be named id, if it is not, other_key must be given in belongsTo method
how it looks like – example:

how to use it
Access data via Post object.
We can use Eloquent dynamic property.

Access data via Comment object.
We can use Eloquent dynamic property.

 

Laravel 5: Eloquent – relationship types: one to one

Eloquent: relationship types – one to one

DB tables used in examples: here.

one2one

One-to-one:
One user has one phone and one phone belongs to one user.
ONE user has ONE phone: hasOne()
base notation

explanation:

  • method location – this method goes into parent Model – User in this case
  • argument #1 – Phone: this is child object name
    it can be given as:

    • object name with path: App\Models\Phone
    • object name: Phone – required use App\Models\Phone
    • class name: Phone::class  – required use App\Models\Phone
  • argument #2foreign_key relation
    what is foreign key: column in table ‘phones’ used to relate to table ‘users’, in other words: holding user table main id
    this is optional, if foreign key name is a snake case of parent model name and suffix ‘_id’, in this case: user_id
    if your foreign_key name is different, you have to state it as argument #2
  • argument #3 – local_key relation
    what is local_key: it is primary key in users (parent model) table
    Laravel expects it to be named id, if it is not, local_key must be given in hasOne method
how it looks like – example:

Inverse: ONE phone belongs to ONE user: belongsTo()
base notation

explanation:

  • method location – this method goes into child Model – Phone in this case
  • argument #1 – User: this is parent object name
    it can be given as:

    • object name with path: App\Models\User
    • object name: User – required use App\Models\User
    • class name: User::class  – required use App\Models\User
  • argument #2foreign_key relation
    what is foreign key: column in table ‘phones’ used to relate to table ‘users’, in other words: holding user table main id
    this is optional, if foreign key name is a snake case of parent model name and suffix ‘_id’, in this case: user_id
    if your foreign_key name is different, you have to state it as argument #2
  • argument #3 – other_key relation (equivalent to local_key in hasOne)
    what is other_key: it is primary key in users (parent model) table
    Laravel expects it to be named id, if it is not, other_key must be given in belongsTo method
how it looks like – example:

how to use it
Access data via User object.
We can use Eloquent dynamic property.

Access data via Phone object.
We can use Eloquent dynamic property.