]);
$loader->load();
- $afform = civicrm_api4('Afform', 'get', ['where' => [['name', '=', $pageArgs['afform']]], 'select' => ['title']]);
+ $afform = civicrm_api4('Afform', 'get', ['checkPermissions' => FALSE, 'where' => [['name', '=', $pageArgs['afform']]], 'select' => ['title']]);
if (!empty($afform[0]['title'])) {
CRM_Utils_System::setTitle(strip_tags($afform[0]['title']));
--- /dev/null
+<?php
+
+namespace Civi\Afform;
+
+class Utils {
+
+ /**
+ * Gets entity metadata and all fields from the form
+ *
+ * @param array $layout
+ * @return array
+ */
+ public static function getEntities($layout) {
+ $entities = array_column(self::getTags($layout, 'af-model-prop'), NULL, 'af-name');
+ self::getFields($layout, $entities);
+ return $entities;
+ }
+
+ /**
+ * Returns all tags with a certain tag name, e.g. 'af-model-prop'
+ *
+ * @param array $collection
+ * @param string $tagName
+ * @return array
+ */
+ public static function getTags($collection, $tagName) {
+ $results = [];
+ if ($collection['#tag'] == $tagName) {
+ $results[] = self::getProps($collection);
+ }
+ foreach ($collection['#children'] ?? [] as $child) {
+ $results = array_merge($results, self::getTags($child, $tagName));
+ }
+ return $results;
+ }
+
+ /**
+ * @param array $layout
+ * @param array $entities
+ */
+ protected static function getFields($layout, &$entities) {
+ foreach ($layout['#children'] as $child) {
+ if ($child['#tag'] == 'af-model' && !empty($child['#children'])) {
+ $entities[$child['af-name']]['fields'] = array_merge($entities[$child['af-name']]['fields'] ?? [], self::getTags($child, 'af-field'));
+ }
+ elseif (!empty($child['#children'])) {
+ self::getFields($child['#children'], $entities);
+ }
+ }
+ }
+
+ /**
+ * Returns all the real properties of a collection,
+ * filtering out any array keys that start with a hashtag
+ *
+ * @param array $collection
+ * @return array
+ */
+ public static function getProps($collection) {
+ return array_filter($collection, function($key) {
+ return substr($key, 0, 1) !== '#';
+ }, ARRAY_FILTER_USE_KEY);
+ }
+
+}
--- /dev/null
+<?php
+
+namespace Civi\Api4\Action\Afform;
+
+use Civi\Afform\Utils;
+use Civi\Api4\Generic\Result;
+
+/**
+ * Class Prefill
+ * @package Civi\Api4\Action\Afform
+ */
+abstract class AbstractProcessor extends \Civi\Api4\Generic\AbstractAction {
+
+ /**
+ * Form name
+ * @var string
+ * @required
+ */
+ protected $name;
+
+ /**
+ * Arguments present when loading the form
+ * @var array
+ */
+ protected $args;
+
+ protected $_afform;
+
+ protected $_afformEntities;
+
+ public function _run(Result $result) {
+ // This will throw an exception if the form doesn't exist
+ $this->_afform = (array) civicrm_api4('Afform', 'get', ['checkPermissions' => FALSE, 'where' => [['name', '=', $this->name]]], 0);
+ $this->_afformEntities = Utils::getEntities($this->_afform['layout']);
+ $this->validateArgs();
+ $result->exchangeArray($this->processForm());
+ }
+
+ /**
+ * Strip out arguments that are not allowed on this form
+ */
+ protected function validateArgs() {
+ $rawArgs = $this->args;
+ $this->args = [];
+ foreach ($rawArgs as $arg => $val) {
+ if (!empty($this->_afformEntities[$arg]['af-url-autofill'])) {
+ $this->args[$arg] = $val;
+ }
+ }
+ }
+
+ /**
+ * @return array
+ */
+ abstract protected function processForm();
+
+}
--- /dev/null
+<?php
+
+namespace Civi\Api4\Action\Afform;
+
+/**
+ * Class Prefill
+ * @package Civi\Api4\Action\Afform
+ */
+class Prefill extends AbstractProcessor {
+
+ protected $_data = [];
+
+ protected function processForm() {
+ foreach ($this->_afformEntities as $entityName => $entity) {
+ // Load entities from args
+ if (!empty($this->args[$entityName])) {
+ $this->loadEntity($entity, $this->args[$entityName]);
+ }
+ // Load entities from autofill settings
+ elseif (!empty($entity['af-autofill'])) {
+ $this->autofillEntity($entity, $entity['af-autofill']);
+ }
+ }
+ $data = [];
+ foreach ($this->_data as $name => $values) {
+ $data[] = ['name' => $name, 'values' => $values];
+ }
+ return $data;
+ }
+
+ /**
+ * Fetch all fields needed to display a given entity on this form
+ *
+ * @param $entity
+ * @param $id
+ * @throws \API_Exception
+ */
+ private function loadEntity($entity, $id) {
+ $checkPermissions = TRUE;
+ if ($entity['af-type'] == 'Contact' && !empty($this->args[$entity['af-name'] . '-cs'])) {
+ $checkSum = civicrm_api4('Contact', 'validateChecksum', [
+ 'checksum' => $this->args[$entity['af-name'] . '-cs'],
+ 'contactId' => $id,
+ ]);
+ $checkPermissions = empty($checkSum[0]['valid']);
+ }
+ $result = civicrm_api4($entity['af-type'], 'get', [
+ 'where' => [['id', '=', $id]],
+ 'select' => array_column($entity['fields'], 'field-name'),
+ 'checkPermissions' => $checkPermissions,
+ ]);
+ if ($result->first()) {
+ $this->_data[$entity['af-name']] = $result->first();
+ }
+ }
+
+ /**
+ * Fetch an entity based on its autofill settings
+ *
+ * @param $entity
+ * @param $mode
+ */
+ private function autoFillEntity($entity, $mode) {
+ $id = NULL;
+ if ($entity['af-type'] == 'Contact') {
+ if ($mode == 'user') {
+ $id = \CRM_Core_Session::getLoggedInContactID();
+ }
+ }
+ if ($id) {
+ $this->loadEntity($entity, $id);
+ }
+ }
+
+}
return new \Civi\Api4\Action\Afform\Update('Afform', __FUNCTION__, 'name');
}
+ /**
+ * @return \Civi\Api4\Action\Afform\Prefill
+ */
+ public static function prefill() {
+ return new \Civi\Api4\Action\Afform\Prefill('Afform', __FUNCTION__);
+ }
+
+ /**
+ * @return \Civi\Api4\Action\Afform\Submit
+ */
+ public static function submit() {
+ return new \Civi\Api4\Action\Afform\Submit('Afform', __FUNCTION__);
+ }
+
public static function getFields() {
return new BasicGetFieldsAction('Afform', __FUNCTION__, function() {
return [
return [
"meta" => ["access CiviCRM"],
"default" => ["administer CiviCRM"],
+ 'prefill' => [],
+ 'submit' => [],
];
}
this.getEntity = function getEntity(name) {
return schema[name];
};
+ // Returns field values for a given entity
this.getData = function getData(name) {
return data[name];
};
return schema[name];
};
this.loadData = function() {
- var apiCalls = {};
+ var toLoad = 0;
_.each(schema, function(entity, entityName) {
- if ($routeParams[entityName]) {
- var id = $routeParams[entityName];
- apiCalls[entityName] = [entity.type, 'get', {select: entity.fields, where: [['id', '=', id]]}, 0];
+ if ($routeParams[entityName] || entity.autofill) {
+ toLoad++;
}
});
- if (!_.isEmpty(apiCalls)) {
- crmApi4(apiCalls).then(function(resp) {
- data = resp;
- });
+ if (toLoad) {
+ crmApi4('Afform', 'prefill', {name: CRM.afform.open, args: $routeParams})
+ .then(function(result) {
+ _.each(result, function(item) {
+ data[item.name] = item.values;
+ });
+ });
}
};
scope: {
afType: '@',
afName: '@',
- afLabel: '@'
+ afLabel: '@',
+ afAutofill: '@'
},
link: function($scope, $el, $attr, afModelListCtrl) {
var ts = $scope.ts = CRM.ts('afform');
type: $scope.afType,
name: $scope.afName,
label: $scope.afLabel,
- fields: [],
+ autofill: $scope.afAutofill,
+ fields: []
});
// $scope.$watch('afModelProp', function(newValue){$scope.myOptions = newValue;});
}