Validation Constraints
Overview
This article will cover how to add validation constraints to your custom code.
Constraints
Validation constraints allow developers to validate user input
Symfony Validation Constraints
The Symfony's Validation library, located in ./vendor/symfony/validator/
, contains many open source constraints. You can find the full list of constraints documented in Symphony's Validation Constraints. They are listed below for your reference.
Date Constraints |
Collection ConstraintsOther Constraints |
Sugar Constraints
Sugar contains its own set of validation constraints. These constraints extend from Symfony's validation constraints and are located in ./src/Security/Validator/Constraints
of your Sugar installation.
|
|
Custom Constraints
If you find that the existing constraints do not meet your needs, you can also create your own. These constraints exist under ./custom/src/Security/Validator/Constraints/
. The following section will outline the details. The example below will demonstrate how to create a phone number validation constraint.
The constraint file will contain your validations error message.
./custom/src/Security/Validator/Constraints/Phone.php
<?php
namespace Sugarcrm\Sugarcrm\custom\Security\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
*
* @see PhoneValidator
*
*/
class Phone extends Constraint
{
public $message = 'Phone number violation: %msg%';
}
The validator file will contain the logic to determine whether the value meets the requirements.
./custom/src/Security/Validator/Constraints/PhoneValidator.php
<?php
namespace Sugarcrm\Sugarcrm\custom\Security\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
/**
*
* Phone validator
*
*/
class PhoneValidator extends ConstraintValidator
{
/*
* Phone Pattern Examples;
* +1 12 3456789
* +1.12.3456789
*/
const PHONE_PATTERN = '/^([+]?\d+(?:[ \.]\d+)*)$/';
/**
* {@inheritdoc}
*/
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof Phone) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\Phone');
}
if (null === $value || '' === $value) {
return;
}
if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) {
throw new UnexpectedTypeException($value, 'string');
}
$value = (string) $value;
// check for allowed characters
if (!preg_match(self::PHONE_PATTERN, $value)) {
$this->context->buildViolation($constraint->message)
->setParameter('%msg%', 'invalid format')
->setInvalidValue($value)
->addViolation();
return;
}
}
}
Once the files are in place, navigate to Admin > Repairs and run a Quick Repair and Rebuild. Once completed, your constraint will be ready for use.
Using Constraints in API End Points
In this section, we will create a custom endpoint and trigger the custom phone constraint we created above. The code below will create a REST API endpoint path of /phoneCheck
:
./custom/clients/base/api/MyEndpointsApi.php
<?php
if (!defined('sugarEntry') || !sugarEntry) {
die('Not A Valid Entry Point');
}
use Sugarcrm\Sugarcrm\Security\Validator\ConstraintBuilder;
use Sugarcrm\Sugarcrm\Security\Validator\Validator;
class MyEndpointsApi extends SugarApi
{
public function registerApiRest()
{
return array(
//POST
'MyEndpointsApi' => array(
//request type
'reqType' => 'POST',
//endpoint path
'path' => array('phoneCheck'),
//endpoint variables
'pathVars' => array(''),
//method to call
'method' => 'phoneCheck',
//minimum api version
'minVersion' => 10,
//short help string to be displayed in the help documentation
'shortHelp' => 'An example of a POST endpoint to validate phone numbers',
//long help to be displayed in the help documentation
'longHelp' => 'custom/clients/base/api/help/MyEndPoint_phoneCheck_help.html',
),
);
}
/**
* Method to be used for my MyEndpointsApi/phoneCheck endpoint
*/
public function phoneCheck($api, $args)
{
$validator = Validator::getService();
/**
* Validating Phone Number
*/
$phoneContraintBuilder = new ConstraintBuilder();
$phoneConstraints = $phoneContraintBuilder->build(
array(
'Assert\Phone',
)
);
$errors = $validator->validate($args['phone'], $phoneConstraints);
if (count($errors) > 0) {
/*
* Uses a __toString method on the $errors variable which is a
* ConstraintViolationList object. This gives us a nice string
* for debugging.
*/
$errorsString = (string) $errors;
// include/api/SugarApiException.php
throw new SugarApiExceptionInvalidParameter($errorsString);
}
//custom logic
return $args;
}
}
After creating the endpoint, navigate to Admin > Repairs and run a Quick Repair and Rebuild. The API will then be ready to use.
Valid Payload - POST to /phoneCheck
The example below demonstrates a valid phone number post the /phoneCheck
endpoint.
{
phone: "+1.23.456.789"
}
Result
{
phone: "+1.23.456.789"
}
Invalid Payload - POST to /phoneCheck
The example below demonstrates an invalid phone number post the /phoneCheck
endpoint.
{
phone: "Invalid+1.23.456.789"
}
Result
{
"error":"invalid_parameter",
"error_message":"Invalid+1.23.456.789:\n Phone number violation: invalid format\n"
}