Completed
Push — asset-folders-fix ( 79eea5...cd42e0 )
by Bart
02:28 queued 11s
created

SourcesBehavior::getFolderByVolumeId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

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