Passed
Push — master ( 1ca40c...54695a )
by Josh
07:44 queued 11s
created

BlockTypesController   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 159
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 17
eloc 59
c 3
b 0
f 0
dl 0
loc 159
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A actionDelete() 0 17 2
B actionSave() 0 53 7
B actionSaveFieldLayout() 0 46 8
1
<?php
2
/**
3
 * Spoon plugin for Craft CMS 3.x
4
 *
5
 * Enhance Matrix
6
 *
7
 * @link      https://angell.io
8
 * @copyright Copyright (c) 2018 Angell & Co
9
 */
10
11
namespace angellco\spoon\controllers;
12
13
use angellco\spoon\models\BlockType;
14
use angellco\spoon\Spoon;
15
16
use Craft;
17
use craft\helpers\Db;
18
use craft\web\Controller;
19
20
/**
21
 * BlockTypes Controller
22
 *
23
 * @author    Angell & Co
24
 * @package   Spoon
25
 * @since     3.0.0
26
 */
27
class BlockTypesController extends Controller
28
{
29
30
    // Protected Properties
31
    // =========================================================================
32
33
    /**
34
     * @var    bool|array Allows anonymous access to this controller's actions.
35
     *         The actions must be in 'kebab-case'
36
     * @access protected
37
     */
38
    protected $allowAnonymous = false;
39
40
    // Public Methods
41
    // =========================================================================
42
43
    /**
44
     * Saves a Spoon block type
45
     *
46
     * @return \yii\web\Response
47
     * @throws \yii\db\Exception
48
     * @throws \yii\web\BadRequestHttpException
49
     */
50
    public function actionSave()
51
    {
52
        $this->requirePostRequest();
53
        $this->requireAcceptsJson();
54
55
        // This will be an array of Tab Names with Block Type IDs.
56
        // The order in which they appear is the order in which they should also
57
        // be returned in eventually, so we will just rely on the id to describe this
58
        // and make sure each time we are referencing a context that already exists to
59
        // delete the rows matching that context before proceeding with the save.
60
        $blockTypesPostData = Craft::$app->getRequest()->getParam('spoonedBlockTypes');
61
62
        $context = (string)Craft::$app->getRequest()->getParam('context');
63
        $fieldId = (integer)Craft::$app->getRequest()->getParam('fieldId');
64
65
        // Get any existing field layouts so we don’t lose them
66
        $fieldLayoutIds = Spoon::$plugin->blockTypes->getFieldLayoutIds($context, $fieldId);
67
68
        // Remove all current block types by context
69
        Spoon::$plugin->blockTypes->deleteByContext($context, $fieldId);
70
71
        // Loop over the data and save new rows for each block type / group combo
72
        $errors = 0;
73
        if (is_array($blockTypesPostData))
74
        {
75
            foreach ($blockTypesPostData as $groupName => $blockTypeIds)
76
            {
77
                foreach ($blockTypeIds as $blockTypeId)
78
                {
79
                    $spoonedBlockType = new BlockType();
80
                    $spoonedBlockType->fieldId           = $fieldId;
81
                    $spoonedBlockType->matrixBlockTypeId = $blockTypeId;
82
                    $spoonedBlockType->fieldLayoutId     = isset($fieldLayoutIds[$blockTypeId]) ? $fieldLayoutIds[$blockTypeId] : null;
83
                    $spoonedBlockType->groupName         = urldecode($groupName);
84
                    $spoonedBlockType->context           = $context;
85
86
                    if (!Spoon::$plugin->blockTypes->save($spoonedBlockType))
87
                    {
88
                        $errors++;
89
                    }
90
                }
91
            }
92
        }
93
94
        if ($errors > 0)
95
        {
96
            return $this->asJson([
97
                'success' => false
98
            ]);
99
        }
100
101
        return $this->asJson([
102
            'success' => true
103
        ]);
104
    }
105
106
    /**
107
     * Delete a set of Spoon block types for a given field and context
108
     *
109
     * @return \yii\web\Response
110
     * @throws \yii\db\Exception
111
     * @throws \yii\web\BadRequestHttpException
112
     */
113
    public function actionDelete()
114
    {
115
        $this->requirePostRequest();
116
        $this->requireAcceptsJson();
117
118
        $context = (string)Craft::$app->getRequest()->getParam('context');
119
        $fieldId = (integer)Craft::$app->getRequest()->getParam('fieldId');
120
121
        if (!Spoon::$plugin->blockTypes->deleteByContext($context, $fieldId))
122
        {
123
            $this->asJson([
124
                'success' => false
125
            ]);
126
        }
127
128
        return $this->asJson([
129
            'success' => true
130
        ]);
131
    }
132
133
    /**
134
     * Saves a field layout for a given Spoon block type
135
     *
136
     * @return bool|\yii\web\Response
137
     * @throws \angellco\spoon\errors\BlockTypeNotFoundException
138
     * @throws \yii\web\BadRequestHttpException
139
     */
140
    public function actionSaveFieldLayout()
141
    {
142
        $this->requirePostRequest();
143
        $this->requireAcceptsJson();
144
145
        $spoonedBlockTypeId = Craft::$app->getRequest()->getParam('spoonedBlockTypeId');
146
        $blockTypeFieldLayouts = Craft::$app->getRequest()->getParam('blockTypeFieldLayouts');
0 ignored issues
show
Unused Code introduced by
The assignment to $blockTypeFieldLayouts is dead and can be removed.
Loading history...
147
148
        if ($spoonedBlockTypeId)
149
        {
150
            if (!$spoonedBlockType = Spoon::$plugin->blockTypes->getById($spoonedBlockTypeId)) {
151
                return false;
152
            }
153
        } else
154
        {
155
            return false;
156
        }
157
158
        // Set the field layout on the model
159
        $postedFieldLayout = Craft::$app->getRequest()->getParam('blockTypeFieldLayouts');
160
161
        // Check if we have one
162
        if ($postedFieldLayout) {
163
            $assembledLayout = Craft::$app->fields->assembleLayout($postedFieldLayout);
0 ignored issues
show
Bug introduced by
It seems like $postedFieldLayout can also be of type string; however, parameter $postedFieldLayout of craft\services\Fields::assembleLayout() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

163
            $assembledLayout = Craft::$app->fields->assembleLayout(/** @scrutinizer ignore-type */ $postedFieldLayout);
Loading history...
164
            $spoonedBlockType->setFieldLayout($assembledLayout);
0 ignored issues
show
Bug introduced by
The method setFieldLayout() does not exist on angellco\spoon\models\BlockType. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

164
            $spoonedBlockType->/** @scrutinizer ignore-call */ 
165
                               setFieldLayout($assembledLayout);
Loading history...
165
166
            // Save it
167
            if (!Spoon::$plugin->blockTypes->saveFieldLayout($spoonedBlockType)) {
168
                return $this->asJson([
169
                    'success' => false
170
                ]);
171
            }
172
        } else if ($spoonedBlockType->fieldLayoutId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $spoonedBlockType->fieldLayoutId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
173
174
            // We don’t have a new field layout, so remove the old one if there is one
175
            $oldFieldLayoutId = $spoonedBlockType->fieldLayoutId;
176
            $spoonedBlockType->fieldLayoutId = null;
177
            if (!Spoon::$plugin->blockTypes->save($spoonedBlockType) || !Craft::$app->fields->deleteLayoutById($oldFieldLayoutId)) {
178
                return $this->asJson([
179
                    'success' => false
180
                ]);
181
            }
182
        }
183
184
        return $this->asJson([
185
            'success' => true
186
        ]);
187
    }
188
189
}
190