Merge pull request #15248 from MegaphoneJon/reporting-19
[civicrm-core.git] / Civi / Api4 / Generic / BasicReplaceAction.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | CiviCRM version 5 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2020 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
10 | |
11 | CiviCRM is free software; you can copy, modify, and distribute it |
12 | under the terms of the GNU Affero General Public License |
13 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | |
15 | CiviCRM is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | See the GNU Affero General Public License for more details. |
19 | |
20 | You should have received a copy of the GNU Affero General Public |
21 | License and the CiviCRM Licensing Exception along |
22 | with this program; if not, contact CiviCRM LLC |
23 | at info[AT]civicrm[DOT]org. If you have questions about the |
24 | GNU Affero General Public License or the licensing of CiviCRM, |
25 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
26 +--------------------------------------------------------------------+
27 */
28
29 /**
30 *
31 * @package CRM
32 * @copyright CiviCRM LLC (c) 2004-2020
33 * $Id$
34 *
35 */
36
37
38 namespace Civi\Api4\Generic;
39
40 use Civi\API\Exception\NotImplementedException;
41 use Civi\Api4\Utils\ActionUtil;
42
43 /**
44 * Given a set of records, will appropriately update the database.
45 *
46 * @method $this setRecords(array $records) Array of records.
47 * @method $this addRecord($record) Add a record to update.
48 * @method array getRecords()
49 * @method $this setDefaults(array $defaults) Array of defaults.
50 * @method $this addDefault($name, $value) Add a default value.
51 * @method array getDefaults()
52 * @method $this setReload(bool $reload) Specify whether complete objects will be returned after saving.
53 * @method bool getReload()
54 */
55 class BasicReplaceAction extends AbstractBatchAction {
56
57 /**
58 * Array of records.
59 *
60 * Should be in the same format as returned by Get.
61 *
62 * @var array
63 * @required
64 */
65 protected $records = [];
66
67 /**
68 * Array of default values.
69 *
70 * Will be merged into $records before saving.
71 *
72 * @var array
73 */
74 protected $defaults = [];
75
76 /**
77 * Reload records after saving.
78 *
79 * By default this api typically returns partial records containing only the fields
80 * that were updated. Set reload to TRUE to do an additional lookup after saving
81 * to return complete records.
82 *
83 * @var bool
84 */
85 protected $reload = FALSE;
86
87 /**
88 * @return \Civi\Api4\Result\ReplaceResult
89 */
90 public function execute() {
91 return parent::execute();
92 }
93
94 /**
95 * @inheritDoc
96 */
97 public function _run(Result $result) {
98 $items = $this->getBatchRecords();
99
100 // Copy defaults from where clause if the operator is =
101 foreach ($this->where as $clause) {
102 if (is_array($clause) && $clause[1] === '=') {
103 $this->defaults[$clause[0]] = $clause[2];
104 }
105 }
106
107 $idField = $this->getSelect()[0];
108 $toDelete = array_diff_key(array_column($items, NULL, $idField), array_flip(array_filter(\CRM_Utils_Array::collect($idField, $this->records))));
109
110 // Try to delegate to the Save action
111 try {
112 $saveAction = ActionUtil::getAction($this->getEntityName(), 'save');
113 $saveAction
114 ->setCheckPermissions($this->getCheckPermissions())
115 ->setReload($this->reload)
116 ->setRecords($this->records)
117 ->setDefaults($this->defaults);
118 $result->exchangeArray((array) $saveAction->execute());
119 }
120 // Fall back on Create/Update if Save doesn't exist
121 catch (NotImplementedException $e) {
122 foreach ($this->records as $record) {
123 $record += $this->defaults;
124 if (!empty($record[$idField])) {
125 $result[] = civicrm_api4($this->getEntityName(), 'update', [
126 'reload' => $this->reload,
127 'where' => [[$idField, '=', $record[$idField]]],
128 'values' => $record,
129 'checkPermissions' => $this->getCheckPermissions(),
130 ])->first();
131 }
132 else {
133 $result[] = civicrm_api4($this->getEntityName(), 'create', [
134 'values' => $record,
135 'checkPermissions' => $this->getCheckPermissions(),
136 ])->first();
137 }
138 }
139 }
140
141 if ($toDelete) {
142 $result->deleted = (array) civicrm_api4($this->getEntityName(), 'delete', [
143 'where' => [[$idField, 'IN', array_keys($toDelete)]],
144 'checkPermissions' => $this->getCheckPermissions(),
145 ]);
146 }
147 }
148
149 }