Trying to figure out custom validation with constraints, but no luck yet. Right now, my form posts content and gives no errors when form is filled out incorrectly.

(Please avoid suggesting validation modules -- I know those exist.)

Maybe somebody knows what I'm missing? Or maybe it's done different when I'm doing specific fields? Or maybe this isn't how to do it on a back-end content submission form? Here's what I have so far:

I built a module called "custom_validation." It contains custom_validation.module:

  <?php

/**
 * @file
 */

/**
 * Implements hook_entity_type_alter().
 */
function custom_validation_entity_type_alter(array &$entity_types) {

  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */

  $entity = $entity_types['node'];
  $entity->addConstraint('BlogpostError');
}

Then, in subfolder src/Plugin/Validation/Constraint, I've got two files. BlogpostErrorConstraint.php contains:

namespace Drupal\custom_validation\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;

/**
 * Prevent article creation if errors.
 *
 * @Constraint(
 *   id = "BlogpostError",
 *   label = @Translation("Added blog post category instead of story author in author field", context = "Validation"),
 *   type = "string"
 * )
 */
class BlogpostErrorConstraint extends Constraint {

  /**
   * {@inheritdoc}
   */      

    public $notByline = '%value is a blog post type. Please add a byline';

    public $noImageSource = 'need image source';

}

BlogpostErrorConstraintValidator.php contains:

namespace Drupal\custom_validation\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

/**
 * Validates the BlogpostError constraint.
 */
class BlogpostErrorConstraintValidator extends ConstraintValidator {

  /**
   * {@inheritdoc}
   */
  public function validate($items, Constraint $constraint) {

    if (!isset($items)) {
      return;
    }

    // limit this to 'blog entries' content type
    if ($items->bundle() == 'blog_entry') {

      // now loop through each field...
      foreach ($items as $delta => $item) {
        // an array of phrases we don't want in the field
        $bad_bylines = [];
        array_push($bad_bylines,"Value one","value two","abc123");

        // adding validation...
        //byline field
        if (in_array($item['field_byline'], $bad_bylines)) {
           // not sure of syntax here
           $this->context->addViolation($constraint->notByline, ['%value' => $item->value]);
        }

        //main image source field...
        if ($item['field_main_image_source'] == '') {
           $this->context->addViolation($constraint->noImageSource, ['%value' => $item->value]);
        }
      }

    } 

  } 

}
  • Is that a typo, or does your file's name start with a lowercase 'b'? Talking about blogpostErrorConstraint.php – Stefanos Petrakis Dec 4 at 22:14
  • just a typo. the file is BlogpostErrorConstraint.php - I just corrected it – turpentyne Dec 4 at 22:19
  • All right. Is the code you have in the validate() function complete or is there more to it? – Stefanos Petrakis Dec 4 at 22:25
  • Yes, that's complete. It's just a starting point as I try and figure out how it works. – turpentyne Dec 4 at 22:32
  • Well, that won't really work that well and it's not even a problem of implementing the Validation API. The code has several problems and needs to be revised, e.g. $items comes out of nowhere, if ($field['field_main_image_source'] = '') performs an assignment and not a comparison, and so on. Try to revise and update your question once the code is in order and it does come down to the Validation API. So far as I have tried your code locally, it does hook into the Validation API properly. – Stefanos Petrakis Dec 4 at 22:37

Turns out I was trying too hard. Typical beginner mistake. :) I threw out the code above, and started from scratch. I replaced everything with the code examples in this tutorial: https://www.drupal.org/docs/8/api/entity-validation-api/providing-a-custom-validation-constraint

Within the validator, I replaced if (!is_int($item->value)) with if ($item->value == "Value one" || "value two"), to get what I needed to validate on. Then I modified the variable names, field names and error messages to suit my needs. It only handles one field, but gets me closer to what I need.

  • But $item->value = "Value one" is still an assignment... you'd want if ($item->value == "Value one" || $item->value == "value two") to do a comparison. – Kevin Dec 5 at 18:03
  • ok... just tested with that correction, and it's working. I modified the text above to reflect the correction. – turpentyne Dec 5 at 18:18
  • For the if statement $item->value == "Value one" || "value two" is equivalent to TRUE. – kiamlaluno Dec 5 at 19:02
  • Correct. I want it to be true if it's value one or value two. If it's not, then false. There's probably a better way of doing this. In the code I first posted, I was trying to see if the field value was in an array of unwanted values, else true. The above is working for me as the same thing, without an array to check, and I didn't want to 'rock the boat' for the moment. – turpentyne Dec 5 at 19:10
  • Isn't that just saying "OR [anything]"? It's true so long as its not literally FALSE. If you are looking for value and type, use === instead of ==. – Kevin Dec 5 at 19:43

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.