Skip to content
Snippets Groups Projects
Unverified Commit d4f8ea53 authored by colemanw's avatar colemanw Committed by GitHub
Browse files

Merge pull request #31343 from colemanw/afformRequiredEmail

Afform - Fix LocBlock address/email/phone saving
parents 86f1ffc4 95102016
No related branches found
No related tags found
No related merge requests found
......@@ -48,7 +48,7 @@ trait LocBlockSaveTrait {
$entityId = $params[$joinField] ?? $locBlock[$joinField] ?? NULL;
if ($item) {
$labelField = CoreUtil::getInfoItem($joinEntity, 'label_field');
// If NULL was given for the main field (e.g. `email`) then delete the record IF it's not in use
// If NULL was given for the required field (e.g. `email`) then delete the record IF it's not in use
if (!empty($params['id']) && $entityId && $labelField && array_key_exists($labelField, $item) && ($item[$labelField] === NULL || $item[$labelField] === '')) {
$referenceCount = CoreUtil::getRefCountTotal($joinEntity, $entityId);
if ($referenceCount <= 1) {
......@@ -60,7 +60,8 @@ trait LocBlockSaveTrait {
]);
}
}
else {
// Otherwise save if the required field (e.g. `email`) has a value (or no fields are required)
elseif (!array_key_exists($labelField, $item) || (isset($item[$labelField]) && $item[$labelField] !== '')) {
$item['contact_id'] = '';
if ($entityId) {
$item['id'] = $entityId;
......
......@@ -43,11 +43,18 @@ class DAOGetFieldsAction extends BasicGetFieldsAction {
if ($this->loadOptions) {
$this->loadFieldOptions($fields, $fieldsToGet ?: array_keys($fields));
}
// Add fields across implicit FK joins
foreach ($fieldsToGet ?? [] as $fieldName) {
if (empty($fields[$fieldName]) && str_contains($fieldName, '.')) {
$fkField = $this->getFkFieldSpec($fieldName, $fields);
if ($fkField) {
$fieldPrefix = substr($fieldName, 0, 0 - strlen($fkField['name']));
$fkField['name'] = $fieldName;
// Control field should get the same prefix as it belongs to the new entity now
if (!empty($fkField['input_attrs']['control_field'])) {
$fkField['input_attrs']['control_field'] = $fieldPrefix . $fkField['input_attrs']['control_field'];
}
$fkField['required'] = FALSE;
$fields[] = $fkField;
}
}
......@@ -69,7 +76,7 @@ class DAOGetFieldsAction extends BasicGetFieldsAction {
* @return array|null
* @throws \CRM_Core_Exception
*/
private function getFkFieldSpec($fieldName, $fields) {
private function getFkFieldSpec(string $fieldName, array $fields): ?array {
$fieldPath = explode('.', $fieldName);
// Search for the first segment alone plus the first and second
// No field in the schema contains more than one dot in its name.
......@@ -81,9 +88,11 @@ class DAOGetFieldsAction extends BasicGetFieldsAction {
'checkPermissions' => $this->checkPermissions,
'where' => [['name', '=', $newFieldName]],
'loadOptions' => $this->loadOptions,
'values' => FormattingUtil::filterByPath($this->values, $fieldName, $newFieldName),
'action' => $this->action,
])->first();
}
return NULL;
}
/**
......
......@@ -460,8 +460,8 @@ class Submit extends AbstractProcessor {
// Forward FK e.g. Event.loc_block_id => LocBlock
$forwardFkField = self::getFkField($mainEntity['type'], $joinEntityName);
if ($forwardFkField && $values) {
// Add id to values for update op
if ($whereClause) {
// Add id to values for update op, but only if id is not already on the form
if ($whereClause && empty($mainEntity['joins'][$joinEntityName]['fields'][$joinIdField])) {
$values[0][$joinIdField] = $whereClause[0][2];
}
$result = civicrm_api4($joinEntityName, 'save', [
......
......@@ -2,13 +2,14 @@
namespace api\v4\Afform;
use Civi\Api4\Afform;
use Civi\Test\TransactionalInterface;
/**
* Test case for Afform.prefill and Afform.submit with Event records.
*
* @group headless
*/
class AfformEventUsageTest extends AfformUsageTestCase {
class AfformEventUsageTest extends AfformUsageTestCase implements TransactionalInterface {
use \Civi\Test\Api4TestTrait;
/**
......@@ -75,4 +76,110 @@ EOHTML;
$this->assertSame('2234567', $prefill['values'][0]['joins']['LocBlock'][0]['phone_id.phone']);
}
/**
* Test saving & updating
*/
public function testEventLocationUpdate(): void {
$layout = <<<EOHTML
<af-form ctrl="afform">
<af-entity actions="{create: true, update: true}" type="Event" name="Event1" label="Event 1" security="FBAC" />
<fieldset af-fieldset="Event1" class="af-container" af-title="Event 1">
<af-field name="id" />
<af-field name="title" />
<af-field name="start_date" />
<af-field name="event_type_id" />
<div af-join="LocBlock">
<af-field name="id" />
<af-field name="email_id.email" />
<af-field name="address_id.street_address" />
</div>
</fieldset>
<button class="af-button btn btn-primary" crm-icon="fa-check" ng-click="afform.submit()">Submit</button>
</af-form>
EOHTML;
$this->useValues([
'layout' => $layout,
'permission' => \CRM_Core_Permission::ALWAYS_ALLOW_PERMISSION,
]);
// Create a new event with a new location
$submit = Afform::submit()
->setName($this->formName)
->setValues([
'Event1' => [
[
'fields' => [
'title' => 'Event Title 1',
'start_date' => '2021-01-01 00:00:00',
'event_type_id' => 1,
],
'joins' => [
'LocBlock' => [
[
'email_id.email' => 'test1@te.st',
'address_id.street_address' => '12345',
],
],
],
],
],
])->execute();
$event1 = $submit[0]['Event1'][0]['id'];
$loc1 = $submit[0]['Event1'][0]['joins']['LocBlock'][0]['id'];
// Create a 2nd new event with a new location
$submit = Afform::submit()
->setName($this->formName)
->setValues([
'Event1' => [
[
'fields' => [
'title' => 'Event Title 2',
'start_date' => '2022-01-01 00:00:00',
'event_type_id' => 1,
],
'joins' => [
'LocBlock' => [
[
'id' => $loc1,
],
],
],
],
],
])->execute();
$event2 = $submit[0]['Event1'][0]['id'];
$this->assertGreaterThan($event1, $event2);
$this->assertSame($loc1, $submit[0]['Event1'][0]['joins']['LocBlock'][0]['id']);
// Update event 1 with a new location
$submit = Afform::submit()
->setName($this->formName)
->setValues([
'Event1' => [
[
'fields' => [
'id' => $event1,
'title' => 'Event Title 1 Updated',
],
'joins' => [
'LocBlock' => [
[
'id' => NULL,
'address_id.street_address' => '12345',
],
],
],
],
],
])->execute();
$this->assertSame($event1, $submit[0]['Event1'][0]['id']);
$this->assertGreaterThan($loc1, $submit[0]['Event1'][0]['joins']['LocBlock'][0]['id']);
}
}
......@@ -25,6 +25,7 @@ use Civi\Api4\Address;
use Civi\Api4\Contact;
use Civi\Api4\Household;
use Civi\Api4\Individual;
use Civi\Api4\LocBlock;
use Civi\Api4\Tag;
/**
......@@ -101,6 +102,20 @@ class GetExtraFieldsTest extends Api4TestBase {
$this->assertGreaterThan(1, count($fields['contact_id.gender_id']['options']));
}
public function testGetLocBlockFields() {
$field = LocBlock::getFields(FALSE)
->setLoadOptions(TRUE)
->addWhere('name', '=', 'address_id.state_province_id')
->addValue('address_id.country_id', 1039)
->execute()->single();
$this->assertEquals('Address', $field['entity']);
$this->assertEquals('address_id.state_province_id', $field['name']);
$this->assertEquals('address_id.country_id', $field['input_attrs']['control_field']);
$this->assertContains('Manitoba', $field['options']);
$this->assertNotContains('Alabama', $field['options']);
}
public function testGetTagsFromFilterField(): void {
$actTag = Tag::create(FALSE)
->addValue('name', uniqid('act'))
......
......@@ -22,11 +22,12 @@ namespace api\v4\Entity;
use api\v4\Api4TestBase;
use Civi\Api4\Email;
use Civi\Api4\LocBlock;
use Civi\Test\TransactionalInterface;
/**
* @group headless
*/
class LocBlockTest extends Api4TestBase {
class LocBlockTest extends Api4TestBase implements TransactionalInterface {
/**
* @throws \CRM_Core_Exception
......@@ -52,18 +53,54 @@ class LocBlockTest extends Api4TestBase {
->addValue('email_2_id.email', 'third@e.mail')
->execute()->first();
// Void both emails in block 1
LocBlock::update(FALSE)
->addWhere('id', '=', $locBlock1['id'])
->addValue('email_id.email', '')
->addValue('email_2_id.email', '')
->execute();
// 1 email has been deleted, the other preserved (because it's shared with block 2)
$email1 = Email::get(FALSE)
->addSelect('id')
->addWhere('id', 'IN', [$locBlock1['email_id'], $locBlock1['email_2_id']])
->execute()->column('id');
$this->assertEquals([$locBlock1['email_id']], (array) $email1);
$this->assertEquals([$locBlock1['email_id']], $email1);
}
public function testLocBlockWithBlankValues(): void {
$locBlockId = LocBlock::create(FALSE)
->addValue('address_id.street_address', '')
->addValue('phone_id.phone', '')
->addValue('email_id.email', '')
->execute()->first()['id'];
// Get locBlock
$locBlock = LocBlock::get(FALSE)
->addWhere('id', '=', $locBlockId)
->execute()->single();
$this->assertNotEmpty($locBlock['address_id']);
$this->assertEmpty($locBlock['phone_id']);
$this->assertEmpty($locBlock['email_id']);
// Update with a 2nd blank email & an address
LocBlock::update(FALSE)
->addWhere('id', '=', $locBlockId)
->addValue('email2_id.email', '')
->addValue('address_id.street_address', '123')
->execute();
$updatedLocBlock = LocBlock::get(FALSE)
->addWhere('id', '=', $locBlockId)
->addSelect('*', 'address_id.street_address', 'phone_id.phone', 'email_id.email')
->execute()->single();
$this->assertEquals($locBlock['address_id'], $updatedLocBlock['address_id']);
$this->assertEquals('123', $updatedLocBlock['address_id.street_address']);
$this->assertNull($updatedLocBlock['phone_id.phone']);
$this->assertNull($updatedLocBlock['email_id.email']);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment