Calculating a quality score of something based on attributes I'm willing to have a way to calculate a quality score of an object; in this case an addressbook contact.

I believe there are way better approaches to do this and I'd like to hear your references.

How can I calculate a quality scoring of an object based on its properties?

/**
 *
 * get Quality
 *
 * @return float Contact quality percentual score calculated from profile completion
 */
public function getQualityAttribute()
{
    $quality  = 0;
    $quality += isset($this-&gt;firstname) ? 1 : 0;
    $quality += isset($this-&gt;lastname) ? 1 : 0;
    $quality += isset($this-&gt;nin) ? 5 : 0;
    $quality += isset($this-&gt;birthdate) ? 2 : 0;
    $quality += isset($this-&gt;mobile) ? 4 : 0;
    $quality += isset($this-&gt;email) ? 4 : 0;
    $quality += isset($this-&gt;postal_address) ? 3 : 0;
    $total    = 20;
    return $quality/$total*100;
}


If you want to know the purpose of this method or further in the app, you can find the code here.
This approach sounds logically good, as it allows to determine how much the profile has been completed. There seems to exist a correlation between people completing their profile fully and giving interesting data in these. It also provides an incentive for completion.

A first iteration of improvement could be to decouple the data and the calculation operation.

First, define an array with a bunch of scores.

Then, loop on this array and compute it:

/**
 * Computes the quality of a contact, according profile completion
 *
 * @return float The score calculated from profile completion (between 0 and 1)
 */
public function getQualityAttribute()
{
    $propertiesScore = [
        'firstname' =&gt; 1, 
        'lastname' =&gt; 1,
        'nin' =&gt; 5,
        'birthdate' =&gt; 2,
        'mobile' =&gt; 4,
        'email' =&gt; 4,
        'postal_address' =&gt; 3,
    ];
    $totalScore = array_sum($propertiesScore);

    $qualityScore = 0;
    foreach ($propertiesScore as $property =&gt; $score)
    {            
        if (isset($this-&gt;$property))
        {
            $qualityScore += $score;
        }
    }

    return $qualityScore / $totalScore * 100;
}


This is a first naive approach to illustrate the method, but introduces something not desirable, $this-&gt;$property: this works, but it's not easy to parse by a static analyzer, as the type is not easy to determine. Normally, such code should be replaced by an array.

A more robust approach is so something like this:

    $qualityScore = 0;
    $instanceProperties = get_class_vars($this);
    foreach ($propertiesScore as $property =&gt; $score)
    {
        if (isset($instanceProperties[$property]))
        {
            $qualityScore += $score;
        }
    }


Then, we could see the properties score array is a preference. Laravel offers a config repository to store that.

Move this array to config/app.php or better, create a config/quality.php so you'll be able to put future settings too:

&lt;?php

return [

    /*
    |--------------------------------------------------------------------------
    | Quality score per user profiles
    |--------------------------------------------------------------------------
    |
    | This option allows to balance the equation which determines the quality
    | score of a profile, according its level of completion.
    |
    | You can assign a weight (the greater the more important) to each property.
    |
    */

    'scores' =&gt; [
        'profile' =&gt; [
            'firstname' =&gt; 1, 
            'lastname' =&gt; 1,
            'nin' =&gt; 5,
            'birthdate' =&gt; 2,
            'mobile' =&gt; 4,
            'email' =&gt; 4,
            'postal_address' =&gt; 3,
        ],
    ],
];


Now you can access it from the getQualityAttribute method using $propertiesScore = Config::get('quality.scores.profile');. Don't forget to add use Config; at the top of your file to get this facade.

Finally, if 0 is never a valid answer, you could use empty instead of isset, so you avoid a bug if the property is "" instead of null (that would give score).