loading...

Laravel validation rule — record owner

mattkingshott profile image Matt Kingshott 👨🏻‍💻 Originally published at Medium on ・3 min read

Image courtesy of Unsplash

Laravel validation rule — record owner

In this new series, we’ll be exploring the concept of custom validation rules in Laravel and why you’ll want to use them. I’m aiming to release a new article each day containing a new rule which you can use in your own projects. I’ll also be collecting these rules into a package that you can pull in via composer.

Recap

If you’re unfamiliar with the reasoning behind creating custom rules to handle data validation, check out the intro section from the first article in this series.

You may also want to review the section on creating a rule (in the same post), as we won’t be repeating the mechanics of each method in your validation classes, we’ll just be exploring the code required to make the rule work.

Promotion

I’ve recently released Pulse — a friendly, affordable server and site monitoring service designed specifically for developers. It includes all the usual hardware monitors, custom service monitors, alerting via various notification channels, logs, as well as full API support. Take a look… https://pulse.alphametric.co

Server and Site Monitoring with Pulse

The check and response

Let’s begin by writing the logic necessary to ensure that the current user is the “owner” of a particular record. To do so, we’ll need to allow our rule to accept a database table and a record id to verify against.

However, in order to accept those values, we’ll need to add a constructor to our RecordOwner class which will accept any number of given parameters and convert them to an array for us to use later.

A new abstract rule class

I’ve actually opted to go a step further and create a custom rule abstract class that all our other rules can inherit from. That way, all of our rules can accept parameters without having to declare a constructor each time:

<?php

use Illuminate\Contracts\Validation\Rule as BaseRule;

abstract class Rule implements BaseRule
{

    protected $parameters;

    public function \_\_construct()
    {
        $this->parameters = func\_get\_args();
    }

}

Back to the rule itself

Now that our RecordOwner class can accept parameters, let’s go ahead and create the database query required to verify ownership:

public function passes($attribute, $value)
{
    return DB::table($this->parameters[0])
             ->where($this->parameters[1], $value)
             ->where('user\_id', Auth::id())
             ->exists();
}

Let’s break this down... the query uses the first parameter provided to the class as its table. It then uses the second parameter (almost always id) as the record to match against. Finally, we check that the corresponding record’s user_id value matches that of the currently authenticated user.

Next, we’ll need to write an error message to return when the user is either unauthenticated or not the owner of the record:

public function message()
{
    return 'You do not have permission to interact with this resource';
}

Testing it works

As before, we’ll write a quick unit test to confirm that the rule works correctly and rejects unauthenticated users & authenticated users that are not owners:

/\*\* @test \*/
public function a\_record\_owner\_can\_be\_validated()
{
    $rule = ['phone' => [new App\Rules\RecordOwner('posts', 'id')]];

    $owner = factory(App\User::class, 1)->create();
    $other = factory(App\User::class, 1)->create();
    $post = factory(App\Post::class, 1, ['user\_id' => $owner->id])->create();

    // Test a unauthenticated user
    $this->assertFalse(validator(['post\_id' => $post->id], $rule)->passes());

    // Test an authenticated user (but not the owner)     
    Auth::loginUsingId($other);
    $this->assertFalse(validator(['post\_id' => $post->id], $rule)->passes());

    // Test an authenticated user (that is the owner)
    Auth::loginUsingId($owner);
    $this->assertTrue(validator(['post\_id' => $post->id], $rule)->passes());

}

Wrapping Up

We now have a reusable validation rule to ensure that the authenticated user is the owner of a given record. We also respond with a suitable error message when the check fails, and we have a test to ensure the rule works.

You can see the complete class and pull it into your projects by visiting the repo on Github: https://github.com/alphametric/laravel-validation-rules

I have additional validation rules that I intend to share with you in the coming days, so be sure to follow me for those articles. If you’re interested, you can also follow me on Twitter to see everything I’m up to.

Happy coding!

Posted on by:

mattkingshott profile

Matt Kingshott 👨🏻‍💻

@mattkingshott

Founder. Developer. Writer. Lunatic. Created Pulse, IodineJS, Axiom, and more. #PHP #Laravel #Vue #TailwindCSS

Discussion

markdown guide