Passed
Push — developer ( b6ebe7...0bf5e9 )
by Mariusz
47:54 queued 29:05
created

Map::getDataApi()   C

Complexity

Conditions 16
Paths 3

Size

Total Lines 46
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 34
dl 0
loc 46
rs 5.5666
c 1
b 0
f 0
cc 16
nc 3
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Comarch abstract base map file.
5
 *
6
 * The file is part of the paid functionality. Using the file is allowed only after purchasing a subscription.
7
 * File modification allowed only with the consent of the system producer.
8
 *
9
 * @package Integration
10
 *
11
 * @copyright YetiForce S.A.
12
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
13
 * @author    Mariusz Krzaczkowski <[email protected]>
14
 */
15
16
namespace App\Integrations\Comarch;
17
18
/**
19
 * Comarch abstract base map class.
20
 */
21
abstract class Map
22
{
23
	/** @var string The name of the field with the identifier in Comarch */
24
	const FIELD_NAME_ID = 'comarch_id';
25
	/** @var string The name of the key with the identifier from Comarch */
26
	const API_NAME_ID = 'id';
27
	/** @var string Map module name. */
28
	protected $moduleName;
29
	/** @var array Mapped fields. */
30
	protected $fieldMap = [];
31
	/** @var array Data from Comarch. */
32
	protected $dataApi = [];
33
	/** @var array Default data from Comarch. */
34
	protected $defaultDataApi = [];
35
	/** @var array Data from YetiForce. */
36
	protected $dataYf = [];
37
	/** @var array Default data from YetiForce. */
38
	protected $defaultDataYf = [];
39
	/** @var \App\Integrations\Comarch\Synchronizer Synchronizer instance */
40
	protected $synchronizer;
41
	/** @var array Dependent synchronizations to be performed during the operation */
42
	protected $dependentSynchronizations = [];
43
	/** @var \Vtiger_Module_Model Module model instance */
44
	protected $moduleModel;
45
	/** @var \Vtiger_Record_Model Record model instance */
46
	protected $recordModel;
47
	/** @var string API map mode: create, update, get. */
48
	protected $modeApi;
49
	/** @var string Skip mode when data is incomplete */
50
	public $skip = false;
51
52
	/** @var string[] Mapped address fields. */
53
	protected $addressMapFields = [
54
		'addresslevel1' => [
55
			'names' => ['get' => 'knt_Kraj', 'create' => 'Kraj', 'update' => 'Kraj'], 'fn' => 'convertCountry'
56
		],
57
		'addresslevel2' => ['names' => ['get' => 'knt_Wojewodztwo', 'create' => 'Wojewodztwo', 'update' => 'Wojewodztwo']],
58
		'addresslevel3' => ['names' => ['get' => 'knt_Powiat', 'create' => 'Powiat', 'update' => 'Powiat']],
59
		'addresslevel4' => ['names' => ['get' => 'knt_Gmina', 'create' => 'Gmina', 'update' => 'Gmina']],
60
		'addresslevel5' => ['names' => ['get' => 'knt_Miasto', 'create' => 'Miasto', 'update' => 'Miasto']],
61
		'addresslevel7' => ['names' => ['get' => 'knt_KodP', 'create' => 'KodP', 'update' => 'KodP']],
62
		'addresslevel8' => ['names' => ['get' => 'knt_Ulica', 'create' => 'Ulica', 'update' => 'Ulica']],
63
		'first_name_' => 'first_name',
64
		'last_name_' => 'last_name',
65
		'phone_' => ['name' => 'phone', 'fn' => 'convertPhone'],
66
		'email_' => 'email',
67
		'company_name_' => 'company',
68
	];
69
70
	/**
71
	 * Constructor.
72
	 *
73
	 * @param \App\Integrations\Comarch\Synchronizer $synchronizer
74
	 */
75
	public function __construct(Synchronizer $synchronizer)
76
	{
77
		$this->synchronizer = $synchronizer;
78
		$this->moduleModel = \Vtiger_Module_Model::getInstance($this->moduleName);
79
	}
80
81
	/**
82
	 * Set data from/for API.
83
	 *
84
	 * @param array $data
85
	 */
86
	public function setDataApi(array $data): void
87
	{
88
		if ($data) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
89
			$this->dataApi = $data;
90
			$this->modeApi = 'get';
91
		} else {
92
			$this->dataApi = $this->defaultDataApi;
93
			$this->modeApi = '';
94
		}
95
	}
96
97
	/**
98
	 * Set data from/for YetiForce. YetiForce data is read-only.
99
	 *
100
	 * @param array $data
101
	 * @param bool  $updateRecordModel
102
	 *
103
	 * @return void
104
	 */
105
	public function setDataYf(array $data, bool $updateRecordModel = false): void
106
	{
107
		$this->dataYf = $data;
108
		if ($updateRecordModel) {
109
			$this->recordModel = \Vtiger_Module_Model::getInstance($this->moduleName)->getRecordFromArray($data);
110
		}
111
	}
112
113
	/**
114
	 * Set data from/for YetiForce by record ID. Read/Write YetiForce data.
115
	 *
116
	 * @param int $id
117
	 *
118
	 * @return void
119
	 */
120
	public function setDataYfById(int $id): void
121
	{
122
		$this->recordModel = \Vtiger_Record_Model::getInstanceById($id, $this->moduleName);
123
		$this->dataYf = $this->recordModel->getData();
124
	}
125
126
	/**
127
	 * Checking what is the mode of operation to be performed in the API,
128
	 * along with searching for the same entry in the API.
129
	 *
130
	 * @return void
131
	 */
132
	public function loadModeApi(): void
133
	{
134
		if (empty($this->modeApi)) {
135
			$this->modeApi = empty($this->dataYf[$this::FIELD_NAME_ID]) ? 'create' : 'update';
136
			if (empty($this->dataApi['id']) && ($id = $this->findRecordInApi())) {
137
				$this->dataApi['id'] = $id;
138
				$this->modeApi = 'update';
139
			}
140
		}
141
	}
142
143
	/**
144
	 * Get API mode.
145
	 *
146
	 * @return string|null
147
	 */
148
	public function getModeApi(): ?string
149
	{
150
		return $this->modeApi;
151
	}
152
153
	/**
154
	 * Load record model.
155
	 *
156
	 * @param int|null $id
157
	 */
158
	public function loadRecordModel(?int $id = null): void
159
	{
160
		if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
161
			$this->recordModel = \Vtiger_Record_Model::getInstanceById($id, $this->moduleName);
162
		} else {
163
			$this->recordModel = \Vtiger_Record_Model::getCleanInstance($this->moduleName);
164
		}
165
	}
166
167
	/**
168
	 * Get record model.
169
	 *
170
	 * @return \Vtiger_Record_Model
171
	 */
172
	public function getRecordModel(): \Vtiger_Record_Model
173
	{
174
		return $this->recordModel;
175
	}
176
177
	/**
178
	 * Get module name.
179
	 *
180
	 * @return string
181
	 */
182
	public function getModule(): string
183
	{
184
		return $this->moduleName;
185
	}
186
187
	/**
188
	 * Return fields list.
189
	 *
190
	 * @return array
191
	 */
192
	public function getFields(): array
193
	{
194
		return $this->fieldMap;
195
	}
196
197
	/**
198
	 * Return parsed data in YetiForce format.
199
	 *
200
	 * @param string $type
201
	 * @param bool   $mapped
202
	 *
203
	 * @return array
204
	 */
205
	public function getDataYf(string $type = 'fieldMap', bool $mapped = true): array
206
	{
207
		if ($mapped) {
208
			$this->dataYf = $this->defaultDataYf[$type] ?? [];
209
			foreach ($this->{$type} as $fieldCrm => $field) {
210
				if ($this->skip) {
211
					continue;
212
				}
213
				if (\is_array($field)) {
214
					if (!empty($field['direction']) && 'api' === $field['direction']) {
215
						continue;
216
					}
217
					$key = $field['name'] ?? ($field['names'][$this->modeApi] ?? '');
218
					$field['fieldCrm'] = $fieldCrm;
219
					if (empty($key)) {
220
						$this->synchronizer->controller->log(
221
							"[API>YF][1] No key ($fieldCrm)",
222
							['fieldConfig' => $field, 'data' => $this->dataApi], null, true
223
						);
224
					} elseif (\is_array($key)) {
225
						$field['name'] = $key;
226
						$this->loadDataYfMultidimensional($fieldCrm, $field);
227
					} elseif (\array_key_exists($key, $this->dataApi)) {
228
						$this->loadDataYfMap($fieldCrm, $field);
229
					} elseif (!\array_key_exists('optional', $field) || empty($field['optional'])) {
230
						$error = "[API>YF][1] No column {$key} ($fieldCrm)";
231
						\App\Log::warning($error, $this->synchronizer::LOG_CATEGORY);
232
						$this->synchronizer->controller->log($error, ['fieldConfig' => $field, 'data' => $this->dataApi], null, true);
233
					}
234
				} else {
235
					$this->dataYf[$fieldCrm] = $this->dataApi[$field] ?? null;
236
					if (!\array_key_exists($field, $this->dataApi)) {
237
						$error = "[API>YF][2] No column $field ($fieldCrm)";
238
						\App\Log::warning($error, $this->synchronizer::LOG_CATEGORY);
239
						$this->synchronizer->controller->log($error, $this->dataApi, null, true);
240
					}
241
				}
242
			}
243
		}
244
		return $this->dataYf;
245
	}
246
247
	/**
248
	 * Parse data to YetiForce format from multidimensional array.
249
	 *
250
	 * @param string $fieldCrm
251
	 * @param array  $field
252
	 *
253
	 * @return void
254
	 */
255
	protected function loadDataYfMultidimensional(string $fieldCrm, array $field): void
256
	{
257
		$value = $this->dataApi;
258
		$field['fieldCrm'] = $fieldCrm;
259
		foreach ($field['name'] as $name) {
260
			if (\array_key_exists($name, $value)) {
261
				$value = $value[$name];
262
			} else {
263
				$error = "[API>YF][3] No column $name ($fieldCrm)";
264
				if (!\array_key_exists('optional', $field) || empty($field['optional'])) {
265
					\App\Log::warning($error, $this->synchronizer::LOG_CATEGORY);
266
					$this->synchronizer->controller->log($error, ['fieldConfig' => $field, 'data' => $this->dataApi], null, true);
267
				}
268
			}
269
		}
270
		if (empty($error)) {
271
			$this->loadDataYfMap($fieldCrm, $field, $value);
272
		}
273
	}
274
275
	/**
276
	 * Parse data to YetiForce format from map.
277
	 *
278
	 * @param string     $fieldCrm
279
	 * @param array      $field
280
	 * @param mixed|null $value
281
	 *
282
	 * @return void
283
	 */
284
	protected function loadDataYfMap(string $fieldCrm, array $field, $value = null): void
285
	{
286
		$key = $field['name'] ?? $field['names']['get'];
287
		$value = $value ?? $this->dataApi[$key];
288
		if (isset($field['map'])) {
289
			if (\array_key_exists($value, $field['map'])) {
290
				$this->dataYf[$fieldCrm] = $field['map'][$value];
291
			} elseif (empty($field['mayNotExist'])) {
292
				$value = print_r($value, true);
293
				$error = "[API>YF] No value `{$value}` in map {$key}";
294
				\App\Log::warning($error, $this->synchronizer::LOG_CATEGORY);
295
				$this->synchronizer->controller->log($error, ['fieldConfig' => $field, 'data' => $this->dataApi], null, true);
296
			}
297
		} elseif (isset($field['fn'])) {
298
			$this->dataYf[$fieldCrm] = $this->{$field['fn']}($value, $field, true);
299
		} else {
300
			$this->dataYf[$fieldCrm] = $value;
301
		}
302
	}
303
304
	/**
305
	 * Return parsed data in YetiForce format.
306
	 *
307
	 * @param bool $mapped
308
	 *
309
	 * @return array
310
	 */
311
	public function getDataApi(bool $mapped = true): array
312
	{
313
		if ($mapped) {
314
			if (!empty($this->dataYf[$this::FIELD_NAME_ID])) {
315
				$this->dataApi['id'] = $this->dataYf[$this::FIELD_NAME_ID];
316
			}
317
			foreach ($this->fieldMap as $fieldCrm => $field) {
318
				if ($this->skip) {
319
					continue;
320
				}
321
				if (\is_array($field)) {
322
					if (!empty($field['direction']) && 'yf' === $field['direction']) {
323
						continue;
324
					}
325
					if (\array_key_exists($fieldCrm, $this->dataYf)) {
326
						$field['fieldCrm'] = $fieldCrm;
327
						if (isset($field['map'])) {
328
							$mapValue = array_search($this->dataYf[$fieldCrm], $field['map']);
329
							if (false !== $mapValue) {
330
								$this->setApiData($mapValue, $field);
331
							} elseif (empty($field['mayNotExist'])) {
332
								$error = "[YF>API] No value `{$this->dataYf[$fieldCrm]}` in map {$fieldCrm}";
333
								\App\Log::warning($error, $this->synchronizer::LOG_CATEGORY);
334
								$this->synchronizer->controller->log($error, ['fieldConfig' => $field, 'data' => $this->dataYf], null, true);
335
							}
336
						} elseif (isset($field['fn'])) {
337
							$this->setApiData($this->{$field['fn']}($this->dataYf[$fieldCrm], $field, false), $field);
338
						} else {
339
							$this->setApiData($this->dataYf[$fieldCrm], $field);
340
						}
341
					} elseif (!\array_key_exists('optional', $field) || empty($field['optional'])) {
342
						$error = '[YF>API] No field ' . $fieldCrm;
343
						\App\Log::warning($error, $this->synchronizer::LOG_CATEGORY);
344
						$this->synchronizer->controller->log($error, ['fieldConfig' => $field, 'data' => $this->dataYf], null, true);
345
					}
346
				} else {
347
					$this->dataApi[$field] = $this->dataYf[$fieldCrm] ?? null;
348
					if (!\array_key_exists($fieldCrm, $this->dataYf)) {
349
						$error = '[YF>API] No field ' . $fieldCrm;
350
						\App\Log::warning($error, $this->synchronizer::LOG_CATEGORY);
351
						$this->synchronizer->controller->log($error, ['fieldConfig' => $field, 'data' => $this->dataYf], null, true);
352
					}
353
				}
354
			}
355
		}
356
		return $this->dataApi;
357
	}
358
359
	/**
360
	 * Set the data to in the appropriate key structure.
361
	 *
362
	 * @param mixed $value
363
	 * @param array $field
364
	 *
365
	 * @return void
366
	 */
367
	public function setApiData($value, array $field): void
368
	{
369
		$key = $field['name'] ?? ($field['names'][$this->modeApi] ?? '');
370
		if (empty($key)) {
371
			$this->synchronizer->controller->log(
372
				"[API>YF][1] No key ({$field['fieldCrm']})",
373
				['fieldConfig' => $field, 'data' => $this->dataApi], null, true
374
			);
375
		} elseif (\is_array($key)) {
376
			foreach (array_reverse($key) as $name) {
377
				$value = [$name => $value];
378
			}
379
			$this->dataApi = \App\Utils::merge($this->dataApi, $value);
380
		} else {
381
			$this->dataApi[$key] = $value;
382
		}
383
	}
384
385
	/**
386
	 * Create/update product in YF.
387
	 *
388
	 * @return void
389
	 */
390
	public function saveInYf(): void
391
	{
392
		foreach ($this->dataYf as $key => $value) {
393
			$this->recordModel->set($key, $value);
394
		}
395
		if ($this->recordModel->isEmpty('assigned_user_id')) {
396
			$this->recordModel->set('assigned_user_id', $this->synchronizer->config->get('assigned_user_id'));
397
		}
398
		if (
399
			$this->recordModel->isEmpty($this::FIELD_NAME_ID)
400
			&& ($id = $this->dataApi['id'] ?? $this->dataApi[$this::API_NAME_ID] ?? 0)
401
			&& $this->recordModel->getModule()->getFieldByName($this::FIELD_NAME_ID)
402
			&& !empty($id)
403
		) {
404
			$this->recordModel->set($this::FIELD_NAME_ID, $id);
405
		}
406
		$this->recordModel->set('comarch_server_id', $this->synchronizer->config->get('id'));
407
		$isNew = empty($this->recordModel->getId());
408
		$this->recordModel->save();
409
		$this->recordModel->ext['isNew'] = $isNew;
410
		if ($isNew && $this->recordModel->get($this::FIELD_NAME_ID)) {
411
			$this->synchronizer->updateMapIdCache(
412
				$this->recordModel->getModuleName(),
413
				$this->recordModel->get($this::FIELD_NAME_ID), $this->recordModel->getId()
414
			);
415
		}
416
	}
417
418
	/**
419
	 * Create/update product by API.
420
	 *
421
	 * @return void
422
	 */
423
	public function saveInApi(): void
424
	{
425
		throw new \App\Exceptions\AppException('Method not implemented');
426
	}
427
428
	/**
429
	 * Find by relationship in YF by API ID.
430
	 *
431
	 * @param mixed $value
432
	 * @param array $field
433
	 * @param bool  $fromApi
434
	 *
435
	 * @return int
436
	 */
437
	protected function findByRelationship($value, array $field, bool $fromApi): int
438
	{
439
		$moduleName = $field['moduleName'] ?? $this->moduleName;
440
		if (empty($value)) {
441
			return 0;
442
		}
443
		if ($fromApi) {
444
			return $this->synchronizer->getYfId($value, $moduleName);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->synchroniz...Id($value, $moduleName) could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
445
		}
446
		return $this->synchronizer->getApiId($value, $moduleName);
447
	}
448
449
	/**
450
	 * Add relationship in YF by API ID.findByRelationship.
451
	 *
452
	 * @param mixed $value
453
	 * @param array $field
454
	 * @param bool  $fromApi
455
	 *
456
	 * @return string|array string (YF) or string (API)
457
	 */
458
	protected function addRelationship($value, array $field, bool $fromApi)
459
	{
460
		$moduleName = rtrim($field['moduleName'], 's');
461
		$key = mb_strtolower($moduleName);
462
		if (null === $this->{$key}) {
463
			$this->{$key} = $this->synchronizer->getMapModel($moduleName);
464
		}
465
		$this->{$key}->setDataApi($this->dataApi);
466
		return $this->{$key}->saveFromRelation($field);
467
	}
468
469
	/**
470
	 * Find relationship in YF by API ID.
471
	 *
472
	 * @param mixed $value
473
	 * @param array $field
474
	 * @param bool  $fromApi
475
	 *
476
	 * @return mixed
477
	 */
478
	protected function findBySynchronizer($value, array $field, bool $fromApi)
479
	{
480
		$synchronizer = $this->synchronizer->controller->getSync($field['synchronizer']);
481
		if ($fromApi) {
482
			$return = $synchronizer->getYfValue($value, $field);
483
		} else {
484
			$return = $synchronizer->getApiValue($value, $field);
485
		}
486
		if (null === $return && (!\array_key_exists('optional', $field) || empty($field['optional']))) {
0 ignored issues
show
introduced by
The condition null === $return is always false.
Loading history...
487
			$this->skip = true;
488
			$this->synchronizer->controller->log(
489
				($fromApi ? '[API>YF]' : '[YF>API]') .
490
				"Skip value: {$value} (Field: {$field['fieldCrm']} ,Sync: {$field['synchronizer']})",
491
				['fieldConfig' => $field, 'data' => $this->dataApi], null, true
492
			);
493
		}
494
		return $return;
495
	}
496
497
	/**
498
	 * Save record in YF from relation action.
499
	 *
500
	 * @param array $field
501
	 *
502
	 * @return int
503
	 */
504
	public function saveFromRelation(array $field): int
505
	{
506
		$id = 0;
507
		if ($dataYf = $this->getDataYf()) {
508
			try {
509
				$id = $this->findRecordInYf();
510
				if (empty($field['onlyCreate']) || empty($id)) {
511
					$this->loadRecordModel($id);
512
					$this->loadAdditionalData();
513
					$this->saveInYf();
514
					$id = $this->getRecordModel()->getId();
515
				}
516
			} catch (\Throwable $ex) {
517
				$error = "[API>YF] Import {$this->moduleName}";
518
				\App\Log::warning($error . "\n" . $ex->getMessage(), $this->synchronizer::LOG_CATEGORY);
519
				$this->synchronizer->controller->log($error, ['YF' => $dataYf, 'API' => $this->dataApi], $ex);
520
			}
521
		}
522
		return $id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $id could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
523
	}
524
525
	/**
526
	 * Run dependent synchronizer.
527
	 *
528
	 * @param bool $fromApi
529
	 *
530
	 * @return void
531
	 */
532
	protected function runDependentSynchronizer(bool $fromApi): void
533
	{
534
		if (empty($this->dependentSynchronizations)) {
535
			return;
536
		}
537
		foreach ($this->dependentSynchronizations as $synchronizer) {
538
			$synchronizer = $this->synchronizer->controller->getSync($synchronizer);
539
			if ($fromApi) {
540
				if (method_exists($synchronizer, 'importFromDependent')) {
541
					$synchronizer->importFromDependent($this);
542
				}
543
			} else {
544
				if (method_exists($synchronizer, 'exportFromDependent')) {
545
					$synchronizer->exportFromDependent($this);
546
				}
547
			}
548
		}
549
	}
550
551
	/**
552
	 * Find record in YetiFoce.  It can only be based on data from CRM `$this->dataApi`.
553
	 *
554
	 * @return int|null
555
	 */
556
	public function findRecordInYf(): ?int
557
	{
558
		return $this->synchronizer->getYfId($this->dataApi['id'], $this->moduleName);
559
	}
560
561
	/**
562
	 * Find record in API. It can only be based on data from CRM `$this->dataYf`.
563
	 *
564
	 * @return int
565
	 */
566
	public function findRecordInApi(): int
567
	{
568
		return $this->synchronizer->getApiId($this->dataYf['id'], $this->moduleName);
569
	}
570
571
	/**
572
	 * Convert phone number to system YF format.
573
	 *
574
	 * @param mixed $value
575
	 * @param array $field
576
	 * @param bool  $fromApi
577
	 *
578
	 * @return string
579
	 */
580
	protected function convertPhone($value, array $field, bool $fromApi)
581
	{
582
		if (empty($value) || !$fromApi) {
583
			return $value;
584
		}
585
		$fieldCrm = $field['fieldCrm'];
586
		$parsedData = [$fieldCrm => $value];
587
		$parsedData = \App\Fields\Phone::parsePhone($fieldCrm, $parsedData);
588
		if (empty($parsedData[$fieldCrm])) {
589
			foreach ($parsedData as $key => $value) {
0 ignored issues
show
introduced by
$value is overwriting one of the parameters of this function.
Loading history...
590
				$this->dataYf[$key] = $value;
591
			}
592
			return '';
593
		}
594
		return $parsedData[$fieldCrm];
595
	}
596
597
	/**
598
	 * Convert country to system format.
599
	 *
600
	 * @param mixed $value
601
	 * @param array $field
602
	 * @param bool  $fromApi
603
	 *
604
	 * @return string|null Country name (YF) or Country code (API)
605
	 */
606
	protected function convertCountry($value, array $field, bool $fromApi)
607
	{
608
		if (empty($value)) {
609
			return $value;
610
		}
611
		return $fromApi ? \App\Fields\Country::getCountryName($value) : \App\Fields\Country::getCountryCode($value);
612
	}
613
614
	/**
615
	 * Convert currency.
616
	 *
617
	 * @param mixed $value
618
	 * @param array $field
619
	 * @param bool  $fromApi
620
	 *
621
	 * @return int|string int (YF) or string (API)
622
	 */
623
	protected function convertCurrency($value, array $field, bool $fromApi)
624
	{
625
		if ($fromApi) {
626
			$currency = \App\Fields\Currency::getIdByCode($value);
627
			if (empty($currency)) {
628
				$currency = \App\Fields\Currency::addCurrency($value);
629
			}
630
		} else {
631
			$currency = \App\Fields\Currency::getById($value)['currency_code'];
632
		}
633
		return $currency;
634
	}
635
636
	/**
637
	 * Load additional data.
638
	 *
639
	 * @return void
640
	 */
641
	public function loadAdditionalData(): void
642
	{
643
	}
644
}
645