Completed
Pull Request — master (#171)
by Bart
02:28 queued 01:06
created

SourcesBehavior::getSource()   F

Complexity

Conditions 32
Paths 132

Size

Total Lines 95

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 58
CRAP Score 42.3482

Importance

Changes 0
Metric Value
dl 0
loc 95
ccs 58
cts 74
cp 0.7838
rs 3.9
c 0
b 0
f 0
cc 32
nc 132
nop 4
crap 42.3482

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-2018, 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 9
        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 'group':
126 7
            case 'editCategories':
127 5
                $service = Users::class == $fieldType ? Craft::$app->userGroups : Craft::$app->categories;
128 5
                $method = 'getGroupBy';
129 5
                break;
130 7
            case 'folder':
131 2
                $service = $this;
132 2
                $method = 'getFolderBy';
133 2
                break;
134 5
            case 'createFoldersInVolume':
135 5
            case 'deleteFilesAndFoldersInVolume':
136 5
            case 'saveAssetInVolume':
137 5
            case 'viewVolume':
138 3
                $service = Craft::$app->volumes;
139 3
                $method = 'getVolumeBy';
140 3
                break;
141 2
            case 'taggroup':
142
                $service = Craft::$app->tags;
143
                $method = 'getTagGroupBy';
144
                break;
145 2
            case 'field':
146 2
                $service = Craft::$app->fields;
147 2
                $method = 'getFieldBy';
148 2
                break;
149
            case 'editGlobalSet':
150
                $service = Craft::$app->globals;
151
                $method = 'getSetBy';
152
                break;
153
            case 'utility':
154
                return $source;
155
        }
156
157
        // Send event
158 9
        $plugin = Craft::$app->controller->module;
159 9
        $event = new SourceMappingEvent([
160 9
            'source' => $source,
161 9
            'service' => $service ?? null,
162 9
            'method' => $method ?? null,
163
        ]);
164 9
        $plugin->trigger($plugin::EVENT_MAP_SOURCE, $event);
165 9
        $service = $event->service;
166 9
        $method = $event->method;
167
168
        // Try service and method
169 9
        if (isset($service) && isset($method) && isset($sourceFrom)) {
170 9
            $method = $method.ucfirst($indexFrom);
171
            try {
172 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...
173
            } catch (TypeError $e) {
174
                Schematic::error('An error occured mapping source '.$source.' from '.$indexFrom.' to '.$indexTo);
175
                Schematic::error($e->getMessage());
176
177
                return null;
178
            }
179
        }
180
181 9
        if ($sourceObject) {
182 8
            return $sourceType.':'.$sourceObject->$indexTo;
183
        }
184
185 1
        Schematic::warning('No mapping found for source '.$source);
186
187 1
        return null;
188
    }
189
190
    /**
191
     * Get a folder by id
192
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
193
     *
194
     * @param int $folderId
195
     * @return object
196
     */
197 1
    private function getFolderById(int $folderId): \stdClass
198
    {
199 1
        $folder = Craft::$app->assets->getFolderById($folderId);
200 1
        if ($folder) {
201 1
            $volume = $folder->getVolume();
202
            return  (object) [
203 1
                'id' => $folderId,
204 1
                'handle' => $volume->handle
205
            ];
206
        }
207
        return null;
208
    }
209
210
    /**
211
     * Get folder by volume id
212
     *
213
     * @param int $volumeId
214
     * @return VolumeFolder
215
     */
216 1
    private function getFolderByVolumeId(int $volumeId): VolumeFolder
217
    {
218 1
        return $this->mockFolder ? $this->mockFolder : VolumeFolder::findOne(['volumeId' => $volumeId]);
219
    }
220
221
    /**
222
     * Set a mock folder for the tests
223
     *
224
     * @param VolumeFolder $mockFolder
225
     */
226 1
    public function setMockFolder(VolumeFolder $mockFolder)
227
    {
228 1
        $this->mockFolder = $mockFolder;
229 1
    }
230
231
    /**
232
     * Get a folder by volume handle
233
     * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
234
     *
235
     * @param string $folderHandle
236
     * @return object
237
     */
238 1
    private function getFolderByHandle(string $folderHandle): \stdClass
239
    {
240 1
        $volume = Craft::$app->volumes->getVolumeByHandle($folderHandle);
241 1
        if ($volume) {
242 1
            $folder = $this->getFolderByVolumeId($volume->id);
243 1
            if ($folder) {
244
                return  (object) [
245 1
                    'id' => $folder->id,
246 1
                    'handle' => $folderHandle
247
                ];
248
            }
249
        }
250
        return null;
251
    }
252
}
253