Data can be validated using the entity schemas or the ValidatorFactory
. In both cases, we use Laravel’s Validation library.
All of Laravel’s validation rules are supported except the
exist
rule.
The ValidatorFactory
class is a wrapper for Laravel’s Validator. It mimics Laravel’s make
method to create a validator.
use PKP\validation\ValidatorFactory;
$validator = ValidatorFactory::make($props, $rules);
Run the validator and retrieve errors.
if ($validator->fails()) {
$errors = $validator->errors();
}
Validate a single value.
use PKP\validation\ValidatorFactory;
$props = ['contactEmail' => $userEmail];
$rules = ['contactEmail' => ['email_or_localhost']];
$validator = ValidatorFactory::make($props, $rules);
Or validate more than one value at a time.
use PKP\validation\ValidatorFactory;
$props = [
'contactEmail' => $userEmail,
'contactUsername' => $userName,
];
$rules = [
'contactEmail' => ['email_or_localhost'],
'contactUsername' => ['alpha_num'],
];
$validator = ValidatorFactory::make($props, $rules);
The validator will return helpful errors when a value does not validate. If you want, you can customize these messages by passing an additional argument.
use PKP\validation\ValidatorFactory;
$props = ['contactUsername' => $userName];
$rules = ['contactUsername' => ['min:6', 'alpha_num']];
$messages = ['contactUsername.min' => 'The journal contact username must be at least 6 characters.'];
$validator = ValidatorFactory::make($props, $rules, $messages);
Validation rules can be defined in an entity’s schema. In this example, the numAnnouncementsHomepage
must be an integer that is not negative.
{
"numAnnouncementsHomepage": {
"type": "integer",
"validation": [
"nullable",
"min:0"
]
}
}
These rules will be applied when the entity’s Repository validates user input that contains a numAnnouncementsHomepage
prop. See the Repository Validation section below.
Every property that can be empty or null must have the nullable
validation rule assigned, or it will throw an error when it is empty.
{
"mailingAddress": {
"type": "string",
"validation": [
"nullable"
]
}
}
You never need to add the
array
,boolean
,integer
orstring
validation rules. These will be applied automatically based on thetype
property.
An entity’s Repository should implement a validate
method which validates props against the schema. Use the SchemaService
to access helper methods for working with the schema.
namespace PKP\context;
use PKP\context\Context;
use PKP\services\PKPSchemaService;
use PKP\validation\ValidatorFactory;
class Repository
{
protected PKPSchemaService $schemaService;
public function __construct(PKPSchemaService $schemaService)
{
$this->schemaService = $schemaService;
}
public function validate(?Context $context, array $props, array $allowedLocales, string $primaryLocale): array
{
$errors = [];
// Validate the $props against the entity's
// schema file
$validator = ValidatorFactory::make(
$props,
$this->schemaService->getValidationRules(PKPSchemaService::SCHEMA_CONTEXT, $allowedLocales)
);
// Validate the $props against the required fields
// in the entity's schema file
ValidatorFactory::required(
$validator,
$submission,
$this->schemaService->getRequiredProps(PKPSchemaService::SCHEMA_CONTEXT),
$this->schemaService->getMultilingualProps(PKPSchemaService::SCHEMA_CONTEXT),
$primaryLocale,
$allowedLocales
);
// Validate the $props against the locales supported
// by this context.
ValidatorFactory::allowedLocales(
$validator,
$this->schemaService->getMultilingualProps(SCHEMA_CONTEXT),
$allowedLocales
);
}
}
Some validation rules can not be described in the schema. This is the case when validation requires checking the database. For example, a context can not have a urlPath
if another context exists with that urlPath
.
In such cases, the Repository’s validate
method should be used to extend the validation check.
namespace PKP\context;
use PKP\context\Context;
use PKP\services\PKPSchemaService;
use PKP\validation\ValidatorFactory;
class Repository
{
protected PKPSchemaService $schemaService;
public function __construct(PKPSchemaService $schemaService)
{
$this->schemaService = $schemaService;
}
public function validate(?Context $context, array $props, array $allowedLocales, string $primaryLocale): array
{
$errors = [];
$validator = ValidatorFactory::make(
$props,
$this->schemaService->getValidationRules(PKPSchemaService::SCHEMA_CONTEXT, $allowedLocales)
);
...
// Ensure that a urlPath, if provided, does not already exist
$validator->after(function($validator) use ($action, $props) {
if (isset($props['urlPath']) && !$validator->errors()->get('urlPath')) {
if (/* urlPath is duplicate */) {
$validator->errors()->add('urlPath', __('admin.contexts.form.pathExists'));
}
}
});
...
if ($validator->fails()) {
$errors = $this->schemaService->formatValidationErrors($validator->errors());
}
return $errors;
}
}
The following custom validation rules can be used.
Rule | Description |
---|---|
email_or_localhost |
Extends Laravel’s email validation to accept emails @localhost . |
issn |
Require a valid ISSN. |
orcid |
Require a valid ORCID. |
currency |
Require a valid currency code. |
These rules can be applied in the schema.
{
"onlineIssn": {
"type": "string",
"validation": [
"nullable",
"issn"
]
}
}