Commit | Line | Data |
---|---|---|
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 |
18 | use Civi\Api4\UserJob; |
19 | ||
6a488035 TO |
20 | /** |
21 | * This class defines the DataSource interface but must be subclassed to be | |
22 | * useful. | |
23 | */ | |
24 | abstract 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 | } |