Passed
Pull Request — master (#16)
by Matthew
01:54
created

Mapper::findOrCreateFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Dynamic\Salsify\Model;
4
5
use Dynamic\Salsify\Task\ImportTask;
6
use Exception;
7
use JsonMachine\JsonMachine;
8
use SilverStripe\ORM\DataObject;
9
10
/**
11
 * Class Mapper
12
 * @package Dynamic\Salsify\Model
13
 */
14
class Mapper extends Service
15
{
16
    /**
17
     * @var
18
     */
19
    private $file;
20
21
    /**
22
     * @var JsonMachine
23
     */
24
    private $productStream;
25
26
    /**
27
     * @var JsonMachine
28
     */
29
    private $assetStream;
30
31
    /**
32
     * @var array
33
     */
34
    private $currentUniqueFields;
35
36
    /**
37
     * @var int
38
     */
39
    private $importCount = 0;
40
41
    /**
42
     * Mapper constructor.
43
     * @param string $importerKey
44
     * @param $file
45
     * @throws \Exception
46
     */
47
    public function __construct($importerKey, $file)
48
    {
49
        parent::__construct($importerKey);
50
        if (!$this->config()->get('mapping')) {
51
            throw  new Exception('A Mapper needs a mapping');
52
        }
53
54
        $this->file = $file;
55
        $this->productStream = JsonMachine::fromFile($file, '/4/products');
56
        $this->resetAssetStream();
57
    }
58
59
    /**
60
     *
61
     */
62
    public function resetAssetStream()
63
    {
64
        $this->assetStream = JsonMachine::fromFile($this->file, '/3/digital_assets');
65
    }
66
67
    /**
68
     * Maps the data
69
     * @throws \Exception
70
     */
71
    public function map()
72
    {
73
        foreach ($this->productStream as $name => $data) {
74
            foreach ($this->config()->get('mapping') as $class => $mappings) {
75
                $this->mapToObject($class, $mappings, $data);
76
                $this->currentUniqueFields = [];
77
            }
78
        }
79
        ImportTask::echo("Imported and updated $this->importCount products.");
80
    }
81
82
    /**
83
     * @param string|DataObject $class
84
     * @param array $mappings The mapping for a specific class
85
     * @param array $data
86
     * @throws \Exception
87
     */
88
    private function mapToObject($class, $mappings, $data)
89
    {
90
        $object = $this->findObjectByUnique($class, $mappings, $data);
91
        if (!$object) {
0 ignored issues
show
introduced by
$object is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
92
            $object = $class::create();
93
        }
94
95
        $fieldTypes = $this->config()->get('field_types');
96
97
        $firstUniqueKey = array_keys($this->uniqueFields($mappings))[0];
98
        $firstUniqueValue = $data[$mappings[$firstUniqueKey]['salsifyField']];
99
        ImportTask::echo("Updating $firstUniqueKey $firstUniqueValue");
100
101
        foreach ($mappings as $dbField => $salsifyField) {
102
            // default to raw
103
            $type = 'Raw';
104
            if (is_array($salsifyField)) {
105
                if (!array_key_exists('salsifyField', $salsifyField)) {
106
                    continue;
107
                }
108
109
                if (array_key_exists('type', $salsifyField)) {
110
                    if (in_array($salsifyField['type'], $fieldTypes)) {
111
                        $type = $salsifyField['type'];
112
                    }
113
                }
114
115
                $salsifyField = $salsifyField['salsifyField'];
116
            }
117
118
            if (!array_key_exists($salsifyField, $data)) {
119
                ImportTask::echo("Skipping mapping for field $salsifyField for $firstUniqueKey $firstUniqueValue");
120
                continue;
121
            }
122
123
            // TODO - handle has_many and many_many fields
124
            $object->$dbField = $this->handleType($type, $data[$salsifyField], $dbField, $class);
125
        }
126
127
        if ($object->isChanged()) {
128
            $object->write();
129
            $this->importCount++;
130
        } else {
131
            ImportTask::echo("$firstUniqueKey $firstUniqueValue was not changed.");
132
        }
133
    }
134
135
    /**
136
     * @param string $class
137
     * @param array $mappings
138
     * @param array $data
139
     *
140
     * @return \SilverStripe\ORM\DataObject
141
     */
142
    private function findObjectByUnique($class, $mappings, $data)
143
    {
144
        $uniqueFields = $this->uniqueFields($mappings);
145
        // creates a filter
146
        $filter = [];
147
        foreach ($uniqueFields as $dbField => $salsifyField) {
148
            // adds unique fields to filter
149
            $filter[$dbField] = $data[$salsifyField];
150
        }
151
152
        return DataObject::get($class)->filter($filter)->first();
153
    }
154
155
    /**
156
     * Gets a list of all the unique field keys
157
     *
158
     * @param array $mappings
159
     * @return array
160
     */
161
    private function uniqueFields($mappings)
162
    {
163
        // cached after first map
164
        if (!empty($this->currentUniqueFields)) {
165
            return $this->currentUniqueFields;
166
        }
167
168
        $uniqueFields = [];
169
        foreach ($mappings as $dbField => $salsifyField) {
170
            if (!is_array($salsifyField)) {
171
                continue;
172
            }
173
174
            if (!array_key_exists('unique', $salsifyField) ||
175
                !array_key_exists('salsifyField', $salsifyField)) {
176
                continue;
177
            }
178
179
            if ($salsifyField['unique'] !== true) {
180
                continue;
181
            }
182
183
            $uniqueFields[$dbField] = $salsifyField['salsifyField'];
184
        }
185
186
        $this->currentUniqueFields = $uniqueFields;
187
        return $uniqueFields;
188
    }
189
190
    /**
191
     * @param int $type
192
     * @param string|int $value
193
     * @param string $field
194
     * @param $class
195
     * @return mixed
196
     * @throws \Exception
197
     */
198
    private function handleType($type, $value, $field, $class)
199
    {
200
        if ($this->hasMethod("handle{$type}Type")) {
201
            return $this->{"handle{$type}Type"}($value, $field, $class);
202
        } else {
203
            ImportTask::echo("{$type} is not a valid type. skipping field {$field}.");
204
        }
205
        return '';
206
    }
207
208
    /**
209
     * @return \JsonMachine\JsonMachine
210
     */
211
    public function getAssetStream()
212
    {
213
        return $this->assetStream;
214
    }
215
}
216