Passed
Push — develop-v4 ( 73d448...9477d1 )
by Andrew
23:26 queued 16:44
created

Code::getFieldRenderVariables()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 38
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 27
c 1
b 0
f 0
nc 12
nop 3
dl 0
loc 38
rs 8.8657
1
<?php
2
/**
3
 * Code Field plugin for Craft CMS
4
 *
5
 * Provides a Code Field that has a full-featured code editor with syntax highlighting & autocomplete
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2022 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\codefield\fields;
12
13
use Craft;
14
use craft\base\ElementInterface;
0 ignored issues
show
Bug introduced by
The type craft\base\ElementInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use craft\base\Field;
16
use craft\base\PreviewableFieldInterface;
17
use craft\helpers\Html;
18
use craft\helpers\Json;
19
use craft\validators\ArrayValidator;
20
use GraphQL\Type\Definition\Type;
21
use nystudio107\codefield\gql\types\generators\CodeDataGenerator;
22
use nystudio107\codefield\models\CodeData;
23
use nystudio107\codefield\validators\JsonValidator;
24
use yii\db\Schema;
25
26
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
27
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
28
 * @package   CodeField
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
29
 * @since     4.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
30
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
31
class Code extends Field implements PreviewableFieldInterface
32
{
33
    // Public Properties
34
    // =========================================================================
35
36
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
37
     * @var string The theme to use for the Code Editor field.
38
     */
39
    public string $theme = 'auto';
40
41
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
42
     * @var string The language to use for the Code Editor field.
43
     */
44
    public string $language = 'javascript';
45
46
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
47
     * @var bool Whether the Code Editor field display as a single line
48
     */
49
    public bool $singleLineEditor = false;
50
51
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
52
     * @var int The font size to use for the Code Editor field
53
     */
54
    public int $fontSize = 14;
55
56
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
57
     * @var bool Whether line numbers should be displayed in the Code Editor field
58
     */
59
    public bool $lineNumbers = false;
60
61
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
62
     * @var bool Whether code folding should be used in the Code Editor field
63
     */
64
    public bool $codeFolding = false;
65
66
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
67
     * @var string The text that will be shown if the code field is empty.
68
     */
69
    public string $placeholder = '';
70
71
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
72
     * @var bool Whether the language selector dropdown menu should be displayed.
73
     */
74
    public bool $showLanguageDropdown = true;
75
76
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
77
     * @var string The default value the Code Field will be populated with
78
     */
79
    public string $defaultValue = '';
80
81
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
82
     * @var array The languages that should be listed in the language selector dropdown menu.
83
     */
84
    public array $availableLanguages = [
85
        'css',
86
        'graphql',
87
        'html',
88
        'javascript',
89
        'json',
90
        'markdown',
91
        'mysql',
92
        'php',
93
        'shell',
94
        'twig',
95
        'typescript',
96
        'yaml',
97
    ];
98
99
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
100
     * @var string|null The type of database column the field should have in the content table
101
     */
102
    public ?string $columnType = Schema::TYPE_TEXT;
103
104
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
105
     * @var string JSON blob of Monaco [EditorOptions](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IEditorOptions.html) that will override the default settings
106
     */
107
    public string $monacoEditorOptions = '';
108
109
    // Static Methods
110
    // =========================================================================
111
112
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
113
     * @inheritdoc
114
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
115
    public static function displayName(): string
116
    {
117
        return Craft::t('codefield', 'Code');
118
    }
119
120
    // Public Methods
121
    // =========================================================================
122
123
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $value should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $element should have a doc-comment as per coding-style.
Loading history...
124
     * @inheritdoc
125
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
126
    public function normalizeValue(mixed $value, ?ElementInterface $element = null): mixed
127
    {
128
        if ($value instanceof CodeData) {
129
            return $value;
130
        }
131
        // Default config
132
        $config = [
133
            'value' => $this->defaultValue,
134
            'language' => $this->language,
135
        ];
136
        // Handle incoming values potentially being JSON or an array
137
        if (!empty($value)) {
138
            // Handle JSON-encoded values coming in
139
            if (\is_string($value)) {
140
                $jsonValue = Json::decodeIfJson($value);
141
                // If this is still a string (meaning it's not valid JSON), treat it as the value
142
                if (\is_string($jsonValue)) {
143
                    $config['value'] = $jsonValue;
144
                }
145
                if (\is_array($jsonValue)) {
146
                    // Check to make sure the array returned is an encoded `CodeData` config, with exactly
147
                    // the same expected key/value pairs
148
                    if (!array_diff_key($config, $jsonValue) && !array_diff_key($jsonValue, $config)) {
149
                        $value = $jsonValue;
150
                    } else {
151
                        // Otherwise treat it as JSON data
152
                        $value = [
153
                            'value' => $value,
154
                            'language' => 'json',
155
                        ];
156
                    }
157
                }
158
            }
159
            if (\is_array($value)) {
160
                $config = array_merge($config, array_filter($value));
161
            }
162
        }
163
        // Create and validate the model
164
        $codeData = new CodeData($config);
165
        if (!$codeData->validate()) {
166
            Craft::error(
167
                Craft::t('codefield', 'CodeData failed validation: ')
168
                . print_r($codeData->getErrors(), true),
0 ignored issues
show
Bug introduced by
Are you sure print_r($codeData->getErrors(), true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

168
                . /** @scrutinizer ignore-type */ print_r($codeData->getErrors(), true),
Loading history...
169
                __METHOD__
170
            );
171
        }
172
173
        return $codeData;
174
    }
175
176
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
177
     * @inheritdoc
178
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
179
    public function getSettingsHtml(): ?string
180
    {
181
        $monacoLanguages = require(__DIR__ . '/MonacoLanguages.php');
0 ignored issues
show
Coding Style introduced by
"require" is a statement not a function; no parentheses are required
Loading history...
Coding Style introduced by
File is being conditionally included; use "include" instead
Loading history...
182
        $schemaFilePath = Craft::getAlias('@nystudio107/codefield/resources/IEditorOptionsSchema.json');
183
        $optionsSchema = @file_get_contents($schemaFilePath) ?: '';
0 ignored issues
show
Bug introduced by
It seems like $schemaFilePath can also be of type false; however, parameter $filename of file_get_contents() does only seem to accept string, 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

183
        $optionsSchema = @file_get_contents(/** @scrutinizer ignore-type */ $schemaFilePath) ?: '';
Loading history...
184
        // Render the settings template
185
        return Craft::$app->getView()->renderTemplate(
186
            'codefield/_components/fields/Code_settings',
187
            [
188
                'field' => $this,
189
                'monacoLanguages' => $monacoLanguages,
190
                'optionsSchema' => $optionsSchema,
191
            ]
192
        );
193
    }
194
195
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $value should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $element should have a doc-comment as per coding-style.
Loading history...
196
     * @inheritdoc
197
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
198
    public function getInputHtml($value, ElementInterface $element = null): string
199
    {
200
        $twigVariables = $this->getFieldRenderVariables($value, $element, true);
0 ignored issues
show
Bug introduced by
It seems like $element can also be of type null; however, parameter $element of nystudio107\codefield\fi...tFieldRenderVariables() does only seem to accept craft\base\ElementInterface, 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

200
        $twigVariables = $this->getFieldRenderVariables($value, /** @scrutinizer ignore-type */ $element, true);
Loading history...
201
        // Render the input template
202
        return Craft::$app->getView()->renderTemplate(
203
            'codefield/_components/fields/Code_input',
204
            $twigVariables
205
        );
206
    }
207
208
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $value should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $element should have a doc-comment as per coding-style.
Loading history...
209
     * @inheritdoc
210
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
211
    public function getStaticHtml(mixed $value, ElementInterface $element): string
212
    {
213
        $twigVariables = $this->getFieldRenderVariables($value, $element, false);
214
        // Render the input template
215
        return Craft::$app->getView()->renderTemplate(
216
            'codefield/_components/fields/Code_input',
217
            $twigVariables
218
        );
219
    }
220
221
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
222
     * @inheritdoc
223
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
224
    public function getContentGqlType(): Type|array
225
    {
226
        $typeArray = CodeDataGenerator::generateTypes($this);
227
228
        return [
229
            'name' => $this->handle,
230
            'description' => 'Code Editor field',
231
            'type' => array_shift($typeArray),
232
        ];
233
    }
234
235
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
236
     * @inheritdoc
237
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
238
    public function rules(): array
239
    {
240
        $rules = parent::rules();
241
        return array_merge($rules, [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
242
            ['theme', 'in', 'range' => ['auto', 'vs', 'vs-dark', 'hc-black']],
243
            ['theme', 'default', 'value' => 'auto'],
244
            ['language', 'string'],
245
            ['language', 'default', 'value' => 'javascript'],
246
            [['singleLineEditor', 'showLanguageDropdown', 'lineNumbers', 'codeFolding'], 'boolean'],
247
            ['placeholder', 'string'],
248
            ['placeholder', 'default', 'value' => ''],
249
            ['fontSize', 'integer'],
250
            ['fontSize', 'default', 'value' => 14],
251
            ['availableLanguages', ArrayValidator::class],
252
            ['monacoEditorOptions', JsonValidator::class],
253
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
254
    }
255
256
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
257
     * @inheritdoc
258
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
259
    public function getContentColumnType(): string
260
    {
261
        if ($this->columnType) {
262
            return $this->columnType;
263
        }
264
265
        return Schema::TYPE_TEXT;
266
    }
267
268
    // Protected Methods
269
    // =========================================================================
270
271
    /**
272
     * Return the Twig variables for rendering the field
273
     *
274
     * @param $value
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
275
     * @param ElementInterface $element
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
276
     * @param bool $enabled Whether the field is enabled or not
0 ignored issues
show
Coding Style introduced by
Expected 13 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
277
     * @return array[]
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
278
     */
279
    protected function getFieldRenderVariables($value, ElementInterface $element, bool $enabled): array
280
    {
281
        // Get our id and namespace
282
        $id = Html::id($this->handle);
0 ignored issues
show
Bug introduced by
It seems like $this->handle can also be of type null; however, parameter $id of craft\helpers\Html::id() does only seem to accept string, 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

282
        $id = Html::id(/** @scrutinizer ignore-type */ $this->handle);
Loading history...
283
        $namespacedId = Craft::$app->getView()->namespaceInputId($id);
284
285
        // Extract just the languages that have been selected for display
286
        $displayLanguages = [];
287
        if ($this->showLanguageDropdown) {
288
            $monacoLanguages = require(__DIR__ . '/MonacoLanguages.php');
0 ignored issues
show
Coding Style introduced by
"require" is a statement not a function; no parentheses are required
Loading history...
Coding Style introduced by
File is being conditionally included; use "include" instead
Loading history...
289
            $decomposedLanguages = array_column($monacoLanguages, 'label', 'value');
290
            $displayLanguages = array_intersect_key($decomposedLanguages, array_flip($this->availableLanguages));
291
            // Handle "all" checkbox
292
            if ($this->availableLanguages[0] === '*') {
293
                $displayLanguages = $decomposedLanguages;
294
            }
295
            $displayLanguages = array_map(static function ($k, $v) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
296
                return ['value' => $k, 'label' => $v];
297
            }, array_keys($displayLanguages), array_values($displayLanguages));
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
298
        }
299
        $monacoOptionsOverride = Json::decodeIfJson($this->monacoEditorOptions);
300
        if ($monacoOptionsOverride === null || is_string($monacoOptionsOverride)) {
301
            $monacoOptionsOverride = [];
302
        }
303
        // Disable the Monaco editor
304
        if (!$enabled) {
305
            $monacoOptionsOverride['domReadOnly'] = true;
306
            $monacoOptionsOverride['readOnly'] = true;
307
        }
308
        return [
0 ignored issues
show
Bug Best Practice introduced by
The expression return array('name' => $...$monacoOptionsOverride) returns an array which contains values of type nystudio107\codefield\fields\Code|string which are incompatible with the documented value type array.
Loading history...
309
            'name' => $this->handle,
310
            'value' => $value,
311
            'field' => $this,
312
            'orientation' => $this->getOrientation($element),
313
            'id' => $id,
314
            'namespacedId' => $namespacedId,
315
            'displayLanguages' => $displayLanguages,
316
            'monacoOptionsOverride' => $monacoOptionsOverride,
317
        ];
318
    }
319
}
320