Completed
Pull Request — master (#114)
by Bart
11:49
created

Base::getRecordDefinition()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 0
cts 9
cp 0
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 15
nc 8
nop 1
crap 20
1
<?php
2
3
namespace NerdsAndCompany\Schematic\Services;
4
5
use craft\base\Model;
6
use craft\helpers\ArrayHelper;
7
use yii\base\Component as BaseComponent;
8
use NerdsAndCompany\Schematic\Behaviors\FieldLayoutBehavior;
9
use NerdsAndCompany\Schematic\Behaviors\SourcesBehavior;
10
use NerdsAndCompany\Schematic\Interfaces\MappingInterface;
11
use NerdsAndCompany\Schematic\Schematic;
12
use LogicException;
13
14
/**
15
 * Schematic Base Service.
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
abstract class Base extends BaseComponent implements MappingInterface
26
{
27
    /**
28
     * Load fieldlayout and sources behaviors
29
     *
30
     * @return array
31
     */
32
    public function behaviors()
33
    {
34
        return [
35
          FieldLayoutBehavior::className(),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
36
          SourcesBehavior::className(),
0 ignored issues
show
Deprecated Code introduced by
The method yii\base\BaseObject::className() has been deprecated with message: since 2.0.14. On PHP >=5.5, use `::class` instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
37
        ];
38
    }
39
40
    /**
41
     * Get all records
42
     *
43
     * @return Model[]
44
     */
45
    abstract protected function getRecords();
46
47 57
    //==============================================================================================================
48
    //================================================  EXPORT  ====================================================
49 57
    //==============================================================================================================
50 57
51
    /**
52
     * Get all record definitions
53
     *
54
     * @return array
55
     */
56
    public function export(array $records = null)
57
    {
58
        $records = $records ?: $this->getRecords();
59
        $result = [];
60
        foreach ($records as $record) {
61
            $result[$record->handle] = $this->getRecordDefinition($record);
62
        }
63
        return $result;
64
    }
65
66
    /**
67
     * Get single record definition
68
     *
69
     * @param  Model $record
70
     * @return array
71
     */
72
    protected function getRecordDefinition(Model $record)
73
    {
74
        $definition = [
75
          'class' => get_class($record),
76
          'attributes' => $record->attributes,
77
        ];
78
        unset($definition['attributes']['id']);
79
        unset($definition['attributes']['dateCreated']);
80
        unset($definition['attributes']['dateUpdated']);
81
82
        if (isset($definition['attributes']['sources'])) {
83
            $definition['sources'] = $this->getSources($definition['class'], $definition['attributes']['sources'], 'id', 'handle');
0 ignored issues
show
Documentation Bug introduced by
The method getSources does not exist on object<NerdsAndCompany\Schematic\Services\Base>? 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...
84
        }
85
86
        if (isset($definition['attributes']['source'])) {
87
            $definition['source'] = $this->getSource($definition['class'], $definition['attributes']['sources'], 'id', 'handle');
0 ignored issues
show
Documentation Bug introduced by
The method getSource does not exist on object<NerdsAndCompany\Schematic\Services\Base>? 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...
88
        }
89
90
        if (isset($definition['attributes']['fieldLayoutId'])) {
91
            $definition['fieldLayout'] = $this->getFieldLayoutDefinition($record->getFieldLayout());
0 ignored issues
show
Documentation Bug introduced by
The method getFieldLayoutDefinition does not exist on object<NerdsAndCompany\Schematic\Services\Base>? 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...
92
            unset($definition['attributes']['fieldLayoutId']);
93
        }
94
95
        return $definition;
96
    }
97
98
    //==============================================================================================================
99
    //================================================  IMPORT  ====================================================
100
    //==============================================================================================================
101
102
    /**
103
     * Import asset volumes.
104
     *
105
     * @param array $definitions
106
     * @param Model $records The existing records
107
     * @param array $defaultAttributes Default attributes to use for each record
108
     */
109
    public function import(array $definitions, array $records = [], array $defaultAttributes = [])
110
    {
111
        $records = $records ?: $this->getRecords();
112
        $recordsByHandle = ArrayHelper::index($records, 'handle');
113 4
        foreach ($definitions as $handle => $definition) {
114
            $record = new $definition['class']();
115 4
            if (array_key_exists($handle, $recordsByHandle)) {
116 4
                $record = $recordsByHandle[$handle];
117
            }
118
            Schematic::info('- Saving record '.$handle);
119
            $definition['attributes'] = array_merge($definition['attributes'], $defaultAttributes);
120
            if (!$this->saveRecord($record, $definition)) {
121
                $this->importError($record, $handle);
122
            }
123
            unset($recordsByHandle[$handle]);
124 11
        }
125
126 11
        if (Schematic::$force) {
127 11
            // Delete volumes not in definitions
128
            foreach ($recordsByHandle as $handle => $record) {
129
                Schematic::info('- Deleting record '.$handle);
130
                $this->deleteRecord($record);
131
            }
132
        }
133
    }
134
135
    /**
136
     * Log an import error
137
     *
138
     * @param  Model $record
139
     * @param  string $handle
140
     */
141
    protected function importError($record, $handle)
142
    {
143
        Schematic::warning('- Error importing record '.$handle);
144
        foreach ($record->getErrors() as $errors) {
145
            foreach ($errors as $error) {
146
                Schematic::error('   - '.$error);
147
            }
148
        }
149
    }
150
151
    /**
152
     * Save a record
153
     *
154
     * @param Model $record
155
     * @param array $definition
156
     * @return boolean
157
     */
158
    abstract protected function saveRecord(Model $record, array $definition);
159
160
    /**
161
     * Delete a record
162
     *
163
     * @param Model $record
164
     * @return boolean
165
     */
166
    abstract protected function deleteRecord(Model $record);
167
}
168