loading...

Laravel validation rules — Domains, citizen identification numbers, zero whitespace…

mattkingshott profile image Matt Kingshott 👨🏻‍💻 Originally published at itnext.io on ・5 min read

Image courtesy of Unsplash

Laravel validation rules — domain names, citizenship identification numbers and zero whitespace strings

In this new series, we’ll be exploring the concept of custom validation rules in Laravel and how they can assist you. I’m posting an article each day with a new rule you can use in your projects. The rules are also part of a package.

In this post, we’ll be creating three new rules to validate:

  1. Domain names without the http(s) protocol.
  2. Citizen ID numbers for the USA, UK and France.
  3. Strings have zero whitespace at the beginning, middle and end.

If you’re new to this topic, check out the first article in the series, as well as this article to learn how to use parameters in your rules.

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

Rule #1 — Domain Names

We’ll start with a simple one. We want to allow a user to specify a domain name, but it shouldn’t include the HTTP(s) protocol or an actual URL route e.g. /pages/welcome/index.html

Needless to say, the quickest approach is to use a regular expression to verify these requirements, so let’s insert that logic into the passes method:

public function passes($attribute, $value)
{
    return preg\_match(
        "/^([a-zA-Z0-9][a-zA-Z0-9-\_]\*\.)\*[a-zA-Z0-9]\*[a-zA-Z0-9-\_]\*
        [[a-zA-Z0-9]+$/", $value
    );
}

Next, we’ll need to write an error message to respond with when the user has supplied a value which is not a valid domain:

public function message()
{
    return 'The :attribute must be a valid domain without an http 
            protocol e.g. google.com, www.google.com';
}

As before, we’ll write a quick unit test to confirm that the rule works correctly and rejects values that are not solely domains:

/\*\* @test \*/
public function the\_domain\_rule\_can\_be\_validated()
{
    $rule = ['domain' => [new Domain]];

    $this->assertFalse(validator(['domain' => 'http://'], $rule)->passes());

    $this->assertFalse(validator(['domain' => 'https://'], $rule)->passes());

    $this->assertFalse(validator(['domain' => 'http://google.com'], $rule)->passes());

    $this->assertFalse(validator(['domain' => 'https://google.com'], $rule)->passes());

    $this->assertFalse(validator(['domain' => 'http://google'], $rule)->passes());

    $this->assertFalse(validator(['domain' => 'https://google'], $rule)->passes());

    $this->assertTrue(validator(['domain' => 'google.com'], $rule)->passes());

    $this->assertTrue(validator(['domain' => 'www.google.com'], $rule)->passes());

}

Rule #2 — Citizenship Identification Numbers

Next, we’ll add a rule to verify that a social security number or equivalent has been provided. We’ll need to accept a single parameter, which will be used by the rule to decide which nation’s regular expression should be used:

public function passes($attribute, $value)
{
    switch (mb\_strtolower($this->parameters[0] ?? 'usa')) {

        case 'usa':
            return preg\_match("/^(?!000|666)[0-8][0-9]{2}-(?!00)[0-
                               9]{2}-(?!0000)[0-9]{4}$/", $value);

        case 'uk':
            return preg\_match("/^[A-CEGHJ-PR-TW-Z]{1}[A-CEGHJ-NPR-
                               TW-Z]{1}[0-9]{6}[A-DFM]{0,1}$/", 
                              $value);

        case 'fr':
            return preg\_match("/^[1,2][]?[0-9]{2}[]?[0,1,2,3,5][0-
                               9][]?[0-9A-Z]{5}[]?[0-9]{3}[]?[0-
                               9]{2}$/", $value);

        default:
            return false;

    }
}

NOTE : I’ve only added a few national examples (USA, UK, France), but you can easily add your own if you needed to validate a number from another country.

As before, we’ll need to write an error message to respond with:

public function message()
{
    return 'The :attribute must be a valid form of identification';
}

And finally, include some unit tests:

/\*\* @test \*/
public function the\_citizen\_identification\_rule\_can\_be\_validated\_for\_usa()
{

    $rule = ['id' => [new CitizenIdentification('usa')]];

    $this->assertFalse(validator(['id' => 'XXX-XX-XXXX'], $rule)->passes());

    $this->assertFalse(validator(['id' => '000-11-1111'], $rule)->passes());

    $this->assertTrue(validator(['id' => '401-60-1048'], $rule)->passes());

    $this->assertTrue(validator(['id' => '318-66-9044'], $rule)->passes());

}

/\*\* @test \*/
public function the\_citizen\_identification\_rule\_can\_be\_validated\_for\_uk()
{

    $rule = ['id' => [new CitizenIdentification('uk')]];

    $this->assertFalse(validator(['id' => 'DC135798A'], $rule)->passes());

    $this->assertFalse(validator(['id' => 'FQ987654C'], $rule)->passes());

    $this->assertTrue(validator(['id' => 'JG103759A'], $rule)->passes());

    $this->assertTrue(validator(['id' => 'AP019283D'], $rule)->passes());

}

/\*\* @test \*/
public function the\_citizen\_identification\_rule\_can\_be\_validated\_for\_france()
{

    $rule = ['id' => [new CitizenIdentification('fr')]];

    $this->assertFalse(validator(['id' => 'DC135798A'], $rule)->passes());

    $this->assertFalse(validator(['id' => 'FQ987654C'], $rule)->passes());

    $this->assertTrue(validator(['id' => '1 51 02 46102 043 25'], $rule)->passes());

}

Rule #3 — Without Whitespace

Our final rule will validate that the supplied input does not contain any empty whitespace characters. For instances where the user might be inclined to use spaces e.g. bank cards, but where you can’t accept them, this rule is perfect.

As you would imagine, we can use a painfully simple regular expression:

public function passes($attribute, $value)
{
    return ! preg\_match("/\s/", $value);
}

We’ll also include the error response:

public function message()
{
    return 'The :attribute must not contain any spaces';
}

And the unit test:

/\*\* @test \*/
public function the\_without\_whitespace\_rule\_can\_be\_validated()
{

    $rule = ['text' => [new WithoutWhitespace]];

    $this->assertFalse(validator(['text' => 'hello '], $rule)->passes());

    $this->assertFalse(validator(['text' => ' hello'], $rule)->passes());

    $this->assertFalse(validator(['text' => 'hello world'], $rule)->passes());

    $this->assertTrue(validator(['text' => 'hello'], $rule)->passes());

}

Wrapping Up

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

By now, you should be very familiar with the process of creating custom rules to validate input within your Laravel apps. In addition, with the package now containing over 25 rules, this feels like a good point to wrap up the series.

I hope you’ve found it useful and that you’ll consider the package a worthy inclusion in your default Laravel installations. I’ll now be moving on to other projects, which I hope to document here in the near future.

If you’re interested in hearing about them, you can follow me here, or also on Twitter for the occasional sneak peak.

Thanks for following the series, and 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