DEV Community

Joël Harkes
Joël Harkes

Posted on

2 3

Make Laravel do type safe validation

Laravel has a nice validation framework, but a big catch is that it doesn't make sure your result has the right types.

here an example:

$data = ['isOk' => '1'];
$result = $this->validate($data, ['isOk' => 'boolean');

$isOkString = $result['isOk'];
$isOkBoolean = (boo;)  $result['isOk'];
if($isOkString === true){
    // wont fall here.
}
if($isOkBoolean === true){
    // but will go here.
}

wouldn't be wonderful to make sure you have no side affects.

Todo this we must create a nice interface to be able to make Rules allow to transform the result. You must subclass the Laravel Validator and extend the method: validateUsingCustomRule

interface RuleTransformsResult
{
    public function transformResult($attribute, $value);
}


class MyTypeSafeValidator extends \Illuminate\Validation\Validator {
    protected function validateUsingCustomRule($attribute, $value, $rule)
    {
        // below is just copy pasted laravel code of method
        if (!$rule->passes($attribute, $value)) {
            $this->failedRules[$attribute][get_class($rule)] = [];

            $messages = (array) $rule->message();

            foreach ($messages as $message) {
                $this->messages->add($attribute, $this->makeReplacements(
                    $message, $attribute, get_class($rule), []
                ));
            }

        // here is where we do our magic
        } elseif ($rule instanceof RuleTransformsResult) {
            $newValue = $rule->transformResult($attribute, $value, $result);
            if($newValue !== $value) {
                Arr::set($this->data, $attribute, $result);
            }
        }
    }
}

Now we can write our own Boolean validator:

class ValidBoolean implements Rule, RuleTransformsResult
{
    public static $validValuesMap = [
        '0' => false,
        '1' => true,
        'false' => false,
        'true' => true,
        'yes' => true,
        'no' => false,
    ];

    public function passes($attribute, $value)
    {
        if (is_bool($value)) {
            return true;
        }

        return array_key_exists((string) $value, self::$validValuesMap);
    }

    public function message()
    {
        return __('validation.boolean');
    }

    public function transformResult($attribute, $value)
    {
        return (bool) $value;
    }
}

Now we can always have a boolean as result:

$data = ['isOk' => '1'];
$result = $this->validate($data, ['isOk' => [new ValidBoolean()]);

if($result['isOk'] === true){
   // yeah we will make it here.
}

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs