Upgrade saved import names for contacts
[civicrm-core.git] / CRM / Import / DataSource.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
7b057b66
EM
18use Civi\Api4\UserJob;
19
6a488035
TO
20/**
21 * This class defines the DataSource interface but must be subclassed to be
22 * useful.
23 */
24abstract class CRM_Import_DataSource {
25
7b057b66
EM
26 /**
27 * Class constructor.
28 *
29 * @param int|null $userJobID
30 */
31 public function __construct(int $userJobID = NULL) {
32 if ($userJobID) {
33 $this->setUserJobID($userJobID);
34 }
35 }
36
37 /**
38 * Form fields declared for this datasource.
39 *
40 * @var string[]
41 */
42 protected $submittableFields = [];
43
44 /**
45 * User job id.
46 *
47 * This is the primary key of the civicrm_user_job table which is used to
48 * track the import.
49 *
50 * @var int
51 */
52 protected $userJobID;
53
54 /**
55 * @return int|null
56 */
57 public function getUserJobID(): ?int {
58 return $this->userJobID;
59 }
60
61 /**
62 * Set user job ID.
63 *
64 * @param int $userJobID
65 */
66 public function setUserJobID(int $userJobID): void {
67 $this->userJobID = $userJobID;
68 }
69
70 /**
71 * User job details.
72 *
73 * This is the relevant row from civicrm_user_job.
74 *
75 * @var array
76 */
77 protected $userJob;
78
79 /**
80 * Get User Job.
81 *
82 * API call to retrieve the userJob row.
83 *
84 * @return array
85 *
86 * @throws \API_Exception
87 */
88 protected function getUserJob(): array {
89 if (!$this->userJob) {
90 $this->userJob = UserJob::get()
91 ->addWhere('id', '=', $this->getUserJobID())
92 ->execute()
93 ->first();
94 }
95 return $this->userJob;
96 }
97
4a01628c
EM
98 /**
99 * Get submitted value.
100 *
101 * Get a value submitted on the form.
102 *
103 * @return mixed
104 *
105 * @throws \API_Exception
106 */
107 protected function getSubmittedValue(string $valueName) {
108 return $this->getUserJob()['metadata']['submitted_values'][$valueName];
109 }
110
111 /**
112 * Get rows as an array.
113 *
114 * The array has all values.
115 *
116 * @param int $limit
117 * @param int $offset
118 *
119 * @return array
120 *
121 * @throws \API_Exception
122 * @throws \CRM_Core_Exception
123 */
124 public function getRows(int $limit = 0, int $offset = 0) {
125 $query = 'SELECT * FROM ' . $this->getTableName();
126 if ($limit) {
127 $query .= ' LIMIT ' . $limit . ($offset ? (' OFFSET ' . $offset) : NULL);
128 }
129 $rows = [];
130 $result = CRM_Core_DAO::executeQuery($query);
131 while ($result->fetch()) {
132 $values = $result->toArray();
133 /* trim whitespace around the values */
134 foreach ($values as $k => $v) {
135 $values[$k] = trim($v, " \t\r\n");
136 }
137 // Historically we expect a non-associative array...
138 $rows[] = array_values($values);
139 }
140 return $rows;
141 }
142
143 /**
144 * Get an array of column headers, if any.
145 *
146 * Null is returned when there are none - ie because a csv file does not
147 * have an initial header row.
148 *
149 * This is presented to the user in the MapField screen so
150 * that can see what fields they are mapping.
151 *
152 * @return array
153 * @throws \API_Exception
154 */
155 public function getColumnHeaders(): array {
156 return $this->getUserJob()['metadata']['DataSource']['column_headers'];
157 }
158
159 /**
160 * Get an array of column headers, if any.
161 *
162 * Null is returned when there are none - ie because a csv file does not
163 * have an initial header row.
164 *
165 * This is presented to the user in the MapField screen so
166 * that can see what fields they are mapping.
167 *
168 * @return int
169 * @throws \API_Exception
170 */
171 public function getNumberOfColumns(): int {
172 return $this->getUserJob()['metadata']['DataSource']['number_of_columns'];
173 }
174
7b057b66
EM
175 /**
176 * Generated metadata relating to the the datasource.
177 *
178 * This is values that are computed within the DataSource class and
179 * which are stored in the userJob metadata in the DataSource key - eg.
180 *
181 * ['table_name' => $]
182 *
183 * Will be in the user_job.metadata field encoded into the json like
184 *
185 * `{'DataSource' : ['table_name' => $], 'submitted_values' : .....}`
186 *
187 * @var array
188 */
189 protected $dataSourceMetadata = [];
190
191 /**
4a01628c
EM
192 * Get metadata about the datasource.
193 *
7b057b66 194 * @return array
4a01628c
EM
195 *
196 * @throws \API_Exception
7b057b66
EM
197 */
198 public function getDataSourceMetadata(): array {
4a01628c
EM
199 if (!$this->dataSourceMetadata && $this->getUserJobID()) {
200 $this->dataSourceMetadata = $this->getUserJob()['metadata']['DataSource'];
201 }
202
7b057b66
EM
203 return $this->dataSourceMetadata;
204 }
205
4a01628c
EM
206 /**
207 * Get the table name for the datajob.
208 *
209 * @return string|null
210 *
211 * @throws \API_Exception
212 * @throws \CRM_Core_Exception
213 */
214 protected function getTableName(): ?string {
215 // The old name is still stored...
216 $tableName = $this->getDataSourceMetadata()['table_name'];
217 if (!$tableName) {
218 return NULL;
219 }
220 if (strpos($tableName, 'civicrm_tmp_') !== 0
221 || !CRM_Utils_Rule::alphanumeric($tableName)) {
222 // The table name is generated and stored by code, not users so it
223 // should be safe - but a check seems prudent all the same.
224 throw new CRM_Core_Exception('Table cannot be deleted');
225 }
226 return $tableName;
227 }
228
7b057b66
EM
229 /**
230 * Get the fields declared for this datasource.
231 *
232 * @return string[]
233 */
234 public function getSubmittableFields(): array {
235 return $this->submittableFields;
236 }
237
6a488035 238 /**
fe482240 239 * Provides information about the data source.
6a488035 240 *
a6c01b45 241 * @return array
11749569
TO
242 * Description of this data source, including:
243 * - title: string, translated, required
244 * - permissions: array, optional
245 *
6a488035
TO
246 */
247 abstract public function getInfo();
248
6a488035 249 /**
54957108 250 * This is function is called by the form object to get the DataSource's form snippet.
6a488035 251 *
54957108 252 * It should add all fields necessary to get the data uploaded to the temporary table in the DB.
6c8f6e67 253 *
54957108 254 * @param CRM_Core_Form $form
6a488035
TO
255 */
256 abstract public function buildQuickForm(&$form);
257
11749569
TO
258 /**
259 * Determine if the current user has access to this data source.
260 *
261 * @return bool
262 */
263 public function checkPermission() {
264 $info = $this->getInfo();
265 return empty($info['permissions']) || CRM_Core_Permission::check($info['permissions']);
266 }
267
4a01628c
EM
268 /**
269 * @param string $key
270 * @param array $data
271 *
272 * @throws \API_Exception
273 * @throws \Civi\API\Exception\UnauthorizedException
274 */
275 protected function updateUserJobMetadata(string $key, array $data): void {
276 $metaData = array_merge(
277 $this->getUserJob()['metadata'],
278 [$key => $data]
279 );
280 UserJob::update(FALSE)
281 ->addWhere('id', '=', $this->getUserJobID())
282 ->setValues(['metadata' => $metaData])
283 ->execute();
284 $this->userJob['metadata'] = $metaData;
285 }
286
6a488035 287}