diff --git a/ext/afform/core/Civi/Afform/Event/AfformBaseEvent.php b/ext/afform/core/Civi/Afform/Event/AfformBaseEvent.php index 805cb5b4dde9..d25c8068e1ee 100644 --- a/ext/afform/core/Civi/Afform/Event/AfformBaseEvent.php +++ b/ext/afform/core/Civi/Afform/Event/AfformBaseEvent.php @@ -3,23 +3,23 @@ use Symfony\Component\EventDispatcher\Event; -class AfformBaseEvent extends Event { +abstract class AfformBaseEvent extends Event { /** * @var array * The main 'Afform' record/configuration. */ - public $afform; + private $afform; /** * @var \Civi\Afform\FormDataModel */ - public $formDataModel; + private $formDataModel; /** * @var \Civi\Api4\Generic\AbstractAction */ - public $apiRequest; + private $apiRequest; /** * AfformBaseEvent constructor. @@ -33,6 +33,17 @@ public function __construct(array $afform, \Civi\Afform\FormDataModel $formDataM $this->apiRequest = $apiRequest; } + public function getAfform(): array { + return $this->afform; + } + + /** + * @return \Civi\Afform\FormDataModel + */ + public function getFormDataModel(): \Civi\Afform\FormDataModel { + return $this->formDataModel; + } + /** * @return \Civi\Api4\Generic\AbstractAction */ diff --git a/ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php b/ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php index 4aa1fa4f051c..ff2ddb9b1f68 100644 --- a/ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php +++ b/ext/afform/core/Civi/Afform/Event/AfformSubmitEvent.php @@ -8,41 +8,45 @@ * Class AfformSubmitEvent * @package Civi\Afform\Event * - * Handle submission of an "". - * Listeners ought to take any recognized items from `entityValues`, handle - * them, and remove them. + * Handle submission of an "" entity. * - * NOTE: I'm on the fence about whether to expose the arrays or more targeted - * methods. For the moment, this is only expected to be used internally, - * so KISS. + * The default handler of this event is `Submit::processGenericEntity` + * If special processing for an entity type is desired, add a new listener with a higher priority + * than 0, and either manipulate the $records and allow the default listener to perform the save, + * or fully process the save and cancel event propagation to bypass `processGenericEntity`. */ class AfformSubmitEvent extends AfformBaseEvent { /** + * One or more records to be saved for this entity. + * (because of `` all entities are treated as if they may be multi) * @var array - * Values to be saved for this entity - * */ - public $values; + public $records; /** * @var string * entityType */ - public $entityType; + private $entityType; /** * @var string * entityName e.g. Individual1, Activity1, */ - public $entityName; + private $entityName; /** + * Ids of each saved entity. + * + * Each key in the array corresponds to the name of an entity, + * and the value is an array of ids + * (because of `` all entities are treated as if they may be multi) + * E.g. $entityIds['Individual1'] = [1]; + * * @var array - * List of Submitted Entities and their matching ids - * $entityIds['Individual1'] = 1; */ - public $entityIds; + private $entityIds; /** * AfformSubmitEvent constructor. @@ -55,36 +59,46 @@ class AfformSubmitEvent extends AfformBaseEvent { * @param string $entityName * @param array $entityIds */ - public function __construct(array $afform, FormDataModel $formDataModel, Submit $apiRequest, $values, string $entityType, string $entityName, array &$entityIds) { + public function __construct(array $afform, FormDataModel $formDataModel, Submit $apiRequest, &$values, string $entityType, string $entityName, array &$entityIds) { parent::__construct($afform, $formDataModel, $apiRequest); - $this->values = $values; + $this->records =& $values; $this->entityType = $entityType; $this->entityName = $entityName; - $this->entityIds = $entityIds; + $this->entityIds =& $entityIds; } /** - * Set the entity type associated with this event - * @param string $entityType + * Get the entity type associated with this event + * @return string */ - public function setEntityType(string $entityType): void { - $this->entityType = $entityType; + public function getEntityType(): string { + return $this->entityType; } /** - * Set the values associated with this event - * @param array $values + * Get the entity name associated with this event + * @return string */ - public function setValues(array $values): void { - $this->values = $values; + public function getEntityName(): string { + return $this->entityName; } /** - * Set the entity name associated with this event - * @param string $entityName + * @return callable + * API4-style */ - public function setEntityName(string $entityName): void { - $this->entityName = $entityName; + public function getSecureApi4() { + return $this->getFormDataModel()->getSecureApi4($this->entityName); + } + + /** + * @param $index + * @param $entityId + * @return $this + */ + public function setEntityId($index, $entityId) { + $this->entityIds[$this->entityName][$index] = $entityId; + return $this; } } diff --git a/ext/afform/core/Civi/Afform/FormDataModel.php b/ext/afform/core/Civi/Afform/FormDataModel.php index c31c7de2beb1..82b78fb18980 100644 --- a/ext/afform/core/Civi/Afform/FormDataModel.php +++ b/ext/afform/core/Civi/Afform/FormDataModel.php @@ -161,11 +161,18 @@ protected function parseFields($nodes, $entity = NULL, $join = NULL) { } /** - * @return array + * @return array[] * Ex: $entities['spouse']['type'] = 'Contact'; */ public function getEntities() { return $this->entities; } + /** + * @return array + */ + public function getEntity($entityName) { + return $this->entities[$entityName] ?? NULL; + } + } diff --git a/ext/afform/core/Civi/Afform/Utils.php b/ext/afform/core/Civi/Afform/Utils.php index c1fe8fff1d91..c183ae679425 100644 --- a/ext/afform/core/Civi/Afform/Utils.php +++ b/ext/afform/core/Civi/Afform/Utils.php @@ -19,38 +19,34 @@ */ class Utils { + /** + * Sorts entities according to references to each other + * + * Returns a list of entity names in order of when they should be processed, + * so that an entity being referenced is saved before the entity referencing it. + * + * @param $formEntities + * @param $entityValues + * @return string[] + */ public static function getEntityWeights($formEntities, $entityValues) { - $entityWeights = $entityMapping = $entitiesToBeProcessed = []; + $sorter = new \MJS\TopSort\Implementations\FixedArraySort(); + foreach ($formEntities as $entityName => $entity) { - $entityWeights[$entityName] = 1; - $entityMapping[$entityName] = $entity['type']; - foreach ($entityValues[$entity['type']][$entityName] as $record) { - foreach ($record as $index => $vals) { - foreach ($vals as $field => $value) { - if (array_key_exists($value, $entityWeights)) { - $entityWeights[$entityName] = max((int) $entityWeights[$entityName], (int) ($entityWeights[$value] + 1)); - } - else { - if (!array_key_exists($value, $entitiesToBeProcessed)) { - $entitiesToBeProcessed[$value] = [$entityName]; - } - else { - $entitiesToBeProcessed[$value][] = $entityName; - } + $references = []; + foreach ($entityValues[$entityName] as $record) { + foreach ($record['fields'] as $fieldName => $fieldValue) { + foreach ((array) $fieldValue as $value) { + if (array_key_exists($value, $formEntities) && $value !== $entityName) { + $references[$value] = $value; } } } } - // If any other entities have been processed that relied on this entity lets now alter their weights based on this entity's weight. - if (array_key_exists($entityName, $entitiesToBeProcessed)) { - foreach ($entitiesToBeProcessed[$entityName] as $dependentEntity) { - $entityWeights[$dependentEntity] = max((int) $entityWeights[$dependentEntity], (int) ($entityWeights[$entityName] + 1)); - } - } + $sorter->add($entityName, $references); } - // Numerically sort the weights now that we have them set - asort($entityWeights); - return $entityWeights; + // Return the list of entities ordered by weight + return $sorter->sort(); } } diff --git a/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php b/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php index 1682f9bf5b54..f22237552376 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/AbstractProcessor.php @@ -22,7 +22,7 @@ abstract class AbstractProcessor extends \Civi\Api4\Generic\AbstractAction { * Arguments present when loading the form * @var array */ - protected $args; + protected $args = []; protected $_afform; @@ -72,9 +72,9 @@ abstract protected function processForm(); */ protected static function getJoinWhereClause($mainEntityName, $joinEntityName, $mainEntityId) { $params = []; - if (self::fieldExists($joinEntityName, 'entity_id')) { + if (self::getEntityField($joinEntityName, 'entity_id')) { $params[] = ['entity_id', '=', $mainEntityId]; - if (self::fieldExists($joinEntityName, 'entity_table')) { + if (self::getEntityField($joinEntityName, 'entity_table')) { $params[] = ['entity_table', '=', 'civicrm_' . \CRM_Core_DAO_AllCoreTables::convertEntityNameToLower($mainEntityName)]; } } @@ -86,24 +86,54 @@ protected static function getJoinWhereClause($mainEntityName, $joinEntityName, $ } /** - * Check if a field exists for a given entity + * Get field definition for a given entity * * @param $entityName * @param $fieldName - * @return bool + * @return array|null * @throws \API_Exception */ - public static function fieldExists($entityName, $fieldName) { - if (empty(\Civi::$statics[__CLASS__][__FUNCTION__][$entityName])) { + public static function getEntityField($entityName, $fieldName) { + if (!isset(\Civi::$statics[__CLASS__][__FUNCTION__][$entityName])) { $fields = civicrm_api4($entityName, 'getFields', [ 'checkPermissions' => FALSE, 'action' => 'create', - 'select' => ['name'], - 'includeCustom' => FALSE, ]); - \Civi::$statics[__CLASS__][__FUNCTION__][$entityName] = $fields->column('name'); + \Civi::$statics[__CLASS__][__FUNCTION__][$entityName] = $fields->indexBy('name'); } - return in_array($fieldName, \Civi::$statics[__CLASS__][__FUNCTION__][$entityName]); + return \Civi::$statics[__CLASS__][__FUNCTION__][$entityName][$fieldName] ?? NULL; + } + + /** + * @return array + */ + public function getArgs():array { + return $this->args; + } + + /** + * @param array $args + * @return $this + */ + public function setArgs(array $args) { + $this->args = $args; + return $this; + } + + /** + * @return string + */ + public function getName():string { + return $this->name; + } + + /** + * @param string $name + * @return $this + */ + public function setName(string $name) { + $this->name = $name; + return $this; } } diff --git a/ext/afform/core/Civi/Api4/Action/Afform/Prefill.php b/ext/afform/core/Civi/Api4/Action/Afform/Prefill.php index 0b69d395763c..8fb0c8ed8ebb 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/Prefill.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/Prefill.php @@ -48,7 +48,7 @@ private function loadEntity($entity, $id) { 'where' => self::getJoinWhereClause($entity['type'], $joinEntity, $item['id']), 'limit' => !empty($join['af-repeat']) ? $join['max'] ?? 0 : 1, 'select' => array_keys($join['fields']), - 'orderBy' => self::fieldExists($joinEntity, 'is_primary') ? ['is_primary' => 'DESC'] : [], + 'orderBy' => self::getEntityField($joinEntity, 'is_primary') ? ['is_primary' => 'DESC'] : [], ]); } $this->_data[$entity['name']][] = $data; diff --git a/ext/afform/core/Civi/Api4/Action/Afform/Submit.php b/ext/afform/core/Civi/Api4/Action/Afform/Submit.php index 56e0768f451d..5bdab3bb7c22 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/Submit.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/Submit.php @@ -19,51 +19,42 @@ class Submit extends AbstractProcessor { */ protected $values; + /** + * Ids of each saved entity. + * + * Each key in the array corresponds to the name of an entity, + * and the value is an array of ids + * (because of `` all entities are treated as if they may be multi) + * E.g. $entityIds['Individual1'] = [1]; + * + * @var array + */ + private $entityIds = []; + protected function processForm() { - $entityValues = $entityIds = $entityMapping = $entityRefFields = []; + $entityValues = []; foreach ($this->_formDataModel->getEntities() as $entityName => $entity) { - $entityIds[$entityName] = NULL; - $entityMapping[$entityName] = $entity['type']; - $entityFields = \civicrm_api4($entity['type'], 'getFields', ['checkPermissions' => FALSE]); - foreach ($entityFields as $field) { - if ($field['input_type'] === 'EntityRef') { - $entityRefFields[] = $field['name']; - } - } + $this->entityIds[$entityName] = []; + $entityValues[$entityName] = []; + + // Gather submitted field values from $values['fields'] and sub-entities from $values['joins'] foreach ($this->values[$entityName] ?? [] as $values) { - $entityValues[$entity['type']][$entityName][] = $values + ['fields' => []]; - // Predetermined values override submitted values - if (!empty($entity['data'])) { - foreach ($entityValues[$entity['type']][$entityName] as $index => $vals) { - $entityValues[$entity['type']][$entityName][$index]['fields'] = $entity['data'] + $vals['fields']; - } - } + $values['fields'] = $values['fields'] ?? []; + $entityValues[$entityName][] = $values; } - } - $entityWeights = \Civi\Afform\Utils::getEntityWeights($this->_formDataModel->getEntities(), $entityValues); - $event = new AfformSubmitEvent($this->_afform, $this->_formDataModel, $this, [], '', '', $entityIds); - foreach ($entityWeights as $entity => $weight) { - $eValues = $entityValues[$entityMapping[$entity]][$entity]; - // Replace Entity reference fields that reference other form based entities with their created ids. - foreach ($eValues as $key => $record) { - foreach ($record as $k => $v) { - foreach ($v as $field => $value) { - if (array_key_exists($value, $event->entityIds) && !empty($event->entityIds[$value]) && in_array($field, $entityRefFields, TRUE)) { - $eValues[$key][$k][$field] = $event->entityIds[$value]; - } - } + // Predetermined values override submitted values + if (!empty($entity['data'])) { + foreach ($entityValues[$entityName] as $index => $vals) { + $entityValues[$entityName][$index]['fields'] = $entity['data'] + $vals['fields']; } - $event->setValues($eValues[$key]); - $event->setEntityName($entity); - $event->setEntityType($entityMapping[$entity]); - \Civi::dispatcher()->dispatch(self::EVENT_NAME, $event); } - unset($entityValues[$entityMapping[$entity]][$entity]); } - foreach ($entityValues as $entityType => $entities) { - if (!empty($entities)) { - throw new \API_Exception(sprintf("Failed to process entities (type=%s; name=%s)", $entityType, implode(',', array_keys($entities)))); - } + $entityWeights = \Civi\Afform\Utils::getEntityWeights($this->_formDataModel->getEntities(), $entityValues); + foreach ($entityWeights as $entityName) { + $entityType = $this->_formDataModel->getEntity($entityName)['type']; + $records = $this->replaceReferences($entityName, $entityValues[$entityName]); + $event = new AfformSubmitEvent($this->_afform, $this->_formDataModel, $this, $records, $entityType, $entityName, $this->entityIds); + \Civi::dispatcher()->dispatch(self::EVENT_NAME, $event); } // What should I return? @@ -71,19 +62,30 @@ protected function processForm() { } /** - * @param \Civi\Afform\Event\AfformSubmitEvent $event - * @throws \API_Exception - * @see afform_civicrm_config + * Replace Entity reference fields with the id of the referenced entity. + * @param string $entityName + * @param $records */ - public static function processContacts(AfformSubmitEvent $event) { - if ($event->entityType !== 'Contact') { - return; + private function replaceReferences($entityName, $records) { + $entityNames = array_diff(array_keys($this->entityIds), [$entityName]); + $entityType = $this->_formDataModel->getEntity($entityName)['type']; + foreach ($records as $key => $record) { + foreach ($record['fields'] as $field => $value) { + if (array_intersect($entityNames, (array) $value) && $this->getEntityField($entityType, $field)['input_type'] === 'EntityRef') { + if (is_array($value)) { + foreach ($value as $i => $val) { + if (in_array($val, $entityNames, TRUE)) { + $records[$key]['fields'][$field][$i] = $this->entityIds[$val][0]; + } + } + } + else { + $records[$key]['fields'][$field] = $this->entityIds[$value][0]; + } + } + } } - $entityName = $event->entityName; - $api4 = $event->formDataModel->getSecureApi4($entityName); - $saved = $api4('Contact', 'save', ['records' => [$event->values['fields']]])->first(); - $event->entityIds[$entityName] = $saved['id']; - self::saveJoins('Contact', $saved['id'], $event->values['joins'] ?? []); + return $records; } /** @@ -92,16 +94,29 @@ public static function processContacts(AfformSubmitEvent $event) { * @see afform_civicrm_config */ public static function processGenericEntity(AfformSubmitEvent $event) { - if ($event->entityType === 'Contact') { - return; + $api4 = $event->getSecureApi4(); + foreach ($event->records as $index => $record) { + try { + $saved = $api4($event->getEntityType(), 'save', ['records' => [$record['fields']]])->first(); + $event->setEntityId($index, $saved['id']); + self::saveJoins($event->getEntityType(), $saved['id'], $record['joins'] ?? []); + } + catch (\API_Exception $e) { + // What to do here? Sometimes we should silently ignore errors, e.g. an optional entity + // intentionally left blank. Other times it's a real error the user should know about. + } } - $entityName = $event->entityName; - $api4 = $event->formDataModel->getSecureApi4($event->entityName); - $saved = $api4($event->entityType, 'save', ['records' => [$event->values['fields']]])->first(); - $event->entityIds[$entityName] = $saved['id']; - self::saveJoins($event->entityType, $saved['id'], $event->values['joins'] ?? []); } + /** + * This saves joins (sub-entities) such as Email, Address, Phone, etc. + * + * @param $mainEntityName + * @param $entityId + * @param $joins + * @throws \API_Exception + * @throws \Civi\API\Exception\NotImplementedException + */ protected static function saveJoins($mainEntityName, $entityId, $joins) { foreach ($joins as $joinEntityName => $join) { $values = self::filterEmptyJoins($joinEntityName, $join); @@ -161,4 +176,20 @@ private static function filterEmptyJoins($entity, $join) { }); } + /** + * @return array + */ + public function getValues():array { + return $this->values; + } + + /** + * @param array $values + * @return $this + */ + public function setValues(array $values) { + $this->values = $values; + return $this; + } + } diff --git a/ext/afform/core/afform.php b/ext/afform/core/afform.php index 5529e0bdbe1e..4cf0d6cf3946 100644 --- a/ext/afform/core/afform.php +++ b/ext/afform/core/afform.php @@ -50,8 +50,7 @@ function afform_civicrm_config(&$config) { Civi::$statics[__FUNCTION__] = 1; $dispatcher = Civi::dispatcher(); - $dispatcher->addListener(Submit::EVENT_NAME, [Submit::class, 'processContacts'], 500); - $dispatcher->addListener(Submit::EVENT_NAME, [Submit::class, 'processGenericEntity'], -1000); + $dispatcher->addListener(Submit::EVENT_NAME, [Submit::class, 'processGenericEntity'], 0); $dispatcher->addListener('hook_civicrm_angularModules', ['\Civi\Afform\AngularDependencyMapper', 'autoReq'], -1000); $dispatcher->addListener('hook_civicrm_alterAngular', ['\Civi\Afform\AfformMetadataInjector', 'preprocess']); $dispatcher->addListener('hook_civicrm_check', ['\Civi\Afform\StatusChecks', 'hook_civicrm_check']); diff --git a/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php b/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php index 6eb2609e9811..655f01f32bae 100644 --- a/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php +++ b/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php @@ -18,7 +18,6 @@ class CRM_Afform_UtilTest extends \PHPUnit\Framework\TestCase implements Headles public function setUpHeadless() { return \Civi\Test::headless() ->installMe(__DIR__) - ->install(version_compare(CRM_Utils_System::version(), '5.19.alpha1', '<') ? ['org.civicrm.api4'] : []) ->apply(); } @@ -69,12 +68,12 @@ public function formEntityWeightExampls() { 'Activity1' => ['type' => 'Activity', ['fields' => ['source_contact_id']]], ], [ - 'Contact' => ['Individual1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]]], - 'Activity' => ['Activity1' => [['fields' => ['source_contact_id' => 'Individual1']]]], + 'Individual1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]], + 'Activity1' => [['fields' => ['source_contact_id' => 'Individual1']]], ], [ - 'Individual1' => 1, - 'Activity1' => 2, + 'Individual1', + 'Activity1', ], ]; $exs[] = [ @@ -84,14 +83,14 @@ public function formEntityWeightExampls() { 'LocBlock1' => ['type' => 'LocBlock', ['fields' => ['event_id']]], ], [ - 'Contact' => ['Individual1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]]], - 'Event' => ['Event1' => [['fields' => ['created_id' => 'Individual1']]]], - 'LocBlock' => ['LocBlock1' => [['fields' => ['event_id' => 'Event1']]]], + 'Individual1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]], + 'Event1' => [['fields' => ['created_id' => 'Individual1']]], + 'LocBlock1' => [['fields' => ['event_id' => 'Event1']]], ], [ - 'Individual1' => 1, - 'Event1' => 2, - 'LocBlock1' => 3, + 'Individual1', + 'Event1', + 'LocBlock1', ], ]; $exs[] = [ @@ -101,14 +100,37 @@ public function formEntityWeightExampls() { 'Event1' => ['type' => 'Event', ['fields' => ['created_id']]], ], [ - 'Contact' => ['Individual1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]]], - 'LocBlock' => ['LocBlock1' => [['fields' => ['event_id' => 'Event1']]]], - 'Event' => ['Event1' => [['fields' => ['created_id' => 'Individual1']]]], + 'Individual1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]], + 'LocBlock1' => [['fields' => ['event_id' => 'Event1']]], + 'Event1' => [['fields' => ['created_id' => 'Individual1']]], ], [ - 'Individual1' => 1, - 'Event1' => 2, - 'LocBlock1' => 3, + 'Individual1', + 'Event1', + 'LocBlock1', + ], + ]; + $exs[] = [ + [ + 'Activity1' => ['type' => 'Activity', ['fields' => ['source_contact_id']]], + 'Individual1' => ['type' => 'Contact', ['fields' => ['first_name', 'last_name', 'employer_id']]], + 'Individual2' => ['type' => 'Contact', ['fields' => ['first_name', 'last_name', 'employer_id']]], + 'Organization1' => ['type' => 'Contact', ['fields' => ['organization_name']]], + ], + [ + 'Activity1' => [['fields' => ['source_contact_id' => 'Individual1', 'target_contact_id' => ['Individual2']]]], + 'Individual1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact', 'employer_id' => 'Organization1']]], + 'Individual2' => [ + ['fields' => ['first_name' => 'Test2', 'last_name' => 'Contact']], + ['fields' => ['first_name' => 'Test3', 'last_name' => 'Contact', 'employer_id' => 'Organization1']], + ], + 'Organization1' => [['fields' => ['first_name' => 'Test', 'last_name' => 'Contact']]], + ], + [ + 'Organization1', + 'Individual1', + 'Individual2', + 'Activity1', ], ]; return $exs; diff --git a/ext/afform/mock/tests/phpunit/api/v4/AfformUsageTest.php b/ext/afform/mock/tests/phpunit/api/v4/AfformUsageTest.php index fb5219743edf..220a0fe9b6bb 100644 --- a/ext/afform/mock/tests/phpunit/api/v4/AfformUsageTest.php +++ b/ext/afform/mock/tests/phpunit/api/v4/AfformUsageTest.php @@ -29,8 +29,7 @@ public static function setUpBeforeClass(): void {
- - +
Activity 1 @@ -42,12 +41,14 @@ public static function setUpBeforeClass(): void { public function setUp(): void { parent::setUp(); + Civi\Api4\Afform::revert(FALSE) + ->addWhere('type', '=', 'block') + ->execute(); $this->formName = 'mock' . rand(0, 100000); } public function tearDown(): void { - Civi\Api4\Afform::revert() - ->setCheckPermissions(FALSE) + Civi\Api4\Afform::revert(FALSE) ->addWhere('name', '=', $this->formName) ->execute(); parent::tearDown(); @@ -64,7 +65,6 @@ public function testAboutMeAllowed(): void { $prefill = Civi\Api4\Afform::prefill() ->setName($this->formName) - ->setArgs([]) ->execute() ->indexBy('name'); $this->assertEquals('Logged In', $prefill['me']['values'][0]['fields']['first_name']); @@ -76,57 +76,14 @@ public function testAboutMeAllowed(): void { Civi\Api4\Afform::submit() ->setName($this->formName) - ->setArgs([]) ->setValues(['me' => $me]) ->execute(); - $contact = Civi\Api4\Contact::get()->setCheckPermissions(FALSE)->addWhere('id', '=', $cid)->execute()->first(); + $contact = Civi\Api4\Contact::get(FALSE)->addWhere('id', '=', $cid)->execute()->first(); $this->assertEquals('Firsty', $contact['first_name']); $this->assertEquals('Lasty', $contact['last_name']); } - public function testRegisterSite(): void { - $this->useValues([ - 'layout' => self::$layouts['registerSite'], - 'permission' => CRM_Core_Permission::ALWAYS_ALLOW_PERMISSION, - ]); - - CRM_Core_Config::singleton()->userPermissionTemp = new CRM_Core_Permission_Temp(); - - $values = [ - 'Individual1' => [ - [ - 'fields' => [ - 'first_name' => 'Test Register', - 'last_name' => 'site', - 'source' => 'test source', - ], - ], - ], - 'Activity1' => [ - [ - 'fields' => [ - 'subject' => 'Test Register Site Form Submission', - ], - ], - ], - ]; - Civi\Api4\Afform::submit() - ->setName($this->formName) - ->setArgs([]) - ->setValues($values) - ->execute(); - // Check that Activity was submitted correctly. - $activity = \Civi\Api4\Activity::get()->setCheckPermissions(FALSE)->execute()->first(); - $this->assertEquals('Test Register Site Form Submission', $activity['subject']); - $contact = \Civi\Api4\Contact::get()->addWhere('first_name', '=', 'Test Register')->execute()->first(); - $this->assertEquals('site', $contact['last_name']); - // Check that the data overrides form submsision - $this->assertEquals('Register A site', $contact['source']); - // Check that the contact and the activity were correctly linked up as per the form. - $this->callAPISuccess('ActivityContact', 'get', ['contact_id' => $contact['id'], 'activity_id' => $activity['id']]); - } - public function testCheckEntityReferenceFieldsReplacement(): void { $this->useValues([ 'layout' => self::$layouts['registerSite'], @@ -134,12 +91,13 @@ public function testCheckEntityReferenceFieldsReplacement(): void { ]); CRM_Core_Config::singleton()->userPermissionTemp = new CRM_Core_Permission_Temp(); + $firstName = uniqid(__FUNCTION__); $values = [ 'Individual1' => [ [ 'fields' => [ - 'first_name' => 'Test Register Individual1', + 'first_name' => $firstName, 'last_name' => 'site', 'source' => 'test source', ], @@ -148,25 +106,24 @@ public function testCheckEntityReferenceFieldsReplacement(): void { 'Activity1' => [ [ 'fields' => [ - 'subject' => 'Test Register Site Form Submission Individual1', + 'subject' => 'Individual1', ], ], ], ]; Civi\Api4\Afform::submit() ->setName($this->formName) - ->setArgs([]) ->setValues($values) ->execute(); // Check that Activity was submitted correctly. - $activity = \Civi\Api4\Activity::get()->setCheckPermissions(FALSE)->execute()->first(); - $this->assertEquals('Test Register Site Form Submission', $activity['subject']); - $contact = \Civi\Api4\Contact::get()->addWhere('first_name', '=', 'Test Register')->execute()->first(); + $activity = \Civi\Api4\Activity::get(FALSE)->execute()->first(); + $this->assertEquals('Individual1', $activity['subject']); + $contact = \Civi\Api4\Contact::get()->addWhere('first_name', '=', $firstName)->execute()->first(); $this->assertEquals('site', $contact['last_name']); // Check that the data overrides form submsision - $this->assertEquals('Register A site Individual1', $contact['source']); + $this->assertEquals('Register A site', $contact['source']); // Check that the contact and the activity were correctly linked up as per the form. - $this->callAPISuccess('ActivityContact', 'get', ['contact_id' => $contact['id'], 'activity_id' => $activity['id']]); + $this->callAPISuccessGetSingle('ActivityContact', ['contact_id' => $contact['id'], 'activity_id' => $activity['id']]); } public function testAboutMeForbidden(): void { @@ -211,8 +168,7 @@ protected function useValues($values) { 'name' => $this->formName, ]; $full = array_merge($defaults, $values); - Civi\Api4\Afform::create() - ->setCheckPermissions(FALSE) + Civi\Api4\Afform::create(FALSE) ->setLayoutFormat('html') ->setValues($full) ->execute();