Completed
Push — asset-folders-fix ( f29857...40d594 )
by Bart
02:14
created

SourcesBehavior   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 5

Test Coverage

Coverage 85.29%

Importance

Changes 0
Metric Value
wmc 43
lcom 0
cbo 5
dl 0
loc 197
ccs 87
cts 102
cp 0.8529
rs 8.96
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A findSources() 0 14 5
A getSources() 0 13 3
F getSource() 0 95 32
A getFolderById() 0 12 2
A getFolderByHandle() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like SourcesBehavior 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 SourcesBehavior, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace NerdsAndCompany\Schematic\Behaviors;
4
5
use Craft;
6
use TypeError;
7
use yii\base\Behavior;
8
use craft\base\Model;
9
use craft\records\VolumeFolder;
10
use NerdsAndCompany\Schematic\Schematic;
11
use NerdsAndCompany\Schematic\Events\SourceMappingEvent;
12
13
/**
14
 * Schematic Sources Behavior.
15
 *
16
 * Sync Craft Setups.
17
 *
18
 * @author    Nerds & Company
19
 * @copyright Copyright (c) 2015-2018, Nerds & Company
20
 * @license   MIT
21
 *
22
 * @see      http://www.nerds.company
23
 */
24
class SourcesBehavior extends Behavior
25
{
26
    /**
27
     * Recursively find sources in definition attributes.
28
     *
29
     * @param string $fieldType
30
     * @param array  $attributes
31
     * @param string $indexFrom
32
     * @param string $indexTo
33
     *
34
     * @return array
35
     */
36 31
    public function findSources(string $fieldType, array $attributes, string $indexFrom, string $indexTo): array
37
    {
38 31
        foreach ($attributes as $key => $attribute) {
39 31
            if ($key === 'source') {
40 3
                $attributes[$key] = $this->getSource($fieldType, $attribute, $indexFrom, $indexTo);
41 31
            } elseif ($key === 'sources') {
42 3
                $attributes[$key] = $this->getSources($fieldType, $attribute, $indexFrom, $indexTo);
43 31
            } elseif (is_array($attribute)) {
44 31
                $attributes[$key] = $this->findSources($fieldType, $attribute, $indexFrom, $indexTo);
45
            }
46
        }
47
48 31
        return $attributes;
49
    }
50
51
    /**
52
     * Get sources based on the indexFrom attribute and return them with the indexTo attribute.
53
     *
54
     * @param string       $fieldType
55
     * @param string|array $sources
56
     * @param string       $indexFrom
57
     * @param string       $indexTo
58
     *
59
     * @return array|string
60
     */
61 8
    public function getSources(string $fieldType, $sources, string $indexFrom, string $indexTo)
62
    {
63 8
        $mappedSources = $sources;
64 8
        if (is_array($sources)) {
65 6
            $mappedSources = [];
66 6
            $sources = array_filter($sources);
67 6
            foreach ($sources as $source) {
68 6
                $mappedSources[] = $this->getSource($fieldType, $source, $indexFrom, $indexTo);
69
            }
70
        }
71
72 8
        return $mappedSources;
73
    }
74
75
    /**
76
     * Gets a source by the attribute indexFrom, and returns it with attribute $indexTo.
77
     *
78
     * @TODO Break up and simplify this method
79
     *
80
     * @param string $fieldType
81
     * @param string $source
82
     * @param string $indexFrom
83
     * @param string $indexTo
84
     *
85
     * @return string|null
86
     *
87
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
88
     * @SuppressWarnings(PHPMD.NPathComplexity)
89
     */
90 9
    public function getSource(string $fieldType, string $source = null, string $indexFrom, string $indexTo)
91
    {
92 9
        if (false === strpos($source, ':')) {
93 6
            return $source;
94
        }
95
96
        /** @var Model $sourceObject */
97 9
        $sourceObject = null;
98
99
        // Get service and method by source
100 9
        list($sourceType, $sourceFrom) = explode(':', $source);
101
        switch ($sourceType) {
102 9
            case 'editSite':
103
                $service = Craft::$app->sites;
104
                $method = 'getSiteBy';
105
                break;
106 9
            case 'single':
107 9
            case 'section':
108 9
            case 'createEntries':
109 9
            case 'editPeerEntries':
110 9
            case 'deleteEntries':
111 9
            case 'deletePeerEntries':
112 9
            case 'deletePeerEntryDrafts':
113 9
            case 'editEntries':
114 9
            case 'editPeerEntryDrafts':
115 9
            case 'publishEntries':
116 9
            case 'publishPeerEntries':
117 9
            case 'publishPeerEntryDrafts':
118 5
                $service = Craft::$app->sections;
119 5
                $method = 'getSectionBy';
120 5
                break;
121 9
            case 'group':
122 7
            case 'editCategories':
123 5
                $service = 'Users' == $fieldType ? Craft::$app->userGroups : Craft::$app->categories;
124 5
                $method = 'getGroupBy';
125 5
                break;
126 7
            case 'folder':
127 2
                $service = $this;
128 2
                $method = 'getFolderBy';
129 2
                break;
130 5
            case 'createFoldersInVolume':
131 5
            case 'deleteFilesAndFoldersInVolume':
132 5
            case 'saveAssetInVolume':
133 5
            case 'viewVolume':
134 3
                $service = Craft::$app->volumes;
135 3
                $method = 'getVolumeBy';
136 3
                break;
137 2
            case 'taggroup':
138
                $service = Craft::$app->tags;
139
                $method = 'getTagGroupBy';
140
                break;
141 2
            case 'field':
142 2
                $service = Craft::$app->fields;
143 2
                $method = 'getFieldBy';
144 2
                break;
145
            case 'editGlobalSet':
146
                $service = Craft::$app->globals;
147
                $method = 'getSetBy';
148
                break;
149
            case 'utility':
150
                return $source;
151
        }
152
153
        // Send event
154 9
        $plugin = Craft::$app->controller->module;
155 9
        $event = new SourceMappingEvent([
156 9
            'source' => $source,
157 9
            'service' => $service ?? null,
158 9
            'method' => $method ?? null,
159
        ]);
160 9
        $plugin->trigger($plugin::EVENT_MAP_SOURCE, $event);
161 9
        $service = $event->service;
162 9
        $method = $event->method;
163
164
        // Try service and method
165 9
        if (isset($service) && isset($method) && isset($sourceFrom)) {
166 9
            $method = $method.ucfirst($indexFrom);
167
            try {
168 9
                $sourceObject = $service->$method($sourceFrom);
0 ignored issues
show
Bug introduced by
The method $method cannot be called on $service (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
169 2
            } catch (TypeError $e) {
170 1
                Schematic::error('An error occured mapping source '.$source.' from '.$indexFrom.' to '.$indexTo);
171 1
                Schematic::error($e->getMessage());
172
173 1
                return null;
174
            }
175
        }
176
177 7
        if ($sourceObject) {
178 6
            return $sourceType.':'.$sourceObject->$indexTo;
179
        }
180
181 1
        Schematic::warning('No mapping found for source '.$source);
182
183 1
        return null;
184
    }
185
186
    /**
187
     * Get a folder by id
188
     *
189
     * @param int $folderId
190
     * @return object
191
     */
192 1
    private function getFolderById(int $folderId): object
193
    {
194 1
        $folder = Craft::$app->assets->getFolderById($folderId);
195 1
        if ($folder) {
196 1
            $volume = $folder->getVolume();
197
            return  (object) [
198 1
                'id' => $folderId,
199 1
                'handle' => $volume->handle
200
            ];
201
        }
202
        return null;
203
    }
204
205
    /**
206
     * Get a folder by handle
207
     *
208
     * @param string $folderHandle
209
     * @return object
210
     */
211 1
    private function getFolderByHandle(string $folderHandle): object
212
    {
213 1
        $volume = Craft::$app->volumes->getVolumeByHandle($folderHandle);
214 1
        $folder = VolumeFolder::findOne(['volumeId' => $volume->id]);
215
        return  (object) [
216
            'id' => $folder->id,
217
            'handle' => $folderHandle
218
        ];
219
    }
220
}
221