How to add an attribute from a model query in laravel

Posted on March 3, 2014 in Web Dev

So I’m still very much into learning Laravel. One project I’m building at the moment is imrepo.com, which when you strip it down to the basics, is basically just a directory of ‘things’ – not the most complex project ever, but I’m still finding that I’m learning a lot along the way.

I got around to releasing a beta version of the website and then looked back at my codebase. It was a mess. I’m very much an advocate of “if it’s not broke, don’t try to fix it”, especially when it comes to launching new projects (à la the Lean Startup philosophy). However, one of my goals for creating this project is to learn Laravel to a high level. I want to know where I’m swaying from Laravel best practices and how to correct it, as well as learn anything to make me a more efficient developer along the way.

The issue here was that I was adding custom attributes to my model query results from my controllers. To make matters worse, I kept repeating code in the process. I created a function and put it into my /app/require/functions.php file, and it worked fine. But then I realised that this solution is far from ideal.

So here is the evolution of how I fixed this issue (sorry about the pseudo code, hopefully you get the idea):

Original (poor code!):

HomeController {
    foreach ($posts and $post) {
       <generate URL based on column values>
    }
}
PostsController {
    foreach ($posts and $post) {
        <generate URL based on column values>
    }
}

Slightly improved (DRY principle)

HomeController {
    $posts = make_post_variables($posts);
}
PostsController {
    $posts = make_post_variables($posts);
}
File: /app/require/functions.php
public function make_post_variables($postsarray) {
    foreach ($posts and $post) {
        <generate URL based on column values>
    }
}

Optimal (using the model)

HomeController {
    $posts = Post::orderBy('created_at', 'DESC')->get();
}
PostsController {
    $posts = Post::orderBy('created_at', 'DESC')->get();
}

File: /app/model/Post.php

protected $appends = array('Url');
public function getUrlAttribute() {
    $url = "/product/" . $this->id . "/" . sluggify($this->post_title);
    return $url;
}

What this final way of doing it means is that every time my Post model gets queried, essentially a new column is being created called “url” which mimics a real column from the database.

Sorry about the poor formatting on this blog so far. It’s on my to-do list of things to fix, I promise!

Feel free to ask any questions in the comments.

Leave a comment

Was this helpful? Did I miss something? Do you have a question? Get in touch, or tell me below.