Completed
Push — master ( da6bda...f012c7 )
by ARCANEDEV
16s
created

src/NoCaptchaV2.php (2 issues)

mismatching argument types.

Documentation Minor

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace Arcanedev\NoCaptcha;
2
3
use Arcanedev\Html\Elements\Button;
4
use Arcanedev\Html\Elements\Div;
5
use Arcanedev\NoCaptcha\Exceptions\InvalidArgumentException;
6
use Arcanedev\NoCaptcha\Utilities\ResponseV2;
7
use Illuminate\Support\Arr;
8
9
/**
10
 * Class     NoCaptchaV2
11
 *
12
 * @package  Arcanedev\NoCaptcha
13
 * @author   ARCANEDEV <[email protected]>
14
 */
15
class NoCaptchaV2 extends AbstractNoCaptcha
16
{
17
    /* -----------------------------------------------------------------
18
     |  Properties
19
     | -----------------------------------------------------------------
20
     */
21
22
    /**
23
     * Decides if we've already loaded the script file or not.
24
     *
25
     * @param bool
26
     */
27
    protected $scriptLoaded = false;
28
29
    /* -----------------------------------------------------------------
30
     |  Getters & Setters
31
     | -----------------------------------------------------------------
32
     */
33
34
    /**
35
     * Get script source link.
36
     *
37
     * @param  string|null  $callbackName
38
     *
39
     * @return string
40
     */
41 20
    private function getScriptSrc($callbackName = null)
42
    {
43 20
        $queries = [];
44
45 20
        if ($this->hasLang())
46 8
            Arr::set($queries, 'hl', $this->lang);
47
48 20
        if ($this->hasCallbackName($callbackName)) {
49 4
            Arr::set($queries, 'onload', $callbackName);
50 4
            Arr::set($queries, 'render', 'explicit');
51
        }
52
53 20
        return $this->getClientUrl() . (count($queries) ? '?' . http_build_query($queries) : '');
54
    }
55
56
    /* -----------------------------------------------------------------
57
     |  Main Methods
58
     | -----------------------------------------------------------------
59
     */
60
61
    /**
62
     * Display Captcha.
63
     *
64
     * @param  string|null  $name
65
     * @param  array        $attributes
66
     *
67
     * @return \Arcanedev\Html\Elements\Div
68
     */
69 76
    public function display($name = null, array $attributes = [])
70
    {
71 76
        return Div::make()->attributes(array_merge(
0 ignored issues
show
array_merge(static::prep...ttributes($attributes)) is of type array, but the function expects a object<Arcanedev\Html\Elements\Concerns\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
72 76
            static::prepareNameAttribute($name),
73 64
            $this->prepareAttributes($attributes)
74
        ));
75
    }
76
77
    /**
78
     * Display image Captcha.
79
     *
80
     * @param  string|null  $name
81
     * @param  array        $attributes
82
     *
83
     * @return \Arcanedev\Html\Elements\Div
84
     */
85 12
    public function image($name = null, array $attributes = [])
86
    {
87 12
        return $this->display($name, array_merge(
88 9
            $attributes,
89 12
            ['data-type' => 'image']
90
        ));
91
    }
92
93
    /**
94
     * Display audio Captcha.
95
     *
96
     * @param  string|null  $name
97
     * @param  array        $attributes
98
     *
99
     * @return \Arcanedev\Html\Elements\Div
100
     */
101 12
    public function audio($name = null, array $attributes = [])
102
    {
103 12
        return $this->display($name, array_merge(
104 9
            $attributes,
105 12
            ['data-type' => 'audio']
106
        ));
107
    }
108
109
    /**
110
     * Display an invisible Captcha (bind the challenge to a button).
111
     *
112
     * @param  string  $value
113
     * @param  array   $attributes
114
     *
115
     * @return \Arcanedev\Html\Elements\Button
116
     */
117 4
    public function button($value, array $attributes = [])
118
    {
119 4
        return Button::make()->text($value)->attributes(array_merge(
0 ignored issues
show
array_merge(array('data-...ttributes($attributes)) is of type array, but the function expects a object<Arcanedev\Html\Elements\Concerns\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
120 4
            ['data-callback' => 'onSubmit'],
121 4
            $this->prepareAttributes($attributes)
122
        ));
123
    }
124
125
    /**
126
     * Get script tag.
127
     *
128
     * @param  string|null  $callbackName
129
     *
130
     * @return \Illuminate\Support\HtmlString
131
     */
132 20
    public function script($callbackName = null)
133
    {
134 20
        $script = '';
135
136 20
        if ( ! $this->scriptLoaded) {
137 20
            $script = '<script src="'.$this->getScriptSrc($callbackName).'" async defer></script>';
138 20
            $this->scriptLoaded = true;
139
        }
140
141 20
        return $this->toHtmlString($script);
142
    }
143
144
    /**
145
     * Get the NoCaptcha API Script.
146
     *
147
     * @return \Illuminate\Support\HtmlString
148
     */
149 4
    public function getApiScript()
150
    {
151 4
        return $this->toHtmlString(
152 3
            "<script>
153
                window.noCaptcha = {
154
                    captchas: [],
155
                    reset: function(name) {
156
                        var captcha = window.noCaptcha.get(name);
157
        
158
                        if (captcha)
159
                            window.noCaptcha.resetById(captcha.id);
160
                    },
161
                    resetById: function(id) {
162
                        grecaptcha.reset(id);
163
                    },
164
                    get: function(name) {
165
                        return window.noCaptcha.find(function (captcha) {
166
                            return captcha.name === name;
167
                        });
168
                    },
169
                    getById: function(id) {
170
                        return window.noCaptcha.find(function (captcha) {
171
                            return captcha.id === id;
172
                        });
173
                    },
174
                    find: function(callback) {
175
                        return window.noCaptcha.captchas.find(callback);
176
                    },
177
                    render: function(name, sitekey) {
178
                        var captcha = {
179
                            id: grecaptcha.render(name, {'sitekey' : sitekey}),
180
                            name: name
181
                        };
182
                        
183
                        window.noCaptcha.captchas.push(captcha);
184
                        
185
                        return captcha;
186
                    }
187
                }
188 1
            </script>"
189
        );
190
    }
191
192
    /**
193
     * Get script tag with a callback function.
194
     *
195
     * @param  array   $captchas
196
     * @param  string  $callbackName
197
     *
198
     * @return \Illuminate\Support\HtmlString
199
     */
200 4
    public function scriptWithCallback(array $captchas, $callbackName = 'captchaRenderCallback')
201
    {
202 4
        $script = $this->script($callbackName)->toHtml();
203
204 4
        if ( ! empty($script) && ! empty($captchas)) {
205 4
            $script = implode(PHP_EOL, [
206 4
                $this->getApiScript()->toHtml(),
207 4
                '<script>',
208 4
                    "var $callbackName = function() {",
209 4
                        $this->renderCaptchas($captchas),
210 4
                    '};',
211 4
                '</script>',
212 4
                $script,
213
            ]);
214
        }
215
216 4
        return $this->toHtmlString($script);
217
    }
218
219
    /**
220
     * Rendering captchas with callback function.
221
     *
222
     * @param  array  $captchas
223
     *
224
     * @return string
225
     */
226 4
    private function renderCaptchas(array $captchas)
227
    {
228
        return implode(PHP_EOL, array_map(function($captcha) {
229 4
            return "if (document.getElementById('{$captcha}')) { window.noCaptcha.render('{$captcha}', '{$this->siteKey}'); }";
230 4
        }, $captchas));
231
    }
232
233
    /* -----------------------------------------------------------------
234
     |  Check Methods
235
     | -----------------------------------------------------------------
236
     */
237
238
    /**
239
     * Check if callback is not empty.
240
     *
241
     * @param  string|null  $callbackName
242
     *
243
     * @return bool
244
     */
245 20
    private function hasCallbackName($callbackName)
246
    {
247 20
        return ! (is_null($callbackName) || trim($callbackName) === '');
248
    }
249
250
    /* -----------------------------------------------------------------
251
     |  Other Methods
252
     | -----------------------------------------------------------------
253
     */
254
255
    /**
256
     * Parse the response.
257
     *
258
     * @param  string  $json
259
     *
260
     * @return \Arcanedev\NoCaptcha\Utilities\AbstractResponse|mixed
261
     */
262 12
    protected function parseResponse($json)
263
    {
264 12
        return ResponseV2::fromJson($json);
265
    }
266
267
    /**
268
     * Prepare the attributes.
269
     *
270
     * @param  array  $attributes
271
     *
272
     * @return array
273
     */
274 68
    private function prepareAttributes(array $attributes)
275
    {
276 68
        $attributes = array_merge(
277 68
            ['class' => 'g-recaptcha', 'data-sitekey' => $this->siteKey],
278 51
            array_filter($attributes)
279
        );
280
281 68
        self::checkDataAttribute($attributes, 'data-type', ['image', 'audio'], 'image');
282 68
        self::checkDataAttribute($attributes, 'data-theme', ['light', 'dark'], 'light');
283 68
        self::checkDataAttribute($attributes, 'data-size', ['normal', 'compact', 'invisible'], 'normal');
284 68
        self::checkDataAttribute($attributes, 'data-badge', ['bottomright', 'bottomleft', 'inline'], 'bottomright');
285
286 68
        return $attributes;
287
    }
288
289
    /**
290
     * Check the `data-*` attribute.
291
     *
292
     * @param  array   $attributes
293
     * @param  string  $name
294
     * @param  array   $supported
295
     * @param  string  $default
296
     */
297 68
    private static function checkDataAttribute(array &$attributes, $name, array $supported, $default)
298
    {
299 68
        $attribute = $attributes[$name] ?? null;
300
301 68
        if ( ! is_null($attribute)) {
302 60
            $attribute = (is_string($attribute) && in_array($attribute, $supported))
303 44
                ? strtolower(trim($attribute))
304 60
                : $default;
305
306 60
            $attributes[$name] = $attribute;
307
        }
308 68
    }
309
310
    /**
311
     * Prepare the name and id attributes.
312
     *
313
     * @param  string|null  $name
314
     *
315
     * @return array
316
     *
317
     * @throws \Arcanedev\NoCaptcha\Exceptions\InvalidArgumentException
318
     */
319 76
    protected static function prepareNameAttribute($name)
320
    {
321 76
        if (is_null($name))
322 4
            return [];
323
324 72
        if ($name === AbstractNoCaptcha::CAPTCHA_NAME) {
325 12
            throw new InvalidArgumentException(
326 12
                'The captcha name must be different from "' . AbstractNoCaptcha::CAPTCHA_NAME . '".'
327
            );
328
        }
329
330 60
        return array_combine(['id', 'name'], [$name, $name]);
331
    }
332
}
333