namespace Civi\Api4\Generic;
+use Civi\API\Exception\UnauthorizedException;
use Civi\Api4\Event\ValidateValuesEvent;
+use Civi\Api4\Utils\CoreUtil;
/**
* Base class for all `Update` api actions
*/
protected $reload = FALSE;
+ /**
+ * Criteria for selecting items to update.
+ *
+ * Required if no id is supplied in values.
+ *
+ * @var array
+ */
+ protected $where = [];
+
+ abstract protected function updateRecords(array $items): array;
+
+ /**
+ * @inheritDoc
+ */
+ public function _run(Result $result) {
+ $primaryKeys = CoreUtil::getInfoItem($this->getEntityName(), 'primary_key');
+ $this->formatWriteValues($this->values);
+
+ // Add primary keys from values to WHERE clause and check for mismatch
+ foreach ($primaryKeys as $id) {
+ if (!empty($this->values[$id])) {
+ $wheres = array_column($this->where, NULL, 0);
+ if (!isset($wheres[$id])) {
+ $this->addWhere($id, '=', $this->values[$id]);
+ }
+ elseif (!($wheres[$id][1] === '=' && $wheres[$id][2] == $this->values[$id])) {
+ throw new \Exception("Cannot update the $id of an existing " . $this->getEntityName() . '.');
+ }
+ }
+ }
+
+ // Require WHERE if we didn't get primary keys from values
+ if (!$this->where) {
+ throw new \API_Exception('Parameter "where" is required unless primary keys are supplied in values.');
+ }
+
+ // Update a single record by primary key (if this entity has a single primary key)
+ if (count($this->where) === 1 && count($primaryKeys) === 1 && $primaryKeys === $this->getSelect() && $this->where[0][0] === $id && $this->where[0][1] === '=' && !empty($this->where[0][2])) {
+ $this->values[$id] = $this->where[0][2];
+ if ($this->checkPermissions && !CoreUtil::checkAccessRecord($this, $this->values, \CRM_Core_Session::getLoggedInContactID() ?: 0)) {
+ throw new UnauthorizedException("ACL check failed");
+ }
+ $items = [$this->values];
+ $this->validateValues();
+ $result->exchangeArray($this->updateRecords($items));
+ return;
+ }
+
+ // Batch update 1 or more records based on WHERE clause
+ $items = $this->getBatchRecords();
+ foreach ($items as &$item) {
+ $item = $this->values + $item;
+ if ($this->checkPermissions && !CoreUtil::checkAccessRecord($this, $item, \CRM_Core_Session::getLoggedInContactID() ?: 0)) {
+ throw new UnauthorizedException("ACL check failed");
+ }
+ }
+
+ $this->validateValues();
+ $result->exchangeArray($this->updateRecords($items));
+ }
+
/**
* @param string $fieldName
*