269 lines
7.1 KiB
PHP
269 lines
7.1 KiB
PHP
<?php namespace Lucent\Core\Record;
|
|
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Lucent\Core\Data\RecordError;
|
|
use Lucent\Core\Data\RecordField;
|
|
use Lucent\Core\Data\RecordMode;
|
|
use Lucent\Core\Schema\Data\Field;
|
|
|
|
class RecordValidationModule
|
|
{
|
|
/**
|
|
* Validates a record against a schema.
|
|
*
|
|
* @param string[] $locales
|
|
* @param Field[] $schemaFields
|
|
* @param RecordField[] $recordFields
|
|
* @param Edge[] $recordEdges
|
|
* @return RecordError[]
|
|
*/
|
|
public static function validate(
|
|
array $locales,
|
|
array $schemaFields,
|
|
array $recordFields,
|
|
array $recordEdges,
|
|
): array {
|
|
$errors = [];
|
|
foreach ($schemaFields as $schemaField) {
|
|
$res = static::validateField(
|
|
"main",
|
|
$schemaField,
|
|
$recordFields,
|
|
$recordEdges,
|
|
);
|
|
$errors[] = $res;
|
|
if ($schemaField->translatable) {
|
|
foreach ($locales as $locale) {
|
|
$res = static::validateField(
|
|
$locale["id"],
|
|
$schemaField,
|
|
$recordFields,
|
|
$recordEdges,
|
|
);
|
|
$errors[] = $res;
|
|
}
|
|
}
|
|
}
|
|
|
|
return collect($errors)
|
|
->filter(fn($err) => $err !== null)
|
|
->values()
|
|
->toArray();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param Field $schemaField
|
|
* @param RecordField[] $recordFields
|
|
* @param Edge[] $recordEdges
|
|
* @return array
|
|
*/
|
|
public static function validateField(
|
|
string $locale,
|
|
Field $schemaField,
|
|
array $recordFields,
|
|
array $recordEdges,
|
|
): ?RecordError {
|
|
// General Validations
|
|
$error = static::validateRequired(
|
|
$locale,
|
|
$schemaField,
|
|
$recordFields,
|
|
$recordEdges,
|
|
);
|
|
|
|
if (!empty($error)) {
|
|
return $error;
|
|
}
|
|
// Type specific
|
|
|
|
$error = match ($schemaField->type) {
|
|
"text" => static::validateText(
|
|
$locale,
|
|
$schemaField,
|
|
$recordFields,
|
|
),
|
|
"relation" => static::validateRelation(
|
|
$locale,
|
|
$schemaField,
|
|
$recordEdges,
|
|
),
|
|
default => static::validateText(
|
|
$locale,
|
|
$schemaField,
|
|
$recordFields,
|
|
),
|
|
};
|
|
|
|
return $error;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param Field $schemaField
|
|
* @param RecordField[] $recordFields
|
|
* @param Edge[] $recordEdges
|
|
* @return ?RecordError
|
|
*/
|
|
public static function validateRequired(
|
|
string $locale,
|
|
Field $schemaField,
|
|
array $recordFields,
|
|
array $recordEdges,
|
|
): ?RecordError {
|
|
if ($schemaField->required === false) {
|
|
return null;
|
|
}
|
|
return match ($schemaField->type) {
|
|
"relation" => static::validateRequiredRelation(
|
|
$locale,
|
|
$schemaField,
|
|
$recordEdges,
|
|
),
|
|
default => static::validateRequiredField(
|
|
$locale,
|
|
$schemaField,
|
|
$recordFields,
|
|
),
|
|
};
|
|
}
|
|
|
|
private static function validateRequiredField(
|
|
string $locale,
|
|
Field $schemaField,
|
|
array $recordFields,
|
|
): ?RecordError {
|
|
$recordField = static::findField($recordFields, $schemaField, $locale);
|
|
|
|
if (empty($recordField) || empty($recordField->value)) {
|
|
return new RecordError(
|
|
$schemaField->id,
|
|
$locale,
|
|
"This field is required",
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
private static function validateRequiredRelation(
|
|
string $locale,
|
|
Field $schemaField,
|
|
array $recordEdges,
|
|
): ?RecordError {
|
|
if (
|
|
collect($recordEdges)
|
|
->where("fieldId", $schemaField->id)
|
|
->where("locale", $locale)
|
|
->where("mode", RecordMode::DRAFT)
|
|
->isEmpty()
|
|
) {
|
|
return new RecordError(
|
|
$schemaField->id,
|
|
$locale,
|
|
"This field is required",
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param Field $schemaField
|
|
* @param RecordField[] $recordFields
|
|
* @return ?RecordError
|
|
*/
|
|
public static function validateText(
|
|
string $locale,
|
|
Field $schemaField,
|
|
array $recordFields,
|
|
): ?RecordError {
|
|
$recordField = static::findField($recordFields, $schemaField, $locale);
|
|
|
|
if (empty($recordField)) {
|
|
// We have already checked for required fields so only validate existing
|
|
return null;
|
|
}
|
|
|
|
$rules = "";
|
|
if ($schemaField->props->min > 0) {
|
|
$rules = "min:" . $schemaField->props->min;
|
|
}
|
|
if ($schemaField->props->max > 0) {
|
|
$rules = "max:" . $schemaField->props->max;
|
|
}
|
|
|
|
if (empty($rules)) {
|
|
return null;
|
|
}
|
|
|
|
$validator = Validator::make(
|
|
["value" => $recordField->value],
|
|
[
|
|
"value" => $rules,
|
|
],
|
|
);
|
|
|
|
if ($validator->fails()) {
|
|
return new RecordError(
|
|
$schemaField->id,
|
|
$locale,
|
|
$validator->errors()->first(),
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param Field $schemaField
|
|
* @param Edge[] $recordEdges
|
|
* @return ?RecordError
|
|
*/
|
|
public static function validateRelation(
|
|
string $locale,
|
|
Field $schemaField,
|
|
array $recordEdges,
|
|
): ?RecordError {
|
|
$count = collect($recordEdges)
|
|
->where("fieldId", $schemaField->id)
|
|
->where("locale", $locale)
|
|
->where("mode", RecordMode::DRAFT)
|
|
->count();
|
|
|
|
if ($schemaField->props->min > 0) {
|
|
if ($count < $schemaField->props->min) {
|
|
return new RecordError(
|
|
$schemaField->id,
|
|
$locale,
|
|
"You have to have at least {$schemaField->props->min} related records",
|
|
);
|
|
}
|
|
}
|
|
if ($schemaField->props->max > 0) {
|
|
if ($count > $schemaField->props->max) {
|
|
return new RecordError(
|
|
$schemaField->id,
|
|
$locale,
|
|
"You have to have at most {$schemaField->props->max} related records",
|
|
);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static function findField(
|
|
array $recordFields,
|
|
Field $schemaField,
|
|
string $locale,
|
|
): ?RecordField {
|
|
return collect($recordFields)->first(
|
|
fn(RecordField $field) => $field->fieldId === $schemaField->id &&
|
|
$field->locale === $locale &&
|
|
$field->mode === RecordMode::DRAFT,
|
|
);
|
|
}
|
|
}
|