| Total Complexity | 41 | 
| Total Lines | 286 | 
| Duplicated Lines | 0 % | 
| Changes | 1 | ||
| Bugs | 0 | Features | 0 | 
Complex classes like Mapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Mapper, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 14 | class Mapper extends Service  | 
            ||
| 15 | { | 
            ||
| 16 | |||
| 17 | /**  | 
            ||
| 18 | * @var  | 
            ||
| 19 | */  | 
            ||
| 20 | private $file = null;  | 
            ||
| 21 | |||
| 22 | /**  | 
            ||
| 23 | * @var JsonMachine  | 
            ||
| 24 | */  | 
            ||
| 25 | private $productStream;  | 
            ||
| 26 | |||
| 27 | /**  | 
            ||
| 28 | * @var JsonMachine  | 
            ||
| 29 | */  | 
            ||
| 30 | private $assetStream;  | 
            ||
| 31 | |||
| 32 | /**  | 
            ||
| 33 | * @var array  | 
            ||
| 34 | */  | 
            ||
| 35 | private $currentUniqueFields;  | 
            ||
| 36 | |||
| 37 | /**  | 
            ||
| 38 | * @var int  | 
            ||
| 39 | */  | 
            ||
| 40 | private $importCount = 0;  | 
            ||
| 41 | |||
| 42 | /**  | 
            ||
| 43 | * Mapper constructor.  | 
            ||
| 44 | * @param string $importerKey  | 
            ||
| 45 | * @param $file  | 
            ||
| 46 | * @throws \Exception  | 
            ||
| 47 | */  | 
            ||
| 48 | public function __construct($importerKey, $file = null)  | 
            ||
| 49 |     { | 
            ||
| 50 | parent::__construct($importerKey);  | 
            ||
| 51 |         if (!$this->config()->get('mapping')) { | 
            ||
| 52 |             throw  new Exception('A Mapper needs a mapping'); | 
            ||
| 53 | }  | 
            ||
| 54 | |||
| 55 |         if ($file !== null) { | 
            ||
| 56 | $this->file = $file;  | 
            ||
| 57 | $this->productStream = JsonMachine::fromFile($file, '/4/products');  | 
            ||
| 58 | $this->resetAssetStream();  | 
            ||
| 59 | }  | 
            ||
| 60 | }  | 
            ||
| 61 | |||
| 62 | /**  | 
            ||
| 63 | *  | 
            ||
| 64 | */  | 
            ||
| 65 | public function resetAssetStream()  | 
            ||
| 66 |     { | 
            ||
| 67 | $this->assetStream = JsonMachine::fromFile($this->file, '/3/digital_assets');  | 
            ||
| 68 | }  | 
            ||
| 69 | |||
| 70 | /**  | 
            ||
| 71 | * Maps the data  | 
            ||
| 72 | * @throws \Exception  | 
            ||
| 73 | */  | 
            ||
| 74 | public function map()  | 
            ||
| 83 | }  | 
            ||
| 84 | |||
| 85 | /**  | 
            ||
| 86 | * @param string|DataObject $class  | 
            ||
| 87 | * @param array $mappings The mapping for a specific class  | 
            ||
| 88 | * @param array $data  | 
            ||
| 89 | *  | 
            ||
| 90 | * @return DataObject  | 
            ||
| 91 | * @throws \Exception  | 
            ||
| 92 | */  | 
            ||
| 93 | public function mapToObject($class, $mappings, $data)  | 
            ||
| 137 | }  | 
            ||
| 138 | |||
| 139 | /**  | 
            ||
| 140 | * @param string $class  | 
            ||
| 141 | * @param array $mappings  | 
            ||
| 142 | * @param array $data  | 
            ||
| 143 | *  | 
            ||
| 144 | * @return \SilverStripe\ORM\DataObject  | 
            ||
| 145 | */  | 
            ||
| 146 | private function findObjectByUnique($class, $mappings, $data)  | 
            ||
| 147 |     { | 
            ||
| 148 | $uniqueFields = $this->uniqueFields($mappings);  | 
            ||
| 149 | // creates a filter  | 
            ||
| 150 | $filter = [];  | 
            ||
| 151 |         foreach ($uniqueFields as $dbField => $salsifyField) { | 
            ||
| 152 | |||
| 153 | $modifiedData = $data;  | 
            ||
| 154 | $fieldMapping = $mappings[$dbField];  | 
            ||
| 155 |             if (array_key_exists('modification', $fieldMapping)) { | 
            ||
| 156 | $modifiedData = $this->handleModification(  | 
            ||
| 157 | $fieldMapping['modification'],  | 
            ||
| 158 | $dbField,  | 
            ||
| 159 | $fieldMapping,  | 
            ||
| 160 | $modifiedData  | 
            ||
| 161 | );  | 
            ||
| 162 | }  | 
            ||
| 163 | |||
| 164 | // adds unique fields to filter  | 
            ||
| 165 | $filter[$dbField] = $modifiedData[$salsifyField];  | 
            ||
| 166 | }  | 
            ||
| 167 | |||
| 168 | return DataObject::get($class)->filter($filter)->first();  | 
            ||
| 169 | }  | 
            ||
| 170 | |||
| 171 | /**  | 
            ||
| 172 | * Gets a list of all the unique field keys  | 
            ||
| 173 | *  | 
            ||
| 174 | * @param array $mappings  | 
            ||
| 175 | * @return array  | 
            ||
| 176 | */  | 
            ||
| 177 | private function uniqueFields($mappings)  | 
            ||
| 178 |     { | 
            ||
| 179 | // cached after first map  | 
            ||
| 180 |         if (!empty($this->currentUniqueFields)) { | 
            ||
| 181 | return $this->currentUniqueFields;  | 
            ||
| 182 | }  | 
            ||
| 183 | |||
| 184 | $uniqueFields = [];  | 
            ||
| 185 |         foreach ($mappings as $dbField => $salsifyField) { | 
            ||
| 186 |             if (!is_array($salsifyField)) { | 
            ||
| 187 | continue;  | 
            ||
| 188 | }  | 
            ||
| 189 | |||
| 190 |             if (!array_key_exists('unique', $salsifyField) || | 
            ||
| 191 |                 !array_key_exists('salsifyField', $salsifyField)) { | 
            ||
| 192 | continue;  | 
            ||
| 193 | }  | 
            ||
| 194 | |||
| 195 |             if ($salsifyField['unique'] !== true) { | 
            ||
| 196 | continue;  | 
            ||
| 197 | }  | 
            ||
| 198 | |||
| 199 | $uniqueFields[$dbField] = $salsifyField['salsifyField'];  | 
            ||
| 200 | }  | 
            ||
| 201 | |||
| 202 | $this->currentUniqueFields = $uniqueFields;  | 
            ||
| 203 | return $uniqueFields;  | 
            ||
| 204 | }  | 
            ||
| 205 | |||
| 206 | /**  | 
            ||
| 207 | * @param string $mod  | 
            ||
| 208 | * @param string $dbField  | 
            ||
| 209 | * @param array $config  | 
            ||
| 210 | * @param array $data  | 
            ||
| 211 | * @return array  | 
            ||
| 212 | */  | 
            ||
| 213 | private function handleModification($mod, $dbField, $config, $data)  | 
            ||
| 214 |     { | 
            ||
| 215 |         if ($this->hasMethod($mod)) { | 
            ||
| 216 |             return $this->{$mod}($dbField, $config, $data); | 
            ||
| 217 | }  | 
            ||
| 218 |         ImportTask::output("{$mod} is not a valid field modifier. skipping modification for field {$dbField}."); | 
            ||
| 219 | return $data;  | 
            ||
| 220 | }  | 
            ||
| 221 | |||
| 222 | /**  | 
            ||
| 223 | * @param string|array $field  | 
            ||
| 224 | * @return string  | 
            ||
| 225 | */  | 
            ||
| 226 | public function getFieldType($field)  | 
            ||
| 227 |     { | 
            ||
| 228 |         $fieldTypes = $this->config()->get('field_types'); | 
            ||
| 229 |         if (is_array($field) && array_key_exists('type', $field)) { | 
            ||
| 230 |             if (in_array($field['type'], $fieldTypes)) { | 
            ||
| 231 | return $field['type'];  | 
            ||
| 232 | }  | 
            ||
| 233 | }  | 
            ||
| 234 | return 'Raw';  | 
            ||
| 235 | }  | 
            ||
| 236 | |||
| 237 | /**  | 
            ||
| 238 | * @param int $type  | 
            ||
| 239 | * @param array $salsifyData  | 
            ||
| 240 | * @param string $salsifyField  | 
            ||
| 241 | * @param array $dbFieldConfig  | 
            ||
| 242 | * @param string $dbField  | 
            ||
| 243 | * @param string $class  | 
            ||
| 244 | *  | 
            ||
| 245 | * @return mixed  | 
            ||
| 246 | */  | 
            ||
| 247 | private function handleType($type, $salsifyData, $salsifyField, $dbFieldConfig, $dbField, $class)  | 
            ||
| 248 |     { | 
            ||
| 249 |         if ($this->hasMethod("handle{$type}Type")) { | 
            ||
| 250 |             return $this->{"handle{$type}Type"}($salsifyData, $salsifyField, $dbFieldConfig, $dbField, $class); | 
            ||
| 251 | }  | 
            ||
| 252 |         ImportTask::output("{$type} is not a valid type. skipping field {$dbField}."); | 
            ||
| 253 | return '';  | 
            ||
| 254 | }  | 
            ||
| 255 | |||
| 256 | /**  | 
            ||
| 257 | * @param DataObject $object  | 
            ||
| 258 | * @param string $dbField  | 
            ||
| 259 | * @param mixed $value  | 
            ||
| 260 | *  | 
            ||
| 261 | * @throws \Exception  | 
            ||
| 262 | */  | 
            ||
| 263 | private function writeValue($object, $dbField, $value)  | 
            ||
| 264 |     { | 
            ||
| 265 |         $isManyRelation = array_key_exists($dbField, $object->config()->get('has_many')) || | 
            ||
| 266 |             array_key_exists($dbField, $object->config()->get('many_many')) || | 
            ||
| 267 |             array_key_exists($dbField, $object->config()->get('belongs_many_many')); | 
            ||
| 268 | |||
| 269 |         if (!$isManyRelation) { | 
            ||
| 270 | $object->$dbField = $value;  | 
            ||
| 271 | return;  | 
            ||
| 272 | }  | 
            ||
| 273 | |||
| 274 |         if (!$object->exists()) { | 
            ||
| 275 | $object->write();  | 
            ||
| 276 | }  | 
            ||
| 277 | |||
| 278 |         if (is_array($value)) { | 
            ||
| 279 |             $object->{$dbField}()->addMany($value); | 
            ||
| 280 | return;  | 
            ||
| 281 | }  | 
            ||
| 282 | |||
| 283 |         $object->{$dbField}()->add($value); | 
            ||
| 284 | }  | 
            ||
| 285 | |||
| 286 | /**  | 
            ||
| 287 | * @return \JsonMachine\JsonMachine  | 
            ||
| 288 | */  | 
            ||
| 289 | public function getAssetStream()  | 
            ||
| 290 |     { | 
            ||
| 291 | return $this->assetStream;  | 
            ||
| 292 | }  | 
            ||
| 293 | |||
| 294 | /**  | 
            ||
| 295 | * @return bool  | 
            ||
| 296 | */  | 
            ||
| 297 | public function hasFile()  | 
            ||
| 300 | }  | 
            ||
| 301 | }  | 
            ||
| 302 |