-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
VACMS-16575: Add extra validation to allow for combination of reusabl…
…e and single page QAs. (#16838) * VACMS-16575: Add Entity event listener to va_gov_clp module. * VACMS-16575: Add new constrait for validating two paragraph fields together. * VACMS-16575: Add the requiredErrorDisplayAsMessage option. * VACMS-16575: Adds additional label properties to constraint. * VACMS-16575: Uses new labels in validation. * VACMS-16575: Adds some segment open/close commands to cypress. * VACMS-16575: Updates CLP faq segment test. * VACMS-16575: Ensures the FAQ tab is open before selecting elements inside. * VACMS-16575: Updates to make sure the dropdowns can be toggled to remove paragraphs. --------- Co-authored-by: Daniel Sasser <[email protected]>
- Loading branch information
Showing
7 changed files
with
314 additions
and
9 deletions.
There are no files selected for viewing
75 changes: 75 additions & 0 deletions
75
...ot/modules/custom/va_gov_backend/src/Plugin/Validation/Constraint/RequiredParagraphAB.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?php | ||
|
||
namespace Drupal\va_gov_backend\Plugin\Validation\Constraint; | ||
|
||
/** | ||
* Checks that paragraphs a and b have been created as required. | ||
* | ||
* @Constraint( | ||
* id = "RequiredParagraphAB", | ||
* label = @Translation("Limit Paragraph A and B", context = "Validation"), | ||
* type = "string" | ||
* ) | ||
*/ | ||
class RequiredParagraphAB extends RequiredParagraph { | ||
|
||
/** | ||
* The field name of paragraph A. | ||
* | ||
* @var string | ||
*/ | ||
public $fieldParagraphA; | ||
|
||
/** | ||
* The field name of paragraph B. | ||
* | ||
* @var string | ||
*/ | ||
public $fieldParagraphB; | ||
|
||
/** | ||
* Displays validation error as Drupal message when no field values exist. | ||
* | ||
* @var bool | ||
*/ | ||
public $requiredErrorDisplayAsMessage; | ||
|
||
/** | ||
* The plural label. | ||
* | ||
* @var string | ||
*/ | ||
public $pluralLabel; | ||
|
||
/** | ||
* The panel label. | ||
* | ||
* @var string | ||
*/ | ||
public $panelLabel; | ||
|
||
/** | ||
* The message that will be shown if the paragraph number is less than min. | ||
* | ||
* @var string | ||
* @see \Drupal\va_gov_backend\Plugin\Validation\Constraint\RequiredParagraphABValidator | ||
*/ | ||
public $tooFew = 'Add %plurlLabel. A minimum of %min %readables is required.'; | ||
|
||
/** | ||
* The message that will be shown if the paragraph number is more than max. | ||
* | ||
* @var string | ||
* @see \Drupal\va_gov_backend\Plugin\Validation\Constraint\RequiredParagraphABValidator | ||
*/ | ||
public $tooMany = 'Remove %plurlLabel. A maximum of %max %readables is allowed.'; | ||
|
||
/** | ||
* The message that will be shown if the paragraph is empty. | ||
* | ||
* @var string | ||
* @see \Drupal\va_gov_backend\Plugin\Validation\Constraint\RequiredParagraphABValidator | ||
*/ | ||
public $required = 'A minimum of %min %readables is required when the %panelLabel page segment is enabled. Disable the FAQs page segment if there are no %readables to add.'; | ||
|
||
} |
117 changes: 117 additions & 0 deletions
117
...s/custom/va_gov_backend/src/Plugin/Validation/Constraint/RequiredParagraphABValidator.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
<?php | ||
|
||
namespace Drupal\va_gov_backend\Plugin\Validation\Constraint; | ||
|
||
use Drupal\Core\Entity\FieldableEntityInterface; | ||
use Symfony\Component\Validator\Constraint; | ||
use Symfony\Component\Validator\ConstraintValidator; | ||
|
||
/** | ||
* Validates the RequiredParagraph constraint. | ||
*/ | ||
class RequiredParagraphABValidator extends ConstraintValidator { | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function validate($entity, Constraint $constraint) { | ||
assert($entity instanceof FieldableEntityInterface, 'Entity should inherit from FieldableEntityInterface.'); | ||
/** @var \Drupal\va_gov_backend\Plugin\Validation\Constraint\RequiredParagraphAB $constraint */ | ||
if (!$entity->hasField($constraint->toggle) && !$entity->hasField($constraint->fieldParagraphA) && !$entity->hasField($constraint->fieldParagraphB)) { | ||
return; | ||
} | ||
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ | ||
$panel_enabled = $entity->get($constraint->toggle)->getString(); | ||
$countA = $this->getCountForParagraphField($constraint->fieldParagraphA); | ||
$countB = $this->getCountForParagraphField($constraint->fieldParagraphB); | ||
$number = $countA + $countB; | ||
$paragraphAField = $this->getBaseField($constraint->fieldParagraphA); | ||
$paragraphBField = $this->getBaseField($constraint->fieldParagraphB); | ||
$errorPath = $countA ? $paragraphAField : $paragraphBField; | ||
if ($panel_enabled && $number < $constraint->min && $number > 0) { | ||
$this->context->buildViolation($constraint->tooFew, [ | ||
'%plurlLabel' => $constraint->pluralLabel, | ||
'%readable' => $constraint->readable, | ||
'%min' => $constraint->min, | ||
]) | ||
->atPath($errorPath) | ||
->addViolation(); | ||
} | ||
elseif ($panel_enabled && $number > $constraint->max) { | ||
$this->context->buildViolation($constraint->tooMany, [ | ||
'%plurlLabel' => $constraint->pluralLabel, | ||
'%readable' => $constraint->readable, | ||
'%max' => $constraint->max, | ||
]) | ||
->atPath($errorPath) | ||
->addViolation(); | ||
} | ||
elseif ($panel_enabled && $number === 0) { | ||
// Adding a violation in this way ensures that it is displayed even if | ||
// paragraphA and paragraphB have no values. | ||
$this->context->addViolation($constraint->required, [ | ||
'%min' => $constraint->min, | ||
'%panelLabel' => $constraint->panelLabel, | ||
'%readable' => $constraint->readable, | ||
]); | ||
} | ||
} | ||
|
||
/** | ||
* Gets the item count from a paragraph field. | ||
* | ||
* To target a nested field (a field within a paragraph), specify the $field | ||
* with a colon ":" between the parent and child field names. Only one level | ||
* of nesting is supported. eg: field_faq_group:field_faq_items. | ||
* | ||
* @param string $field | ||
* The field name to get the count from. | ||
* | ||
* @return int | ||
* The item count for the number of nested items. | ||
*/ | ||
private function getCountForParagraphField(string $field): int { | ||
$count = 0; | ||
$entity = $this->context->getRoot()->getEntity(); | ||
if (str_contains($field, ':')) { | ||
$fields = explode(":", $field); | ||
if (!empty($fields)) { | ||
[$outerParagraphField, $innerParagraphField] = $fields; | ||
if ($entity->hasField($outerParagraphField)) { | ||
/** @var \Drupal\entity_reference_revisions\Plugin\Field\FieldType\EntityReferenceRevisionsItem $item */ | ||
foreach ($entity->get($outerParagraphField) as $item) { | ||
/** @var \Drupal\paragraphs\ParagraphInterface $paragraph */ | ||
$paragraph = $item->entity; | ||
if ($paragraph->hasField($innerParagraphField)) { | ||
$count += $paragraph->get($innerParagraphField)->count(); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
$count = $entity->get($field)->count(); | ||
} | ||
return $count; | ||
} | ||
|
||
/** | ||
* Get a base field from a given paragraph field identifier. | ||
* | ||
* Since fields can contain colon's (":") to separate parent:child, this | ||
* method is used to get the base field. | ||
* | ||
* @return string | ||
* The base field name. | ||
*/ | ||
private function getBaseField(string $field): string { | ||
if (str_contains($field, ':')) { | ||
[$baseField] = explode(":", $field); | ||
return $baseField; | ||
} | ||
else { | ||
return $field; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
docroot/modules/custom/va_gov_clp/src/EventSubscriber/EntityEventSubscriber.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
namespace Drupal\va_gov_clp\EventSubscriber; | ||
|
||
use Drupal\Core\Entity\EntityTypeInterface; | ||
use Drupal\core_event_dispatcher\EntityHookEvents; | ||
use Drupal\core_event_dispatcher\Event\Entity\EntityTypeAlterEvent; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
|
||
/** | ||
* VA.gov Campaign Landing Page Event Subscriber. | ||
*/ | ||
class EntityEventSubscriber implements EventSubscriberInterface { | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function getSubscribedEvents(): array { | ||
return [ | ||
EntityHookEvents::ENTITY_TYPE_ALTER => 'entityTypeAlter', | ||
]; | ||
} | ||
|
||
/** | ||
* Equivalent of hook_entity_type_alter(). | ||
* | ||
* @param \Drupal\core_event_dispatcher\Event\Entity\EntityTypeAlterEvent $event | ||
* The event for entityTypeAlter. | ||
*/ | ||
public function entityTypeAlter(EntityTypeAlterEvent $event): void { | ||
$entity_types = $event->getEntityTypes(); | ||
if (!empty($entity_types['node'])) { | ||
$nodeEntityType = $entity_types['node']; | ||
$this->addConstraintsToClp($nodeEntityType); | ||
} | ||
} | ||
|
||
/** | ||
* Adds constraints to Campaign Landing Page Nodes. | ||
* | ||
* @param \Drupal\Core\Entity\EntityTypeInterface $entityType | ||
* The entity type. | ||
*/ | ||
public function addConstraintsToClp(EntityTypeInterface $entityType): void { | ||
$entityType->addConstraint('RequiredParagraphAB', [ | ||
'toggle' => 'field_clp_faq_panel', | ||
'readable' => 'Q&A', | ||
'pluralLabel' => 'Page-Specific or Reusable Q&As', | ||
'panelLabel' => 'FAQ', | ||
'fieldParagraphA' => 'field_clp_faq_paragraphs', | ||
'fieldParagraphB' => 'field_clp_reusable_q_a:field_q_as', | ||
'requiredErrorDisplayAsMessage' => TRUE, | ||
'min' => 3, | ||
'max' => 10, | ||
]); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
services: | ||
va_gov_clp.entity_event_subscriber: | ||
class: Drupal\va_gov_clp\EventSubscriber\EntityEventSubscriber | ||
tags: | ||
- { name: event_subscriber } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters