Structuring Laravel Eloquent Model with Custom Accessors and Mutators

This is NOT a recommended way to work with Laravel. At the time of writing this, strong typing and static analysis tools were not available – with their wide usage now, there is no need to use hacks like this anymore.

In a few recent projects, we have experimented with a slight alteration of Eloquent Models and have found some great value. I thought to share this in case someone else benefits the same way we did 🚀

Let’s first bring a Product model to life for an imaginary e-commerce store:

php artisan make:model Product

We now have our brand new Product model under the App namespace:

<?php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Product extends Model
{
//
}

We do some initial setup at the beginning:

  • Enforcing strict types
  • Marking class as final
  • Adding logical code sections

…resulting in this:

<?php declare(strict_types=1);
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
final class Product extends Model
{
#-----------------------------------------------------------------
# Class Constants
#-----------------------------------------------------------------
 
//
 
#-----------------------------------------------------------------
# Class Properties
#-----------------------------------------------------------------
 
//
 
#-----------------------------------------------------------------
# Relationships
#-----------------------------------------------------------------
 
//
 
#-----------------------------------------------------------------
# Accessors and Mutators
#-----------------------------------------------------------------
 
//
}

Next, we adhere to some general team conventions regarding table and primary key name and include the necessary relations:

<?php declare(strict_types=1);
 
// ...
 
final class Product extends Model
{
// ...
 
#-----------------------------------------------------------------
# Properties
#-----------------------------------------------------------------
 
/**
* @var string
*/
protected $table = 'products';
 
/**
* @var string
*/
protected $primaryKey = 'product_id';
 
#-----------------------------------------------------------------
# Relationships
#-----------------------------------------------------------------
 
/**
* @return HasOne
*/
public function currency(): HasOne
{
return $this->hasOne(Currency::class, 'currencyCode', 'currency');
}
 
// ...
}

You may be wondering what’s new here, this is standard Laravel – you’re entirely correct. I’ve included these details to make sure someone new can also follow along 😌

At this stage, we introduce our own style accessors and mutators to the model (also known as getters/setters):

<?php declare(strict_types=1);
 
// ...
 
final class Product extends Model
{
// ...
 
#-----------------------------------------------------------------
# Accessors and Mutators
#-----------------------------------------------------------------
 
/**
* @return string
*/
public function getName(): string
{
return $this->getAttribute('name');
}
 
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->setAttribute('name', $name);
}
 
/**
* @return float|null
*/
public function getPrice(): ?float
{
return $this->getAttribute('price');
}
 
/**
* @param float|null $value
*/
public function setPrice(?float $value): void
{
$this->setAttribute('price', $value);
}
 
/**
* @return bool
*/
public function isActive(): bool
{
return $this->getAttribute('is_active');
}
 
// ...
}

That’s pretty straightforward, but you may be wondering about the verbosity and why someone would write all these methods by hand.

What’s the benefit?

Well, we have seen these benefits since introducing this overall structure:

  • Model is divided into logical sections, so easy to navigate
  • Model properties are available through IDE auto-completion
  • Model properties are type-hinted, thus using the power of strict type
  • It still preserves the power of Eloquent, so no hacky overrides

In our team, we have seen an overall improvement in DX (developer experience) as a result of these small changes. There are fewer errors, code comprehension has improved and cognitive load has reduced while working with someone else’s code.

Why not just use public properties?

One question that comes up naturally when I present this to anyone: why not just use the public properties? Well, in my opinion, there are a few limitations:

  1. The data type of a given property cannot be enforced, you can set a float value to a property that is defined to store it in the DB
  2. The return type of a given property cannot be determined, so on a language level, you don’t know if a status field is supposed to return a string or int
  3. Property level data validation is difficult, you can set a negative value to a property that is clearly invalid (ex: negative price of a product)
  4. If a property column name is changed, that change needs to be done manually in all places where the property was accessed; as the properties are dynamic, thus cannot make use of IDE usage search

Closing Thoughts

You may want to give this a try and see if this benefits you in any way. This heavily favors the strong typing of PHP 7 so teams who has a preference towards that would get the most out of this. And lastly, your mileage may vary 🙂

Share your ideas and thoughts with me on Twitter!

Installing Symfony 4 (3.4.0-BETA1)

I wanted to install the Symfony 4 beta to play with the new features. While I was able to get most of it working, but was facing issues due to package dependency when trying to install some common bundles. I then settled with the 3.4 branch, which has the exact same functionalities except for some backward compatibility.

Here are the steps to get the framework up & running with the most used bundles:

1composer create-project symfony/skeleton symfony "3.4.0-BETA1"
2cd symfony/
3composer req web-server "3.4.0-BETA1"
4composer req annotations
5composer req orm
6composer req annotations
7composer req doctrine-migrations
8composer req debug "3.4.0-BETA1"
9composer req log
10composer req profiler
11composer req security "3.4.0-BETA1"
12composer req mailer
13composer req validation "3.4.0-BETA1"
14composer req encore
15composer req twig-extensions
16composer req serialization "3.4.0-BETA1"
17composer require friendsofsymfony/rest-bundle
18composer require stof/doctrine-extensions-bundle

Once the installation is done, you can start the application using the web server and it should be running.

Optimizing variables cache in Drupal 6

In Drupal 6, a number of caching strategies are incorporated to handle large traffic. One of them is the serialization of the whole variable table. It is being cached in the database and gets extracted into global $conf variable in each invoke.

In one of our production sites, we faced hard time to keep up with the memory requirement of PHP for the unserialization of this variable from the cache. The variables table was so large that we had to assign around 1GB memory to each PHP thread so that the value can be unserialized without memory exhaustion. This made it much harder to scale the application.

So, we decided to do something about it and successfully handled it by doing the following:

1. First of all, we installed the memcache module to move the cache storage from DB to memory

2. We then edited the memcache module’s cache_get and cache_set functions to store/retrieve individual items from the variables array and split/join them when requested.

3. This requires a memcache call for each of the items in the variable array, but consumes a small amount of memory as there is no huge unserialize operation going on.

4. We performed a few tests to see if the site is working as before, and found its working perfectly!

Here is the code in case you are facing similar issue:

/sites/all/modules/contrib/memcache/memcache.inc

1&lt;?php
2
3// ...beginning part of the file
4
5function cache_set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL) {
6
7 // Handle database fallback first.
8 $bins = variable_get('memcache_bins', array());
9 if (!is_null($table) &amp;&amp; isset($bins[$table]) &amp;&amp; $bins[$table] == 'database') {
10 return _cache_set($cid, $data, $table, $expire, $headers);
11 }
12
13 // In case of special cache items, we keep the individual items as
14 // separate cache items. Later in the retrieval time, we join them together.
15 if (memcache_is_special_cache_item($cid)) {
16
17 $keys = array_keys($data);
18 foreach ($keys as $key) {
19 cache_set($cid . '_' . $key, $data[$key]);
20 }
21
22 cache_set($cid . '_keys', $keys);
23 return true;
24
25 }
26
27 // ...remaining part of the function
28}
29
30function cache_get($cid, $table = 'cache') {
31
32 // Handle excluded bins first.
33 $bins = variable_get('memcache_bins', array());
34 if (!is_null($table) &amp;&amp; isset($bins[$table]) &amp;&amp; $bins[$table] == 'database') {
35 return _cache_get($cid, $table);
36 }
37
38 // The special cache item was previously saved as individual items,
39 // so now we have to retrieve them separately and join them together
40 // and send as one item.
41 if (memcache_is_special_cache_item($cid)) {
42
43 $keys = cache_get($cid . '_keys');
44 if (is_null($keys-&gt;data)) {
45 return false;
46 }
47
48 $data = array();
49 foreach ($keys-&gt;data as $key) {
50 $data[$key] = cache_get($cid . '_' . $key);
51 }
52
53 $cache = new stdClass();
54 $cache-&gt;data = $data;
55
56 return $cache;
57 }
58
59 // ...remaining part of the function
60}
61
62function memcache_is_special_cache_item($cid) {
63 $specials = array('variables', 'strongarm');
64 return in_array($cid, $specials);
65}
66
67// ...remaining part of the file

JSONize your PHP classes using traits

I was having a discussion with a colleague regarding how to add generic JSON based representation to a number of classes without making a big effort. The immediate solution that came in my mind is to use the Traits for it (introduced in PHP 5.4).

So I wrote the following example for him:

JSONized.php

1 
2<?php
3
4trait JSONized {
5
6 public function toJson()
7 {
8 $properties = get_object_vars($this);
9 return json_encode($properties);
10 }
11
12}

User.php

1<?php
2
3class User
4{
5 use JSONized;
6
7 public $username;
8 public $password;
9 public $email;
10
11 public function __construct($username, $password, $email)
12 {
13 $this->username = $username;
14 $this->password = md5($password);
15 $this->email = $email;
16 }
17}

test.php

1<?php
2
3include_once 'JSONized.php';
4include_once 'User.php';
5
6$emran = new User('phpfour', 'emran123', 'phpfour@gmail.com');
7echo $emran->toJson();

The result of running the above code will be like this:

1{
2 "username" : "phpfour",
3 "password" : "02c2ec1e3f21e97dd5ac747147a141e0",
4 "email" : "phpfour@gmail.com"
5}

Using Mockery as a mocking framework with PHPUnit

A few days ago I was explaining mocking to a few colleagues. I came up with the following quick n dirty code to show them the elegance of Mockery as a mocking framework.

The code is straight-forward: it checks the health of a server using a tiny heart beat script.

1. The script residing in the remote server:

1<?php
2
3$response = array('status' => 'online');
4
5header("Content-type: application/json");
6echo json_encode($response);

2. The class that tries to fetch the status from the remote server:

/test/Heartbeat.php

1<?php
2
3class Heartbeat
4{
5 private $http;
6
7 public function __construct(Http $http)
8 {
9 $this->http = $http;
10 }
11
12 public function checkHealth()
13 {
14 $url = 'http://localhost/remote/heart.php';
15 $response = $this->http->getResponse($url);
16
17 $beat = json_decode($response);
18 return (!is_null($beat) && $beat->status == 'online');
19 }
20}

3. The Http wrapper class that we will mock. Remember, in order to mock one object, we must be able to inject that object to the testing class using Dependency Injection.

/test/Http.php

1<?php
2class Http
3{
4 public function getResponse($url)
5 {
6 $response = @file_get_contents($url);
7 return $response;
8 }
9}

4. Finally, the test suite. Observe that we have mocked the Http class here using Mockery and have set expected function call and an expected result as per our need.

/test/HeartbeatTest.php

1<?php
2
3require_once 'gwc.autoloader.php';
4
5use Mockery as m;
6
7include_once 'Heartbeat.php';
8include_once 'Http.php';
9
10class HeartbeatTest extends PHPUnit_Framework_Testcase
11{
12 public function testSystemIsOnlineWhenServiceRuns()
13 {
14 $http = m::mock('Http');
15 $http->shouldReceive('getResponse')->andReturn('{"status":"online"}');
16
17 $heartbeat = new Heartbeat($http);
18 $response = $heartbeat->checkHealth();
19
20 $this->assertTrue($response);
21 }
22}

5. Make sure you have the following libraries installed (they have great install instructions):

6. Run the unit test using phpunit and it should pass:

1Emrans-MacBook-Air ~/Sites/test: phpunit HeartbeatTest.php
2
3PHPUnit 3.6.10 by Sebastian Bergmann.
4.
5
6Time: 0 seconds, Memory: 5.50Mb
7OK (1 test, 1 assertion)

7. Btw, the actual functionality is pretty simple to use as well. Check this script:

/test/check.php

1<?php
2
3include_once 'Heartbeat.php';
4include_once 'Http.php';
5
6$http = new Http();
7$heartbeat = new Heartbeat($http);
8$response = $heartbeat->checkHealth();
9
10echo ($response) ? 'Online' : 'Offline';

This is a very very simple use case and just meant to give an introduction. If you’re serious about unit testing, you should dig deeper into the concepts as well as into the PHPUnit and Mockery library documentations.