Passed
Push — v1 ( 532872...bd3ac4 )
by Andrew
15:20 queued 08:26
created

AutocompleteService::getAutocompleteCacheKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * Twigfield for Craft CMS
4
 *
5
 * Provides a twig editor field with Twig & Craft API 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\twigfield\services;
12
13
use Craft;
14
use craft\base\Component;
15
use craft\events\SectionEvent;
16
use craft\services\Fields;
17
use nystudio107\twigfield\autocompletes\SectionShorthandFieldsAutocomplete;
18
use nystudio107\twigfield\base\Autocomplete as BaseAutoComplete;
19
use nystudio107\twigfield\base\AutocompleteInterface;
20
use nystudio107\twigfield\events\RegisterTwigfieldAutocompletesEvent;
21
use nystudio107\twigfield\Twigfield;
22
use yii\base\Event;
23
use yii\caching\TagDependency;
24
25
/**
26
 * Class Autocomplete
27
 *
28
 * @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...
29
 * @package   Twigfield
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
30
 * @since     1.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...
31
 */
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...
32
class AutocompleteService extends Component
33
{
34
    // Constants
35
    // =========================================================================
36
37
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
38
     * @event RegisterTwigfieldAutocompletesEvent The event that is triggered when registering
39
     *        Twigfield Autocomplete types
40
     *
41
     * Autocomplete Generator types must implement [[AutocompleteInterface]]. [[AutoComplete]]
42
     * provides a base implementation.
43
     *
44
     * ```php
45
     * use nystudio107\twigfield\services\AutocompleteService;
46
     * use nystudio107\twigfield\events\RegisterTwigfieldAutocompletesEvent;
47
     * use yii\base\Event;
48
     *
49
     * Event::on(AutocompleteService::class,
50
     *     AutocompleteService::EVENT_REGISTER_TWIGFIELD_AUTOCOMPLETES,
51
     *     function(RegisterTwigfieldAutocompletesEvent $event) {
52
     *         $event->types[] = MyAutocomplete::class;
53
     *     }
54
     * );
55
     *
56
     * or to pass in a config array for the Autocomplete object:
57
     *
58
     * Event::on(AutocompleteService::class,
59
     *     AutocompleteService::EVENT_REGISTER_TWIGFIELD_AUTOCOMPLETES,
60
     *     function(RegisterTwigfieldAutocompletesEvent $event) {
61
     *         $config = [
62
     *             'property' => value,
63
     *         ];
64
     *         $event->types[] = [MyAutocomplete::class => $config];
65
     *     }
66
     * );
67
     *
68
     * ```
69
     */
70
    const EVENT_REGISTER_TWIGFIELD_AUTOCOMPLETES = 'registerTwigfieldAutocompletes';
71
72
    const AUTOCOMPLETE_CACHE_TAG = 'TwigFieldAutocompleteTag';
73
74
    // Public Properties
75
    // =========================================================================
76
77
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
78
     * @var string Prefix for the cache key
79
     */
80
    public $cacheKeyPrefix = 'TwigFieldAutocomplete';
81
82
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
83
     * @var int Cache duration
84
     */
85
    public $cacheDuration = 3600;
86
87
    // Public Methods
88
    // =========================================================================
89
90
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
91
     * @inerhitDoc
92
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
93
    public function init(): void
94
    {
95
        parent::init();
96
        // Short cacheDuration if we're in devMode
97
        if (Craft::$app->getConfig()->getGeneral()->devMode) {
98
            $this->cacheDuration = 1;
99
        }
100
        // Invalidate any SectionShorthandFieldsAutocomplete caches whenever any field layout is edited
101
        Event::on(Fields::class, Fields::EVENT_AFTER_SAVE_FIELD_LAYOUT, function (SectionEvent $e) {
0 ignored issues
show
Unused Code introduced by
The parameter $e is not used and could be removed. ( Ignorable by Annotation )

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

101
        Event::on(Fields::class, Fields::EVENT_AFTER_SAVE_FIELD_LAYOUT, function (/** @scrutinizer ignore-unused */ SectionEvent $e) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
102
            $this->clearAutocompleteCache(SectionShorthandFieldsAutocomplete::class);
103
        });
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...
104
    }
105
106
    /**
107
     * Call each of the autocompletes to generate their complete items
108
     * @param string $fieldType
0 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
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...
109
     * @param array $twigfieldOptions
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
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...
110
     * @return array
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
111
     */
112
    public function generateAutocompletes(string $fieldType = Twigfield::DEFAULT_FIELD_TYPE, array $twigfieldOptions = []): array
113
    {
114
        $autocompleteItems = [];
115
        $autocompletes = $this->getAllAutocompleteGenerators($fieldType);
116
        foreach ($autocompletes as $autocompleteGenerator) {
117
            /* @var BaseAutoComplete $autocomplete */
118
            // Assume the generator is a class name string
119
            $config = [
120
                'fieldType' => $fieldType,
121
                'twigfieldOptions' => $twigfieldOptions,
122
            ];
123
            $autocompleteClass = $autocompleteGenerator;
124
            // If we're passed in an array instead, extract the class name and config from the key/value pair
125
            // in the form of [className => configArray]
126
            if (is_array($autocompleteGenerator)) {
127
                $autocompleteClass = array_key_first($autocompleteGenerator);
128
                /** @noinspection SlowArrayOperationsInLoopInspection */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
129
                $config = array_merge($config, $autocompleteGenerator[$autocompleteClass]);
130
            }
131
            $autocomplete = new $autocompleteClass($config);
132
            $name = $autocomplete->name;
133
            // Set up the cache parameters
134
            $cache = Craft::$app->getCache();
135
            $cacheKey = $this->getAutocompleteCacheKey($autocomplete, $config);
136
            $dependency = new TagDependency([
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...
137
                'tags' => [
138
                    self::AUTOCOMPLETE_CACHE_TAG,
139
                    self::AUTOCOMPLETE_CACHE_TAG . $name,
140
                    self::AUTOCOMPLETE_CACHE_TAG . $autocomplete::class,
141
                ],
142
            ]);
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...
143
            // Get the autocompletes from the cache, or generate them if they aren't cached
144
            $autocompleteItems[$name] = $cache->getOrSet($cacheKey, static function () use ($name, $autocomplete) {
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...
145
                $autocomplete->generateCompleteItems();
146
                return [
147
                    'name' => $name,
148
                    'type' => $autocomplete->type,
149
                    'hasSubProperties' => $autocomplete->hasSubProperties,
150
                    BaseAutoComplete::COMPLETION_KEY => $autocomplete->getCompleteItems(),
151
                ];
152
            }, $this->cacheDuration, $dependency);
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...
153
        }
154
        Craft::info('Twigfield Autocompletes generated', __METHOD__);
155
156
        return $autocompleteItems;
157
    }
158
159
    /**
160
     * Clear the specified autocomplete cache (or all autocomplete caches if left empty)
161
     *
162
     * @param string $autocompleteName
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...
163
     * @return void
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
164
     */
165
    public function clearAutocompleteCache(string $autocompleteName = ''): void
166
    {
167
        $cache = Craft::$app->getCache();
168
        TagDependency::invalidate($cache, self::AUTOCOMPLETE_CACHE_TAG . $autocompleteName);
169
        Craft::info('Twigfield caches invalidated', __METHOD__);
170
    }
171
172
    /**
173
     * Return the cache key to use for an Autocomplete's complete items
174
     *
175
     * @param AutocompleteInterface $autocomplete
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...
176
     * @param array $config
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 17 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...
177
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
178
     */
179
    public function getAutocompleteCacheKey(AutocompleteInterface $autocomplete, array $config): string
180
    {
181
        return $this->cacheKeyPrefix . $autocomplete->name . md5(serialize($config));
0 ignored issues
show
Bug introduced by
Accessing name on the interface nystudio107\twigfield\base\AutocompleteInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
182
    }
183
184
    // Protected Methods
185
    // =========================================================================
186
187
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $fieldType should have a doc-comment as per coding-style.
Loading history...
188
     * Returns all available autocompletes classes.
189
     *
190
     * @return string[] The available autocompletes classes
191
     */
192
    public function getAllAutocompleteGenerators(string $fieldType = Twigfield::DEFAULT_FIELD_TYPE): array
193
    {
194
        $event = new RegisterTwigfieldAutocompletesEvent([
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...
195
            'types' => Twigfield::$settings->defaultTwigfieldAutocompletes,
196
            'fieldType' => $fieldType,
197
        ]);
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...
198
        $this->trigger(self::EVENT_REGISTER_TWIGFIELD_AUTOCOMPLETES, $event);
199
200
        return $event->types;
201
    }
202
}
203