|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace NerdsAndCompany\Schematic\Mappers; |
|
4
|
|
|
|
|
5
|
|
|
use Craft; |
|
6
|
|
|
use craft\base\Model; |
|
7
|
|
|
use craft\helpers\ArrayHelper; |
|
8
|
|
|
use NerdsAndCompany\Schematic\Schematic; |
|
9
|
|
|
use NerdsAndCompany\Schematic\Converters\Base as BaseConverter; |
|
10
|
|
|
use NerdsAndCompany\Schematic\Interfaces\ConverterInterface; |
|
11
|
|
|
use NerdsAndCompany\Schematic\Interfaces\MapperInterface; |
|
12
|
|
|
use yii\base\Component as BaseComponent; |
|
13
|
|
|
|
|
14
|
|
|
/** |
|
15
|
|
|
* Schematic Model Mapper. |
|
16
|
|
|
* |
|
17
|
|
|
* Sync Craft Setups. |
|
18
|
|
|
* |
|
19
|
|
|
* @author Nerds & Company |
|
20
|
|
|
* @copyright Copyright (c) 2015-2018, Nerds & Company |
|
21
|
|
|
* @license MIT |
|
22
|
|
|
* |
|
23
|
|
|
* @see http://www.nerds.company |
|
24
|
|
|
*/ |
|
25
|
|
|
class ModelMapper extends BaseComponent implements MapperInterface |
|
26
|
|
|
{ |
|
27
|
|
|
/** |
|
28
|
|
|
* Get all record definitions. |
|
29
|
|
|
* |
|
30
|
|
|
* @return array |
|
31
|
|
|
*/ |
|
32
|
|
|
public function export(array $records): array |
|
33
|
|
|
{ |
|
34
|
|
|
$result = []; |
|
35
|
|
|
foreach ($records as $record) { |
|
36
|
|
|
$modelClass = get_class($record); |
|
37
|
|
|
$converter = $this->getConverter($modelClass); |
|
38
|
|
|
if (false == $converter) { |
|
39
|
|
|
Schematic::error('No converter found for '.$modelClass); |
|
40
|
|
|
continue; |
|
41
|
|
|
} |
|
42
|
|
|
$result[$record->handle] = $converter->getRecordDefinition($record); |
|
43
|
|
|
} |
|
44
|
|
|
|
|
45
|
|
|
return $result; |
|
46
|
|
|
} |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* Import records. |
|
50
|
|
|
* |
|
51
|
|
|
* @param array $definitions |
|
52
|
|
|
* @param Model $records The existing records |
|
53
|
|
|
* @param array $defaultAttributes Default attributes to use for each record |
|
54
|
|
|
* @param bool $persist Whether to persist the parsed records |
|
55
|
|
|
*/ |
|
56
|
|
|
public function import(array $definitions, array $records, array $defaultAttributes = [], $persist = true): array |
|
57
|
|
|
{ |
|
58
|
|
|
$imported = []; |
|
59
|
|
|
$recordsByHandle = ArrayHelper::index($records, 'handle'); |
|
60
|
|
|
foreach ($definitions as $handle => $definition) { |
|
61
|
|
|
$modelClass = $definition['class']; |
|
62
|
|
|
$converter = $this->getConverter($modelClass); |
|
63
|
|
|
if (false == $converter) { |
|
64
|
|
|
Schematic::error('No converter found for '.$modelClass); |
|
65
|
|
|
continue; |
|
66
|
|
|
} |
|
67
|
|
|
$record = $this->findOrNewRecord($recordsByHandle, $definition, $handle); |
|
68
|
|
|
|
|
69
|
|
|
if ($converter->getRecordDefinition($record) === $definition) { |
|
70
|
|
|
Schematic::info('- Skipping '.get_class($record).' '.$handle); |
|
71
|
|
|
} else { |
|
72
|
|
|
$converter->setRecordAttributes($record, $definition, $defaultAttributes); |
|
73
|
|
|
if ($persist) { |
|
74
|
|
|
Schematic::info('- Saving '.get_class($record).' '.$handle); |
|
75
|
|
|
if ($converter->saveRecord($record, $definition)) { |
|
|
|
|
|
|
76
|
|
|
} else { |
|
77
|
|
|
Schematic::importError($record, $handle); |
|
78
|
|
|
} |
|
79
|
|
|
} |
|
80
|
|
|
} |
|
81
|
|
|
$imported[] = $record; |
|
82
|
|
|
unset($recordsByHandle[$handle]); |
|
83
|
|
|
} |
|
84
|
|
|
|
|
85
|
|
|
if (Schematic::$force && $persist) { |
|
86
|
|
|
// Delete records not in definitions |
|
87
|
|
|
foreach ($recordsByHandle as $handle => $record) { |
|
88
|
|
|
$modelClass = get_class($record); |
|
89
|
|
|
Schematic::info('- Deleting '.get_class($record).' '.$handle); |
|
90
|
|
|
$converter = $this->getConverter($modelClass); |
|
91
|
|
|
$converter->deleteRecord($record); |
|
92
|
|
|
} |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
return $imported; |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
/** |
|
99
|
|
|
* Find record from records by handle or new record. |
|
100
|
|
|
* |
|
101
|
|
|
* @param Model[] $recordsByHandle |
|
102
|
|
|
* @param array $definition |
|
103
|
|
|
* @param string $handle |
|
104
|
|
|
* |
|
105
|
|
|
* @return Model |
|
106
|
|
|
*/ |
|
107
|
|
|
private function findOrNewRecord(array $recordsByHandle, array $definition, string $handle): Model |
|
108
|
|
|
{ |
|
109
|
|
|
$record = new $definition['class'](); |
|
110
|
|
|
if (array_key_exists($handle, $recordsByHandle)) { |
|
111
|
|
|
$existing = $recordsByHandle[$handle]; |
|
112
|
|
|
if (get_class($record) == get_class($existing)) { |
|
113
|
|
|
$record = $existing; |
|
114
|
|
|
} else { |
|
115
|
|
|
$record->id = $existing->id; |
|
116
|
|
|
$record->setAttributes($existing->getAttributes()); |
|
117
|
|
|
} |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
return $record; |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
/** |
|
124
|
|
|
* Find converter class for model. |
|
125
|
|
|
* |
|
126
|
|
|
* @param string $modelClass |
|
127
|
|
|
* |
|
128
|
|
|
* @return BaseConverter |
|
129
|
|
|
*/ |
|
130
|
|
|
protected function getConverter(string $modelClass) |
|
131
|
|
|
{ |
|
132
|
|
|
if ($modelClass) { |
|
133
|
|
|
$converterClass = 'NerdsAndCompany\\Schematic\\Converters\\'.ucfirst(str_replace('craft\\', '', $modelClass)); |
|
134
|
|
|
if (class_exists($converterClass)) { |
|
135
|
|
|
$converter = new $converterClass(); |
|
136
|
|
|
if ($converter instanceof ConverterInterface) { |
|
137
|
|
|
return $converter; |
|
|
|
|
|
|
138
|
|
|
} |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
return $this->getConverter(get_parent_class($modelClass)); |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
return false; |
|
|
|
|
|
|
145
|
|
|
} |
|
146
|
|
|
} |
|
147
|
|
|
|
This check looks for the bodies of
ifstatements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
ifbodies can be removed. If you have an empty if but statements in theelsebranch, consider inverting the condition.could be turned into
This is much more concise to read.