SourcesBehavior::getSource()   F
last analyzed

Complexity

Conditions 33
Paths 137

Size

Total Lines 99

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 58
CRAP Score 49.3705

Importance

Changes 0
Metric Value
dl 0
loc 99
ccs 58
cts 77
cp 0.7532
rs 3.8583
c 0
b 0
f 0
cc 33
nc 137
nop 4
crap 49.3705

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 craft\fields\Users;
11
use NerdsAndCompany\Schematic\Schematic;
12
use NerdsAndCompany\Schematic\Events\SourceMappingEvent;
13
14
/**
15
 * Schematic Sources Behavior.
16
 *
17
 * Sync Craft Setups.
18
 *
19
 * @author    Nerds & Company
20
 * @copyright Copyright (c) 2015-2019, Nerds & Company
21
 * @license   MIT
22
 *
23
 * @see      http://www.nerds.company
24
 */
25
class SourcesBehavior extends Behavior
26
{
27
    /** Hack to be able to avoid the active record call in VolumeFolder::findOne() */
28
    public $mockFolder = null;
29
30
    /**
31
     * Recursively find sources in definition attributes.
32
     *
33
     * @param string $fieldType
34
     * @param array  $attributes
35
     * @param string $indexFrom
36
     * @param string $indexTo
37
     *
38
     * @return array
39
     */
40 32
    public function findSources(string $fieldType, array $attributes, string $indexFrom, string $indexTo): array
41
    {
42 32
        foreach ($attributes as $key => $attribute) {
43 32
            if ($key === 'source') {
44 4
                $attributes[$key] = $this->getSource($fieldType, $attribute, $indexFrom, $indexTo);
45 32
            } elseif ($key === 'sources') {
46 4
                $attributes[$key] = $this->getSources($fieldType, $attribute, $indexFrom, $indexTo);
47 32
            } elseif (is_array($attribute)) {
48 32
                $attributes[$key] = $this->findSources($fieldType, $attribute, $indexFrom, $indexTo);
49
            }
50
        }
51
52 32
        return $attributes;
53
    }
54
55
    /**
56
     * Get sources based on the indexFrom attribute and return them with the indexTo attribute.
57
     *
58
     * @param string       $fieldType
59
     * @param string|array $sources
60
     * @param string       $indexFrom
61
     * @param string       $indexTo
62
     *
63
     * @return array|string
64
     */
65 9
    public function getSources(string $fieldType, $sources, string $indexFrom, string $indexTo)
66
    {
67 9
        $mappedSources = $sources;
68 9
        if (is_array($sources)) {
69 7
            $mappedSources = [];
70 7
            $sources = array_filter($sources);
71 7
            foreach ($sources as $source) {
72 7
                $mappedSources[] = $this->getSource($fieldType, $source, $indexFrom, $indexTo);
73
            }
74
        }
75
76 9
        return $mappedSources;
77
    }
78
79
    /**
80
     * Gets a source by the attribute indexFrom, and returns it with attribute $indexTo.
81
     *
82
     * @TODO Break up and simplify this method
83
     *
84
     * @param string $fieldType
85
     * @param string $source
86
     * @param string $indexFrom
87
     * @param string $indexTo
88
     *
89
     * @return string|null
90
     *
91
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
92
     * @SuppressWarnings(PHPMD.NPathComplexity)
93
     */
94 9
    public function getSource(string $fieldType, string $source = null, string $indexFrom, string $indexTo)
95
    {
96 9
        if (false === strpos($source, ':')) {
97 7
            return $source;
98
        }
99
100
        /** @var Model $sourceObject */
101 9
        $sourceObject = null;
102
103
        // Get service and method by source
104 9
        list($sourceType, $sourceFrom) = explode(':', $source);
105
        switch ($sourceType) {
106 9
            case 'editSite':
107
                $service = Craft::$app->sites;
108
                $method = 'getSiteBy';
109
                break;
110 9
            case 'single':
111 9
            case 'section':
112 9
            case 'createEntries':
113 9
            case 'editPeerEntries':
114 9
            case 'deleteEntries':
115 9
            case 'deletePeerEntries':
116 9
            case 'deletePeerEntryDrafts':
117 9
            case 'editEntries':
118 9
            case 'editPeerEntryDrafts':
119 9
            case 'publishEntries':
120 9
            case 'publishPeerEntries':
121 9
            case 'publishPeerEntryDrafts':
122 5
                $service = Craft::$app->sections;
123 5
                $method = 'getSectionBy';
124 5
                break;
125 9
            case 'assignUserGroup':
126
                $service = Craft::$app->userGroups;
127
                $method = 'getGroupBy';
128
                break;
129 9
            case 'group':
130 7
            case 'editCategories':
131 5
                $service = Users::class == $fieldType ? Craft::$app->userGroups : Craft::$app->categories;
132 5
                $method = 'getGroupBy';
133 5
                break;
134 7
            case 'folder':
135 2
                $service = $this;
136 2
                $method = 'getFolderBy';
137 2
                break;
138 5
            case 'createFoldersInVolume':
139 5
            case 'deleteFilesAndFoldersInVolume':
140 5
            case 'saveAssetInVolume':
141 5
            case 'viewVolume':
142 3
                $service = Craft::$app->volumes;
143 3
                $method = 'getVolumeBy';
144 3
                break;
145 2
            case 'taggroup':
146
                $service = Craft::$app->tags;
147
                $method = 'getTagGroupBy';
148
                break;
149 2
            case 'field':
150 2
                $service = Craft::$app->fields;
151 2
                $method = 'getFieldBy';
152 2
                break;
153
            case 'editGlobalSet':
154
                $service = Craft::$app->globals;
155
                $method = 'getSetBy';
156
                break;
157
            case 'utility':
158
                return $source;
159
        }
160
161
        // Send event
162 9
        $plugin = Craft::$app->controller->module;
163 9
        $event = new SourceMappingEvent([
164 9
            'source' => $source,
165 9
            'service' => $service ?? null,
166 9
            'method' => $method ?? null,
167
        ]);
168 9
        $plugin->trigger($plugin::EVENT_MAP_SOURCE, $event);
169 9
        $service = $event->service;
170 9
        $method = $event->method;
171
172
        // Try service and method
173 9
        if (isset($service) && isset($method) && isset($sourceFrom)) {
174 9
            $method = $method.ucfirst($indexFrom);
175
            try {
176 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...
177
            } catch (TypeError $e) {
178
                Schematic::error('An error occured mapping source '.$source.' from '.$indexFrom.' to '.$indexTo);
179
                Schematic::error($e->getMessage());
180
181
                return null;
182
            }
183
        }
184
185 9
        if ($sourceObject) {
186 8
            return $sourceType.':'.$sourceObject->$indexTo;
187
        }
188
189 1
        Schematic::warning('No mapping found for source '.$source);
190
191 1
        return null;
192
    }
193
194
    /**
195
     * Get a folder by id
196
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
197
     *
198
     * @param int $folderId
199
     * @return object
200
     */
201 1
    private function getFolderById(int $folderId): \stdClass
202
    {
203 1
        $folder = Craft::$app->assets->getFolderById($folderId);
204 1
        if ($folder) {
205 1
            $volume = $folder->getVolume();
206
            return  (object) [
207 1
                'id' => $folderId,
208 1
                'handle' => $volume->handle
209
            ];
210
        }
211
        return null;
212
    }
213
214
    /**
215
     * Get folder by volume id
216
     *
217
     * @param int $volumeId
218
     * @return VolumeFolder
219
     */
220 1
    private function getFolderByVolumeId(int $volumeId): VolumeFolder
221
    {
222 1
        return $this->mockFolder ? $this->mockFolder : VolumeFolder::findOne(['volumeId' => $volumeId]);
223
    }
224
225
    /**
226
     * Set a mock folder for the tests
227
     *
228
     * @param VolumeFolder $mockFolder
229
     */
230 1
    public function setMockFolder(VolumeFolder $mockFolder)
231
    {
232 1
        $this->mockFolder = $mockFolder;
233 1
    }
234
235
    /**
236
     * Get a folder by volume handle
237
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
238
     *
239
     * @param string $folderHandle
240
     * @return object
241
     */
242 1
    private function getFolderByHandle(string $folderHandle): \stdClass
243
    {
244 1
        $volume = Craft::$app->volumes->getVolumeByHandle($folderHandle);
245 1
        if ($volume) {
246 1
            $folder = $this->getFolderByVolumeId($volume->id);
247 1
            if ($folder) {
248
                return  (object) [
249 1
                    'id' => $folder->id,
250 1
                    'handle' => $folderHandle
251
                ];
252
            }
253
        }
254
        return null;
255
    }
256
}
257