Completed
Push — master ( 280b95...97ab68 )
by Bart
9s
created

SourcesBehavior   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 4

Test Coverage

Coverage 81.82%

Importance

Changes 0
Metric Value
wmc 40
lcom 0
cbo 4
dl 0
loc 159
ccs 72
cts 88
cp 0.8182
rs 9.2
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A findSources() 0 14 5
A getSources() 0 13 3
F getSource() 0 92 32

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 NerdsAndCompany\Schematic\Schematic;
10
use NerdsAndCompany\Schematic\Events\SourceMappingEvent;
11
12
/**
13
 * Schematic Sources Behavior.
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 SourcesBehavior extends Behavior
24
{
25
    /**
26
     * Recursively find sources in definition attributes.
27
     *
28
     * @param string $fieldType
29
     * @param array  $attributes
30
     * @param string $indexFrom
31
     * @param string $indexTo
32
     *
33
     * @return array
34
     */
35 32
    public function findSources(string $fieldType, array $attributes, string $indexFrom, string $indexTo): array
36
    {
37 32
        foreach ($attributes as $key => $attribute) {
38 32
            if ($key === 'source') {
39 4
                $attributes[$key] = $this->getSource($fieldType, $attribute, $indexFrom, $indexTo);
40 32
            } elseif ($key === 'sources') {
41 4
                $attributes[$key] = $this->getSources($fieldType, $attribute, $indexFrom, $indexTo);
42 32
            } elseif (is_array($attribute)) {
43 32
                $attributes[$key] = $this->findSources($fieldType, $attribute, $indexFrom, $indexTo);
44
            }
45
        }
46
47 32
        return $attributes;
48
    }
49
50
    /**
51
     * Get sources based on the indexFrom attribute and return them with the indexTo attribute.
52
     *
53
     * @param string       $fieldType
54
     * @param string|array $sources
55
     * @param string       $indexFrom
56
     * @param string       $indexTo
57
     *
58
     * @return array|string
59
     */
60 9
    public function getSources(string $fieldType, $sources, string $indexFrom, string $indexTo)
61
    {
62 9
        $mappedSources = $sources;
63 9
        if (is_array($sources)) {
64 7
            $mappedSources = [];
65 7
            $sources = array_filter($sources);
66 7
            foreach ($sources as $source) {
67 7
                $mappedSources[] = $this->getSource($fieldType, $source, $indexFrom, $indexTo);
68
            }
69
        }
70
71 9
        return $mappedSources;
72
    }
73
74
    /**
75
     * Gets a source by the attribute indexFrom, and returns it with attribute $indexTo.
76
     *
77
     * @TODO Break up and simplify this method
78
     *
79
     * @param string $fieldType
80
     * @param string $source
81
     * @param string $indexFrom
82
     * @param string $indexTo
83
     *
84
     * @return string|null
85
     *
86
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
87
     * @SuppressWarnings(PHPMD.NPathComplexity)
88
     */
89 9
    public function getSource(string $fieldType, string $source = null, string $indexFrom, string $indexTo)
90
    {
91 9
        if (false === strpos($source, ':')) {
92 7
            return $source;
93
        }
94
95
        /** @var Model $sourceObject */
96 9
        $sourceObject = null;
97
98
        // Get service and method by source
99 9
        list($sourceType, $sourceFrom) = explode(':', $source);
100 9
        switch ($sourceType) {
101 9
            case 'editSite':
102
                $service = Craft::$app->sites;
103
                $method = 'getSiteBy';
104
                break;
105 9
            case 'single':
106 9
            case 'section':
107 9
            case 'createEntries':
108 9
            case 'editPeerEntries':
109 9
            case 'deleteEntries':
110 9
            case 'deletePeerEntries':
111 9
            case 'deletePeerEntryDrafts':
112 9
            case 'editEntries':
113 9
            case 'editPeerEntryDrafts':
114 9
            case 'publishEntries':
115 9
            case 'publishPeerEntries':
116 9
            case 'publishPeerEntryDrafts':
117 5
                $service = Craft::$app->sections;
118 5
                $method = 'getSectionBy';
119 5
                break;
120 9
            case 'group':
121 7
            case 'editCategories':
122 5
                $service = 'Users' == $fieldType ? Craft::$app->userGroups : Craft::$app->categories;
123 5
                $method = 'getGroupBy';
124 5
                break;
125 7
            case 'folder':
126 5
            case 'createFoldersInVolume':
127 5
            case 'deleteFilesAndFoldersInVolume':
128 5
            case 'saveAssetInVolume':
129 5
            case 'viewVolume':
130 5
                $service = Craft::$app->volumes;
131 5
                $method = 'getVolumeBy';
132 5
                break;
133 2
            case 'taggroup':
134
                $service = Craft::$app->tags;
135
                $method = 'getTagGroupBy';
136
                break;
137 2
            case 'field':
138 2
                $service = Craft::$app->fields;
139 2
                $method = 'getFieldBy';
140 2
                break;
141
            case 'editGlobalSet':
142
                $service = Craft::$app->globals;
143
                $method = 'getSetBy';
144
                break;
145
            case 'utility':
146
                return $source;
147
        }
148
149
        // Send event
150 9
        $plugin = Craft::$app->controller->module;
151 9
        $event = new SourceMappingEvent([
152 9
            'source' => $source,
153 9
            'service' => $service ?? null,
154 9
            'method' => $method ?? null,
155
        ]);
156 9
        $plugin->trigger($plugin::EVENT_MAP_SOURCE, $event);
157 9
        $service = $event->service;
158 9
        $method = $event->method;
159
160
        // Try service and method
161 9
        if (isset($service) && isset($method) && isset($sourceFrom)) {
162 9
            $method = $method.ucfirst($indexFrom);
163
            try {
164 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...
165
            } catch (TypeError $e) {
166
                Schematic::error('An error occured mapping source '.$source.' from '.$indexFrom.' to '.$indexTo);
167
                Schematic::error($e->getMessage());
168
169
                return null;
170
            }
171
        }
172
173 9
        if ($sourceObject) {
174 8
            return $sourceType.':'.$sourceObject->$indexTo;
175
        }
176
177 1
        Schematic::warning('No mapping found for source '.$source);
178
179 1
        return null;
180
    }
181
}
182