Yes, use hook_entity_bundle_field_info_alter and when you add a constraint to the field (and not to a item or property), your constraint gets the entire field item list, so you can check how many items you have of which type, see FieldConfigInterface::addConstraint:
function mymodule_entity_bundle_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type, $bundle) { if ($entity_type->id() == 'node' && $bundle == 'page') { $fields['field_paragraph']->addConstraint('MymoduleParagraphTypes'); } }
Example for a constraint restricting the field to four paragraph items of a specific type:
public function validate($items, Constraint $constraint) { $paragraphs = array_filter($items->referencedEntities(), function ($paragraph) { return $paragraph->bundle() === 'image'; }); if (!empty($paragraphs) && count($paragraphs) != 4) { $this->context->addViolation($constraint->errorMessage); } }
You can generate the constraint with the Drush command:
drush generate plugin-constraint
Edit: If you need to check field values inside of the paragraphs then use $item->entity. See How to validate a paragraph field?