A simple validation package based on Valitron.
A simple validation package for PHP inspired by Valitron.
use Rougin\Valla\Valid;
$data = array('name' => '', 'email' => 'not-an-email');
$valid = new Valid($data);
$valid->addRule('name', 'required');
$valid->addRule('email', 'required|email');
if (! $valid->passed())
{
// "Name is required"
echo $valid->firstError();
}Install the package using Composer:
$ composer require rougin/vallaThe core of Valla is the Valid class. Create an instance with the data to validate, then add rules with addRule():
use Rougin\Valla\Valid;
$data = array('age' => 'abc');
$data['email'] = 'not-an-email';
$data['name'] = '';
$valid = new Valid($data);
$valid->addRule('age', 'required|numeric');
$valid->addRule('email', 'required|email');
$valid->addRule('name', 'required');
if (! $valid->passed())
{
$errors = $valid->getErrors();
// "Age must be numeric"
echo $valid->firstError();
}Labels provide user-friendly field names in error messages:
use Rougin\Valla\Valid;
$data = array('email' => 'not-an-email');
$valid = new Valid($data);
$labels = array('email' => 'Email Address');
$valid->setLabels($labels);
$valid->addRule('email', 'email');
if (! $valid->passed())
{
// "Email Address is not a valid email address"
echo $valid->firstError();
}Custom rules can be added by implementing to RuleInterface:
namespace Rougin\Test\Rules;
use Rougin\Valla\RuleInterface;
use Rougin\Valla\Ruleset;
class Uppercase implements RuleInterface
{
public function getError()
{
return 'must be uppercase';
}
public function getName()
{
return 'uppercase';
}
public function passed($value, array $data)
{
return strtoupper($value) === $value;
}
public function setValue(array $values)
{
return $this;
}
}To register the custom rule, add it to a Ruleset class then set it to the Valid class:
use Rougin\Test\Rules\Uppercase;
use Rougin\Valla\Valid;
use Rougin\Valla\Ruleset;
// Register the custom rule ---
$rules = new Ruleset;
$rules->addRule(new Uppercase);
// ----------------------------
// Inject the ruleset to check ---
$data = array('name' => 'Valla');
$valid = new Valid($data);
$valid->setRuleset($rules);
// -------------------------------
$valid->addRule('name', 'uppercase');
if (! $valid->passed())
{
// "Name must be uppercase"
echo $valid->firstError();
}Check classThe Check class provides a declarative, class-based approach to validation by defining rules and labels as properties. It wraps a Valid instance internally.
The $labels property defines user-friendly names for the fields, while $rules specifies the validation rules:
use Rougin\Valla\Check;
class UserCheck extends Check
{
protected $labels = array(
'age' => 'Age',
'email' => 'Email',
'name' => 'Name',
);
protected $rules = array(
'age' => 'required|numeric',
'email' => 'required|email',
'name' => 'required',
);
}Once the Check class is created, validate an array of data using valid():
$check = new UserCheck;
$data = array('name' => 'John');
$data['age'] = 20;
$data['email'] = '[email protected]';
if (! $check->valid($data))
{
echo $check->firstError();
}For more validation scenarios, the labels and rules methods can be overridden to define them dynamically:
use Rougin\Valla\Check;
class UserCheck extends Check
{
/**
* @return array<string, string>
*/
public function labels()
{
$labels = $this->labels;
$labels['is_company'] = 'Is a Company?';
return $labels;
}
/**
* @param array<string, mixed> $data
*
* @return array<string, string>
*/
public function rules(array $data)
{
$rules = $this->rules;
if (array_key_exists('is_company', $data))
{
$rules['company_name'] = 'required';
}
return $rules;
}
}If using ServerRequestInterface from PSR-7, the Request class provides a convenient way to validate request data:
use Rougin\Valla\Request;
class UserCheck extends Request
{
/**
* @var array<string, string>
*/
protected $aliases = array(
'username' => 'name',
'email_add' => 'email',
'new_age' => 'age',
);
// ...
}The Request class provides two methods for validation: isParamsValid for validating query parameters and isParsedValid for validating the parsed body:
$check = new UserCheck;
// Returns the "ServerRequestInterface" ---
$request = Http::getServerRequest();
// ----------------------------------------
// Checks against data from "getQueryParams" ---
if ($check->isParamsValid($request))
{
// Query parameters are valid
}
// ---------------------------------------------
// Checks against data from "getParsedBody" ---
if ($check->isParsedValid($request))
{
// Parsed body is valid
}
// --------------------------------------------When an alias is specified, it will be used to look for the field in the ServerRequestInterface data. For example, if the request data contains a username field, it will be validated against the rules defined for the name field.
validWhen extending the Request class and overriding the valid method, the setAlias method must be called to apply the defined aliases:
use Rougin\Valla\Request;
class UserCheck extends Request
{
// ...
public function valid($data)
{
// Always include this if aliases are defined ---
$data = $this->setAlias($data);
// ----------------------------------------------
if (! parent::valid($data))
{
return count($this->errors) === 0;
}
// Add extra custom validation conditions here
return count($this->errors) === 0;
}
}Valla ships with 43 built-in rules, each pre-loaded in the default Ruleset:
Checks that the value contains the given substring with non-string values fail automatically:
use Rougin\Valla\Valid;
$data = array('name' => 'Jane');
$valid = new Valid($data);
$valid->addRule('name', 'contains:Doe');
if (! $valid->passed())
{
// "Name must contain Doe"
echo $valid->firstError();
}Validates a credit card number using the Luhn algorithm with dashes and spaces stripped before checking:
use Rougin\Valla\Valid;
$data = array('card' => '123456789');
$valid = new Valid($data);
$valid->addRule('card', 'creditCard');
if (! $valid->passed())
{
// "Card must be a valid credit card number"
echo $valid->firstError();
}Validates a properly formatted email address with non-string values fail automatically:
use Rougin\Valla\Valid;
$data = array('email' => 'not-an-email');
$valid = new Valid($data);
$valid->addRule('email', 'email');
if (! $valid->passed())
{
// "Email is not a valid email address"
echo $valid->firstError();
}Checks that the value matches one of the listed values:
use Rougin\Valla\Valid;
$data = array('role' => 'guest');
$valid = new Valid($data);
$valid->addRule('role', 'in:admin,editor');
if (! $valid->passed())
{
// "Role contains invalid value"
echo $valid->firstError();
}Validates that the value is an instance of the given class with non-object values fail automatically:
use Rougin\Valla\Valid;
$data = array('obj' => new \stdClass);
$valid = new Valid($data);
$valid->addRule('obj', 'instanceOf:\DateTime');
if (! $valid->passed())
{
// "Obj must be an instance of 'DateTime'"
echo $valid->firstError();
}Checks that the value does not exceed the given character length with non-string values fail automatically:
use Rougin\Valla\Valid;
$data = array('name' => 'too long');
$valid = new Valid($data);
$valid->addRule('name', 'lengthMax:5');
if (! $valid->passed())
{
// "Name must not exceed 5 characters"
echo $valid->firstError();
}Checks that the value meets the given minimum character length with non-string values fail automatically:
use Rougin\Valla\Valid;
$data = array('name' => 'Jo');
$valid = new Valid($data);
$valid->addRule('name', 'lengthMin:5');
if (! $valid->passed())
{
// "Name must be at least 5 characters long"
echo $valid->firstError();
}Checks that the value does not match any of the listed values:
use Rougin\Valla\Valid;
$data = array('role' => 'admin');
$valid = new Valid($data);
$valid->addRule('role', 'notIn:admin,editor');
if (! $valid->passed())
{
// "Role contains invalid value"
echo $valid->firstError();
}Checks that the value is numeric:
use Rougin\Valla\Valid;
$data = array('age' => 'abc');
$valid = new Valid($data);
$valid->addRule('age', 'numeric');
if (! $valid->passed())
{
// "Age must be numeric"
echo $valid->firstError();
}Ensures the field is present and not empty with an optional strict mode rejecting only null:
use Rougin\Valla\Valid;
$data = array('name' => '');
$valid = new Valid($data);
$valid->addRule('name', 'required');
if (! $valid->passed())
{
// "Name is required"
echo $valid->firstError();
}Makes the field required when at least one of the listed fields is present and non-empty:
use Rougin\Valla\Valid;
$data = array('company_name' => '', 'is_company' => 'yes');
$valid = new Valid($data);
$valid->addRule('company_name', 'requiredWith:is_company');
if (! $valid->passed())
{
// "Company_name is required"
echo $valid->firstError();
}Makes the field required when at least one of the listed fields is absent or empty:
use Rougin\Valla\Valid;
$data = array('phone' => '');
$valid = new Valid($data);
$valid->addRule('phone', 'requiredWithout:email');
if (! $valid->passed())
{
// "Phone is required"
echo $valid->firstError();
}Checks that every item in the array belongs to the listed set with non-array values fail automatically:
use Rougin\Valla\Valid;
$data = array('options' => array('a', 'd'));
$valid = new Valid($data);
$valid->addRule('options', 'subset:a,b,c');
if (! $valid->passed())
{
// "Options contains an item that is not in the list"
echo $valid->firstError();
}Checks that the value is one of yes, on, 1, or true:
use Rougin\Valla\Valid;
$data = array('terms' => 'no');
$valid = new Valid($data);
$valid->addRule('terms', 'accepted');
if (! $valid->passed())
{
// "Terms is not accepted"
echo $valid->firstError();
}Checks that the value contains only alphabetic characters:
use Rougin\Valla\Valid;
$data = array('name' => '123');
$valid = new Valid($data);
$valid->addRule('name', 'alpha');
if (! $valid->passed())
{
// "Name must contain only alphabetic characters"
echo $valid->firstError();
}Checks that the value contains only alpha-numeric characters:
use Rougin\Valla\Valid;
$data = array('name' => 'test!@#');
$valid = new Valid($data);
$valid->addRule('name', 'alphaNum');
if (! $valid->passed())
{
// "Name must contain only alpha-numeric characters"
echo $valid->firstError();
}Checks that the value is an array:
use Rougin\Valla\Valid;
$data = array('items' => 'string');
$valid = new Valid($data);
$valid->addRule('items', 'array');
if (! $valid->passed())
{
// "Items must be an array"
echo $valid->firstError();
}Checks that the array value contains all of the specified keys:
use Rougin\Valla\Valid;
$data = array('data' => array('a' => 1));
$valid = new Valid($data);
$valid->addRule('data', 'arrayHasKeys:a,b');
if (! $valid->passed())
{
// "Data must contain the required keys"
echo $valid->firstError();
}Checks that the value contains only ASCII characters:
use Rougin\Valla\Valid;
$data = array('name' => "J\xC3\xA1ne");
$valid = new Valid($data);
$valid->addRule('name', 'ascii');
if (! $valid->passed())
{
// "Name must contain only ASCII characters"
echo $valid->firstError();
}Checks that the numeric value falls between the given minimum and maximum:
use Rougin\Valla\Valid;
$data = array('age' => 25);
$valid = new Valid($data);
$valid->addRule('age', 'between:1,20');
if (! $valid->passed())
{
// "Age must be between 1 and 20"
echo $valid->firstError();
}Checks that the value is a boolean:
use Rougin\Valla\Valid;
$data = array('flag' => 'yes');
$valid = new Valid($data);
$valid->addRule('flag', 'boolean');
if (! $valid->passed())
{
// "Flag must be a boolean"
echo $valid->firstError();
}Checks that the array value contains only unique values:
use Rougin\Valla\Valid;
$data = array('items' => array('a', 'b', 'a'));
$valid = new Valid($data);
$valid->addRule('items', 'containsUnique');
if (! $valid->passed())
{
// "Items must contain unique values only"
echo $valid->firstError();
}Checks that the value is a valid date string:
use Rougin\Valla\Valid;
$data = array('birthday' => 'not-a-date');
$valid = new Valid($data);
$valid->addRule('birthday', 'date');
if (! $valid->passed())
{
// "Birthday must be a valid date"
echo $valid->firstError();
}Checks that the value is a date after the specified date:
use Rougin\Valla\Valid;
$data = array('date' => '2020-01-01');
$valid = new Valid($data);
$valid->addRule('date', 'dateAfter:2023-01-01');
if (! $valid->passed())
{
// "Date must be a date after 2023-01-01"
echo $valid->firstError();
}Checks that the value is a date before the specified date:
use Rougin\Valla\Valid;
$data = array('date' => '2024-01-01');
$valid = new Valid($data);
$valid->addRule('date', 'dateBefore:2023-01-01');
if (! $valid->passed())
{
// "Date must be a date before 2023-01-01"
echo $valid->firstError();
}Checks that the value matches the specified date format (e.g., Y-m-d):
use Rougin\Valla\Valid;
$data = array('date' => '01-01-2023');
$valid = new Valid($data);
$valid->addRule('date', 'dateFormat:Y-m-d');
if (! $valid->passed())
{
// "Date must be a valid date format"
echo $valid->firstError();
}Checks that the value is different from the value of another field:
use Rougin\Valla\Valid;
$data = array('a' => 'hello', 'b' => 'hello');
$valid = new Valid($data);
$valid->addRule('a', 'different:b');
if (! $valid->passed())
{
// "A must be different from b"
echo $valid->firstError();
}Checks that the value is an email address with an active domain (MX record):
use Rougin\Valla\Valid;
$data = array('email' => '[email protected]');
$valid = new Valid($data);
$valid->addRule('email', 'emailDNS');
if (! $valid->passed())
{
// "Email must be a valid email address with active domain"
echo $valid->firstError();
}Checks that the value equals the value of another field:
use Rougin\Valla\Valid;
$data = array('a' => 'hello', 'b' => 'world');
$valid = new Valid($data);
$valid->addRule('a', 'equals:b');
if (! $valid->passed())
{
// "A must be equal to b"
echo $valid->firstError();
}Checks that the value is an integer with an optional strict mode:
use Rougin\Valla\Valid;
$data = array('age' => 'abc');
$valid = new Valid($data);
$valid->addRule('age', 'integer');
if (! $valid->passed())
{
// "Age must be an integer"
echo $valid->firstError();
}Checks that the value is a valid IP address:
use Rougin\Valla\Valid;
$data = array('ip' => 'not-an-ip');
$valid = new Valid($data);
$valid->addRule('ip', 'ip');
if (! $valid->passed())
{
// "Ip must be a valid IP address"
echo $valid->firstError();
}Checks that the value is a valid IPv4 address:
use Rougin\Valla\Valid;
$data = array('ip' => '::1');
$valid = new Valid($data);
$valid->addRule('ip', 'ipv4');
if (! $valid->passed())
{
// "Ip must be a valid IPv4 address"
echo $valid->firstError();
}Checks that the value is a valid IPv6 address:
use Rougin\Valla\Valid;
$data = array('ip' => '192.168.1.1');
$valid = new Valid($data);
$valid->addRule('ip', 'ipv6');
if (! $valid->passed())
{
// "Ip must be a valid IPv6 address"
echo $valid->firstError();
}Checks that the string length matches an exact value or falls between min and max:
use Rougin\Valla\Valid;
$data = array('name' => 'Jo');
$valid = new Valid($data);
$valid->addRule('name', 'length:5');
if (! $valid->passed())
{
// "Name must be exactly 5 characters"
echo $valid->firstError();
}Checks that the string length falls between the given min and max:
use Rougin\Valla\Valid;
$data = array('name' => 'too long');
$valid = new Valid($data);
$valid->addRule('name', 'lengthBetween:1,5');
if (! $valid->passed())
{
// "Name must be between 1 and 5 characters"
echo $valid->firstError();
}Checks that the array value contains the specified item:
use Rougin\Valla\Valid;
$data = array('items' => array('a', 'b'));
$valid = new Valid($data);
$valid->addRule('items', 'listContains:c');
if (! $valid->passed())
{
// "Items must contain the specified value"
echo $valid->firstError();
}Checks that the numeric value does not exceed the given maximum:
use Rougin\Valla\Valid;
$data = array('age' => 25);
$valid = new Valid($data);
$valid->addRule('age', 'max:20');
if (! $valid->passed())
{
// "Age must not exceed 20"
echo $valid->firstError();
}Checks that the numeric value is at least the given minimum:
use Rougin\Valla\Valid;
$data = array('age' => 5);
$valid = new Valid($data);
$valid->addRule('age', 'min:10');
if (! $valid->passed())
{
// "Age must be at least 10"
echo $valid->firstError();
}Always passes regardless of the value, allowing a field to be optional:
use Rougin\Valla\Valid;
$data = array('field' => '');
$valid = new Valid($data);
$valid->addRule('field', 'optional');
// [NOTE] Optional rules always pass
$valid->passed();Checks that the value matches the given regular expression:
use Rougin\Valla\Valid;
$data = array('name' => 'hello');
$valid = new Valid($data);
$valid->addRule('name', 'regex:/^[0-9]+$/');
if (! $valid->passed())
{
// "Name does not match the required pattern"
echo $valid->firstError();
}Checks that the value is a valid slug (alpha-numeric, dashes, underscores):
use Rougin\Valla\Valid;
$data = array('slug' => 'not a slug!');
$valid = new Valid($data);
$valid->addRule('slug', 'slug');
if (! $valid->passed())
{
// "Slug must be a valid slug"
echo $valid->firstError();
}Checks that the value is a valid URL starting with http, https, or ftp:
use Rougin\Valla\Valid;
$data = array('link' => 'not-a-url');
$valid = new Valid($data);
$valid->addRule('link', 'url');
if (! $valid->passed())
{
// "Link must be a valid URL"
echo $valid->firstError();
}Checks that the value is a valid URL with an active domain (DNS record):
use Rougin\Valla\Valid;
$data = array('link' => 'http://nonexistent-domain.invalid');
$valid = new Valid($data);
$valid->addRule('link', 'urlActive');
if (! $valid->passed())
{
// "Link must be a valid URL with active domain"
echo $valid->firstError();
}As this was inspired from Valitron, migrating to Valla is simple as changing its namespace and the class name. Valla provides the same rule method for mirroring Valitron's:
-use Valitron\Validator;
+use Rougin\Valla\Valid;
-$valid = new Validator($data);
+$valid = new Valid($data);
$valid->rule('required', 'name');
$valid->rule('min', 'age', 5);
$valid->rule('required', array('name', 'email'));
if (! $valid->validate())
{
print_r($valid->errors());
}Once migrated, update the said method to addRule with its required parameters:
-$valid->rule('required', 'name');
+$valid->addRule('name', 'required');
-$valid->rule('min', 'age', 5);
+$valid->addRule('age', 'min:5');
-$valid->rule('required', array('name', 'email'));
+$valid->addRule('name', 'required');
+$valid->addRule('email', 'required');[!WARNING] The
rulemethod only accepts string rule names (e.g.'required','min:5'). Callable rules will not be supported. Kindly see Adding custom rules for how to create one.