Completed
Pull Request — master (#114)
by Bart
06:03
created

ModelMapper::import()   D

Complexity

Conditions 9
Paths 12

Size

Total Lines 40
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 40
rs 4.909
c 0
b 0
f 0
cc 9
eloc 26
nc 12
nop 4
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\Interfaces\MapperInterface;
10
use yii\base\Component as BaseComponent;
11
12
/**
13
 * Schematic Model Mapper.
14
 *
15
 * Sync Craft Setups.
16
 *
17
 * @author    Nerds & Company
18
 * @copyright Copyright (c) 2015-2018, Nerds & Company
19
 * @license   MIT
20
 *
21
 * @see      http://www.nerds.company
22
 */
23
class ModelMapper extends BaseComponent implements MapperInterface
24
{
25
    /**
26
     * Get all record definitions.
27
     *
28
     * @return array
29
     */
30
    public function export(array $records): array
31
    {
32
        $result = [];
33
        foreach ($records as $record) {
34
            $modelClass = get_class($record);
35
            $converter = Craft::$app->controller->module->getConverter($modelClass);
36
            if ($converter) {
37
                $result[$record->handle] = $converter->getRecordDefinition($record);
38
            }
39
        }
40
41
        return $result;
42
    }
43
44
    /**
45
     * Import records.
46
     *
47
     * @param array $definitions
48
     * @param Model $records           The existing records
49
     * @param array $defaultAttributes Default attributes to use for each record
50
     * @param bool  $persist           Whether to persist the parsed records
51
     */
52
    public function import(array $definitions, array $records, array $defaultAttributes = [], $persist = true): array
53
    {
54
        $imported = [];
55
        $recordsByHandle = ArrayHelper::index($records, 'handle');
56
        foreach ($definitions as $handle => $definition) {
57
            $modelClass = $definition['class'];
58
            $converter = Craft::$app->controller->module->getConverter($modelClass);
59
            if ($converter) {
60
                $record = $this->findOrNewRecord($recordsByHandle, $definition, $handle);
61
62
                if ($converter->getRecordDefinition($record) === $definition) {
63
                    Schematic::info('- Skipping '.get_class($record).' '.$handle);
64
                } else {
65
                    $converter->setRecordAttributes($record, $definition, $defaultAttributes);
66
                    if ($persist) {
67
                        Schematic::info('- Saving '.get_class($record).' '.$handle);
68
                        if ($converter->saveRecord($record, $definition)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements 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 if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
69
                        } else {
70
                            Schematic::importError($record, $handle);
71
                        }
72
                    }
73
                }
74
75
                $imported[] = $record;
76
            }
77
            unset($recordsByHandle[$handle]);
78
        }
79
80
        if (Schematic::$force && $persist) {
81
            // Delete records not in definitions
82
            foreach ($recordsByHandle as $handle => $record) {
83
                $modelClass = get_class($record);
84
                Schematic::info('- Deleting '.get_class($record).' '.$handle);
85
                $converter = $this->getConverter($modelClass);
0 ignored issues
show
Documentation Bug introduced by
The method getConverter does not exist on object<NerdsAndCompany\S...ic\Mappers\ModelMapper>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
86
                $converter->deleteRecord($record);
87
            }
88
        }
89
90
        return $imported;
91
    }
92
93
    /**
94
     * Find record from records by handle or new record.
95
     *
96
     * @param Model[] $recordsByHandle
97
     * @param array   $definition
98
     * @param string  $handle
99
     *
100
     * @return Model
101
     */
102
    private function findOrNewRecord(array $recordsByHandle, array $definition, string $handle): Model
103
    {
104
        $record = new  $definition['class']();
105
        if (array_key_exists($handle, $recordsByHandle)) {
106
            $existing = $recordsByHandle[$handle];
107
            if (get_class($record) == get_class($existing)) {
108
                $record = $existing;
109
            } else {
110
                $record->id = $existing->id;
111
                $record->setAttributes($existing->getAttributes());
112
            }
113
        }
114
115
        return $record;
116
    }
117
}
118