Completed
Pull Request — master (#489)
by Richard
10:39
created

ProfileFieldHandler::insertFields()   F

Complexity

Conditions 35
Paths 12852

Size

Total Lines 122
Code Lines 85

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 122
rs 2
cc 35
eloc 85
nc 12852
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
use Xoops\Core\Database\Connection;
13
use Xoops\Core\Kernel\Handlers\XoopsUser;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, XoopsUser.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
14
use Xoops\Core\Kernel\XoopsObject;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, XoopsObject.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
15
use Xoops\Core\Kernel\XoopsPersistableObjectHandler;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, XoopsPersistableObjectHandler.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
16
17
/**
18
 * Extended User Profile
19
 *
20
 * @package         Profile
21
 * @author          Jan Pedersen
22
 * @author          Taiwen Jiang <[email protected]>
23
 * @copyright       2000-2016 XOOPS Project (www.xoops.org)
24
 * @license         GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
25
 * @since           2.3.0
26
 */
27
class ProfileField extends XoopsObject
28
{
29
    /**
30
     * Constructor
31
     */
32
    public function __construct()
33
    {
34
        $this->initVar('field_id', XOBJ_DTYPE_INT, null);
35
        $this->initVar('cat_id', XOBJ_DTYPE_INT, null, true);
36
        $this->initVar('field_type', XOBJ_DTYPE_TXTBOX);
37
        $this->initVar('field_valuetype', XOBJ_DTYPE_INT, null, true);
38
        $this->initVar('field_name', XOBJ_DTYPE_TXTBOX, null, true);
39
        $this->initVar('field_title', XOBJ_DTYPE_TXTBOX);
40
        $this->initVar('field_description', XOBJ_DTYPE_TXTAREA);
41
        $this->initVar('field_required', XOBJ_DTYPE_INT, 0); //0 = no, 1 = yes
42
        $this->initVar('field_maxlength', XOBJ_DTYPE_INT, 0);
43
        $this->initVar('field_weight', XOBJ_DTYPE_INT, 0);
44
        $this->initVar('field_default', XOBJ_DTYPE_TXTAREA, "");
45
        $this->initVar('field_notnull', XOBJ_DTYPE_INT, 1);
46
        $this->initVar('field_edit', XOBJ_DTYPE_INT, 0);
47
        $this->initVar('field_show', XOBJ_DTYPE_INT, 0);
48
        $this->initVar('field_config', XOBJ_DTYPE_INT, 0);
49
        $this->initVar('field_options', XOBJ_DTYPE_ARRAY, array());
50
        $this->initVar('step_id', XOBJ_DTYPE_INT, 0);
51
    }
52
53
    /**
54
     * Extra treatment dealing with non latin encoding
55
     * Tricky solution
56
     *
57
     * @param string $key
58
     * @param mixed $value
59
     *
60
     * @return void
61
     *
62
     * @todo evaluate removing this. New considerations: full UTF-8 system, new Dtype::TYPE_JSON
63
     */
64
    public function setVar($key, $value)
65
    {
66 View Code Duplication
        if ($key === 'field_options' && is_array($value)) {
67
            foreach (array_keys($value) as $idx) {
68
                $value[$idx] = base64_encode($value[$idx]);
69
            }
70
        }
71
        parent::setVar($key, $value);
72
    }
73
74
    /**
75
     * @param string $key
76
     * @param string $format
77
     * @return array|mixed
78
     */
79
    public function getVar($key, $format = 's')
80
    {
81
        $value = parent::getVar($key, $format);
82 View Code Duplication
        if ($key === 'field_options' && !empty($value)) {
83
            foreach (array_keys($value) as $idx) {
84
                $value[$idx] = base64_decode($value[$idx]);
85
            }
86
        }
87
        return $value;
88
    }
89
90
    /**
91
     * Returns a {@link Xoops\Form\Element} for editing the value of this field
92
     *
93
     * @param XoopsUser $user {@link XoopsUser} object to edit the value of
94
     * @param ProfileProfile $profile {@link ProfileProfile} object to edit the value of
95
     *
96
     * @return Xoops\Form\Element
97
     **/
98
    public function getEditElement(XoopsUser $user, ProfileProfile $profile)
99
    {
100
        $xoops = Xoops::getInstance();
101
        $value = in_array($this->getVar('field_name'), $this->getUserVars())
102
                ? $user->getVar($this->getVar('field_name'), 'e') : $profile->getVar($this->getVar('field_name'), 'e');
103
104
        $caption = $this->getVar('field_title');
105
        $caption = defined($caption) ? constant($caption) : $caption;
106
        $name = $this->getVar('field_name', 'e');
107
        $options = $this->getVar('field_options');
108
        if (is_array($options)) {
109
            //asort($options);
110
111
            foreach (array_keys($options) as $key) {
112
                $optval = defined($options[$key]) ? constant($options[$key]) : $options[$key];
113
                $optkey = defined($key) ? constant($key) : $key;
114
                unset($options[$key]);
115
                $options[$optkey] = $optval;
116
            }
117
        }
118
        switch ($this->getVar('field_type')) {
119
            default:
120
            case "autotext":
121
                //autotext is not for editing
122
                $element = new Xoops\Form\Label($caption, $this->getOutputValue($user, $profile));
123
                break;
124
125
            case "textbox":
126
                $element = new Xoops\Form\Text($caption, $name, 35, $this->getVar('field_maxlength'), $value);
127
                break;
128
129
            case "textarea":
130
                $element = new Xoops\Form\TextArea($caption, $name, $value, 4, 30);
131
                break;
132
133
            case "dhtml":
134
                $element = new Xoops\Form\DhtmlTextArea($caption, $name, $value, 10, 30);
135
                break;
136
137
            case "select":
138
                $element = new Xoops\Form\Select($caption, $name, $value);
139
                // If options do not include an empty element, then add a blank option to prevent any default selection
140
                if (!in_array('', array_keys($options))) {
141
                    $element->addOption('', XoopsLocale::NONE);
142
143
                    $eltmsg = empty($caption) ? sprintf(XoopsLocale::F_ENTER, $name) : sprintf(XoopsLocale::F_ENTER, $caption);
144
                    $eltmsg = str_replace('"', '\"', stripslashes($eltmsg));
145
                    $element->addCustomValidationCode("\nvar hasSelected = false; var selectBox = myform.{$name};" . "for (i = 0; i < selectBox.options.length; i++  ) { if ( selectBox.options[i].selected == true && selectBox.options[i].value != '' ) { hasSelected = true; break; } }" . "if ( !hasSelected ) { window.alert(\"{$eltmsg}\"); selectBox.focus(); return false; }");
146
                }
147
                $element->addOptionArray($options);
148
                break;
149
150
            case "select_multi":
151
                $element = new Xoops\Form\Select($caption, $name, $value, 5, true);
152
                $element->addOptionArray($options);
153
                break;
154
155
            case "radio":
156
                $element = new Xoops\Form\Radio($caption, $name, $value);
157
                $element->addOptionArray($options);
158
                break;
159
160
            case "checkbox":
161
                $element = new Xoops\Form\Checkbox($caption, $name, $value);
162
                $element->addOptionArray($options);
163
                break;
164
165
            case "yesno":
166
                $element = new Xoops\Form\RadioYesNo($caption, $name, $value);
167
                break;
168
169
            case "group":
170
                $element = new Xoops\Form\SelectGroup($caption, $name, true, $value);
171
                break;
172
173
            case "group_multi":
174
                $element = new Xoops\Form\SelectGroup($caption, $name, true, $value, 5, true);
175
                break;
176
177
            case "language":
178
                $element = new Xoops\Form\SelectLanguage($caption, $name, $value);
179
                break;
180
181
            case "date":
182
                $element = new Xoops\Form\DateSelect($caption, $name, $value);
183
                break;
184
185
            case "longdate":
186
                $element = new Xoops\Form\DateSelect($caption, $name, str_replace("-", "/", $value));
187
                break;
188
189
            case "datetime":
190
                $element = new Xoops\Form\DateTime($caption, $name, $value);
191
                break;
192
193
            case "timezone":
194
                $element = new Xoops\Form\SelectTimeZone($caption, $name, $value);
195
                break;
196
197
            case "rank":
198
                $ranklist = $xoops->service('userrank')->getAssignableUserRankList()->getValue();
199
                if ($ranklist !== null) {
200
                    $element = new Xoops\Form\Select($caption, $name, $value);
201
                    $element->addOption(0, "--------------");
202
                    $element->addOptionArray($ranklist);
203
                } else {
204
                    $element = new Xoops\Form\Hidden($name, $value);
205
                }
206
                break;
207
208
            case 'theme':
209
                $element = new Xoops\Form\Select($caption, $name, $value);
210
                $element->addOption("0", _PROFILE_MA_SITEDEFAULT);
211
                $handle = opendir(\XoopsBaseConfig::get('themes-path') . '/');
212
                $dirlist = array();
213
                while (false !== ($file = readdir($handle))) {
214
                    if (is_dir(\XoopsBaseConfig::get('themes-path') . '/' . $file) && !preg_match("/^[.]{1,2}$/", $file) && strtolower($file) !== 'cvs') {
215
                        if (XoopsLoad::fileExists(\XoopsBaseConfig::get('themes-path') . "/" . $file . "/theme.tpl") && in_array($file, $xoops->getConfig('theme_set_allowed'))) {
216
                            $dirlist[$file] = $file;
217
                        }
218
                    }
219
                }
220
                closedir($handle);
221
                if (!empty($dirlist)) {
222
                    asort($dirlist);
223
                    $element->addOptionArray($dirlist);
224
                }
225
                break;
226
        }
227
        if ($this->getVar('field_description') != "") {
228
            $element->setDescription($this->getVar('field_description'));
229
        }
230
        return $element;
231
    }
232
233
    /**
234
     * Returns a value for output of this field
235
     *
236
     * @param XoopsUser $user {@link XoopsUser} object to get the value of
237
     * @param profileProfile $profile object to get the value of
238
     *
239
     * @return string
240
     **/
241
    public function getOutputValue(XoopsUser $user, ProfileProfile $profile)
242
    {
243
        $xoops = Xoops::getInstance();
244
        $xoops->loadLanguage('modinfo', 'profile');
245
246
        $value = in_array($this->getVar('field_name'), $this->getUserVars())
247
                ? $user->getVar($this->getVar('field_name')) : $profile->getVar($this->getVar('field_name'));
248
249
        switch ($this->getVar('field_type')) {
250
            default:
251
            case "textbox":
252
                if ($this->getVar('field_name') === 'url' && $value != '') {
253
                    return '<a href="' . $xoops->formatURL($value) . '" rel="external">' . $value . '</a>';
254
                } else {
255
                    return $value;
256
                }
257
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
258
            case "textarea":
259
            case "dhtml":
260
            case 'theme':
261
            case "language":
262
            case "list":
263
                return $value;
264
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
265
266
            case "select":
267
            case "radio":
268
                $options = $this->getVar('field_options');
269 View Code Duplication
                if (isset($options[$value])) {
270
                    $value = htmlspecialchars(
271
                        defined($options[$value]) ? constant($options[$value]) : $options[$value]
272
                    );
273
                } else {
274
                    $value = "";
275
                }
276
                return $value;
277
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
278
279
            case "select_multi":
280
            case "checkbox":
281
                $options = $this->getVar('field_options');
282
                $ret = array();
283
                if (count($options) > 0) {
284
                    foreach (array_keys($options) as $key) {
285 View Code Duplication
                        if (in_array($key, $value)) {
286
                            $ret[$key] = htmlspecialchars(
287
                                defined($options[$key]) ? constant($options[$key]) : $options[$key]
288
                            );
289
                        }
290
                    }
291
                }
292
                return $ret;
293
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
294
295
            case "group":
296
                $member_handler = $xoops->getHandlerMember();
297
                $options = $member_handler->getGroupList();
298
                $ret = isset($options[$value]) ? $options[$value] : '';
299
                return $ret;
300
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
301
302
            case "group_multi":
303
                $member_handler = $xoops->getHandlerMember();
304
                $options = $member_handler->getGroupList();
305
                $ret = array();
306
                foreach (array_keys($options) as $key) {
307
                    if (in_array($key, $value)) {
308
                        $ret[$key] = htmlspecialchars($options[$key]);
309
                    }
310
                }
311
                return $ret;
312
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
313
314
            case "longdate":
315
                //return YYYY/MM/DD format - not optimal as it is not using local date format, but how do we do that
316
                //when we cannot convert it to a UNIX timestamp?
317
                return str_replace("-", "/", $value);
318
319
            case "date":
320
                return XoopsLocale::formatTimestamp($value, 's');
321
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
322
323
            case "datetime":
324
                if (!empty($value)) {
325
                    return XoopsLocale::formatTimestamp($value, 'm');
326
                } else {
327
                    return _PROFILE_MI_NEVER_LOGGED_IN;
328
                }
329
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
330
331
            case "autotext":
332
                $value = $user->getVar($this->getVar('field_name'), 'n'); //autotext can have HTML in it
333
                $value = str_replace("{X_UID}", $user->getVar("uid"), $value);
334
                $value = str_replace("{X_URL}", \XoopsBaseConfig::get('url'), $value);
335
                $value = str_replace("{X_UNAME}", $user->getVar("uname"), $value);
336
                return $value;
337
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
338
339
            case "rank":
340
                $userrank = $user->rank();
341
                $user_rankimage = "";
342 View Code Duplication
                if (isset($userrank['image']) && $userrank['image'] != "") {
343
                    $user_rankimage = '<img src="' . $userrank['image'] . '" alt="' . $userrank['title'] . '" /><br />';
344
                }
345
                return $user_rankimage . $userrank['title'];
346
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
347
348
            case "yesno":
349
                return $value ? XoopsLocale::YES : XoopsLocale::NO;
350
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
351
352
            case "timezone":
353
                $timezones = XoopsLists::getTimeZoneList();
354
                $value = empty($value) ? "0" : (string)($value);
355
                return $timezones[str_replace('.0', '', $value)];
356
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
357
        }
358
    }
359
360
    /**
361
     * Returns a value ready to be saved in the database
362
     *
363
     * @param mixed $value Value to format
364
     *
365
     * @return mixed
366
     */
367
    public function getValueForSave($value)
368
    {
369
        switch ($this->getVar('field_type')) {
370
            default:
371
            case "textbox":
372
            case "textarea":
373
            case "dhtml":
374
            case "yesno":
375
            case "timezone":
376
            case 'theme':
377
            case "language":
378
            case "list":
379
            case "select":
380
            case "radio":
381
            case "select_multi":
382
            case "group":
383
            case "group_multi":
384
            case "longdate":
385
                return $value;
386
387
            case "checkbox":
388
                return (array)$value;
389
390
            case "date":
391
                if ($value != "") {
392
                    return strtotime($value);
393
                }
394
                return $value;
395
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
396
397
            case "datetime":
398
                if (!empty($value)) {
399
                    return strtotime($value['date']) + (int)($value['time']);
400
                }
401
                return $value;
402
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
403
        }
404
    }
405
406
    /**
407
     * Get names of user variables
408
     *
409
     * @return array
410
     */
411
    public function getUserVars()
412
    {
413
        /* @var $profile_handler ProfileProfileHandler */
414
        $profile_handler = \Xoops::getModuleHelper('profile')->getHandler('profile');
415
        return $profile_handler->getUserVars();
416
    }
417
}
418
419
/**
420
 * @package kernel
421
 * @copyright copyright &copy; 2000 XOOPS.org
422
 */
423
class ProfileFieldHandler extends XoopsPersistableObjectHandler
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
424
{
425
    /**
426
     * @param null|Connection $db database
427
     */
428
    public function __construct(Connection $db = null)
429
    {
430
        parent::__construct($db, 'profile_field', 'ProfileField', 'field_id', 'field_title');
431
    }
432
433
    /**
434
     * Read field information from cached storage
435
     *
436
     * @param bool   $force_update   read fields from database and not cached storage
437
     *
438
     * @return array
439
     */
440
    public function loadFields($force_update = false)
441
    {
442
        static $fields = array();
443
        if (!empty($force_update) || count($fields) == 0) {
444
            $this->table_link = $this->db2->prefix('profile_category');
445
            $criteria = new Criteria('o.field_id', 0, "!=");
446
            $criteria->setSort('l.cat_weight ASC, o.field_weight');
447
            $field_objs = $this->getByLink($criteria, array('o.*'), true, 'cat_id', 'cat_id');
448
            /* @var ProfileField $field */
449
            foreach ($field_objs as $field) {
0 ignored issues
show
Bug introduced by
The expression $field_objs of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
450
                $fields[$field->getVar('field_name')] = $field;
451
            }
452
        }
453
        return $fields;
454
    }
455
456
    /**
457
     * save a profile field in the database
458
     *
459
     * @param XoopsObject|ProfileField $obj reference to the object
460
     * @param bool $force whether to force the query execution despite security settings
461
     * @return bool FALSE if failed, TRUE if already present and unchanged or successful
462
     */
463
    public function insertFields(XoopsObject $obj, $force = false)
464
    {
465
        $profile_handler = \Xoops::getModuleHelper('profile')->getHandler('profile');
466
        $obj->setVar('field_name', str_replace(' ', '_', $obj->getVar('field_name')));
467
        $obj->cleanVars(); //Don't quote
468
        switch ($obj->getVar('field_type')) {
469
            case "datetime":
470
            case "date":
471
                $obj->setVar('field_valuetype', XOBJ_DTYPE_INT);
472
                $obj->setVar('field_maxlength', 10);
473
                break;
474
475
            case "longdate":
476
                $obj->setVar('field_valuetype', XOBJ_DTYPE_MTIME);
477
                break;
478
479
            case "yesno":
480
                $obj->setVar('field_valuetype', XOBJ_DTYPE_INT);
481
                $obj->setVar('field_maxlength', 1);
482
                break;
483
484
            case "textbox":
485
                if ($obj->getVar('field_valuetype') != XOBJ_DTYPE_INT) {
486
                    $obj->setVar('field_valuetype', XOBJ_DTYPE_TXTBOX);
487
                }
488
                break;
489
490
            case "autotext":
491
                if ($obj->getVar('field_valuetype') != XOBJ_DTYPE_INT) {
492
                    $obj->setVar('field_valuetype', XOBJ_DTYPE_TXTAREA);
493
                }
494
                break;
495
496
            case "group_multi":
497
            case "select_multi":
498
            case "checkbox":
499
                $obj->setVar('field_valuetype', XOBJ_DTYPE_ARRAY);
500
                break;
501
502
            case "language":
503
            case "timezone":
504
            case "theme":
505
                $obj->setVar('field_valuetype', XOBJ_DTYPE_TXTBOX);
506
                break;
507
508
            case "dhtml":
509
            case "textarea":
510
                $obj->setVar('field_valuetype', XOBJ_DTYPE_TXTAREA);
511
                break;
512
        }
513
514
        if ($obj->getVar('field_valuetype') == "") {
515
            $obj->setVar('field_valuetype', XOBJ_DTYPE_TXTBOX);
516
        }
517
518
        if (!in_array($obj->getVar('field_name'), $this->getUserVars())) {
519
            if ($obj->isNew()) {
520
                //add column to table
521
                $changetype = "ADD";
522
            } else {
523
                //update column information
524
                $changetype = "CHANGE `" . $obj->getVar('field_name', 'n') . "`";
525
            }
526
            $maxlengthstring = $obj->getVar('field_maxlength') > 0 ? "(" . $obj->getVar('field_maxlength') . ")" : "";
527
528
            //set type
529
            switch ($obj->getVar('field_valuetype')) {
530
                default:
531
                case XOBJ_DTYPE_ARRAY:
532
                case XOBJ_DTYPE_EMAIL:
533
                case XOBJ_DTYPE_TXTBOX:
534
                case XOBJ_DTYPE_URL:
535
                    $type = "varchar";
536
                    // varchars must have a maxlength
537
                    if (!$maxlengthstring) {
538
                        //so set it to max if maxlength is not set - or should it fail?
539
                        $maxlengthstring = "(255)";
540
                        $obj->setVar('field_maxlength', 255);
541
                    }
542
                    break;
543
544
                case XOBJ_DTYPE_INT:
545
                    $type = "int";
546
                    break;
547
548
                case XOBJ_DTYPE_DECIMAL:
549
                    $type = "decimal(14,6)";
550
                    break;
551
552
                case XOBJ_DTYPE_FLOAT:
553
                    $type = "float(15,9)";
554
                    break;
555
556
                case XOBJ_DTYPE_OTHER:
557
                case XOBJ_DTYPE_TXTAREA:
558
                    $type = "text";
559
                    $maxlengthstring = "";
560
                    break;
561
562
                case XOBJ_DTYPE_MTIME:
563
                    $type = "date";
564
                    $maxlengthstring = "";
565
                    break;
566
            }
567
568
            $sql = "ALTER TABLE `" . $profile_handler->table . "` " . $changetype . " `" . $obj->cleanVars['field_name'] . "` " . $type . $maxlengthstring . ' NULL';
569
            if ($force) {
570
                $this->db2->setForce(true);
571
            }
572
            if (!$this->db2->query($sql)) {
573
                return false;
574
            }
575
        }
576
577
        //change this to also update the cached field information storage
578
        $obj->setDirty();
579
        if (!parent::insert($obj, $force)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression parent::insert($obj, $force) of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. 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...
Comprehensibility Bug introduced by
It seems like you call parent on a different method (insert() instead of insertFields()). Are you sure this is correct? If so, you might want to change this to $this->insert().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
580
            return false;
581
        }
582
        return $obj->getVar('field_id');
583
584
    }
585
586
    /**
587
     * delete a profile field from the database
588
     *
589
     * @param XoopsObject|ProfileField $obj reference to the object to delete
590
     * @param bool $force
591
     * @return bool FALSE if failed.
592
     **/
593
    public function deleteFields(XoopsObject $obj, $force = false)
594
    {
595
        $xoops = Xoops::getInstance();
596
        $profile_handler = \Xoops::getModuleHelper('profile')->getHandler('profile');
597
        // remove column from table
598
        $sql = "ALTER TABLE " . $profile_handler->table . " DROP `" . $obj->getVar('field_name', 'n') . "`";
599
        if ($this->db2->query($sql)) {
600
            //change this to update the cached field information storage
601
            if (!parent::delete($obj, $force)) {
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (delete() instead of deleteFields()). Are you sure this is correct? If so, you might want to change this to $this->delete().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
602
                return false;
603
            }
604
605
            if ($obj->getVar('field_show') || $obj->getVar('field_edit')) {
606
                $profile_module = $xoops->getModuleByDirname('profile');
607
                if (is_object($profile_module)) {
608
                    // Remove group permissions
609
                    $groupperm_handler = $xoops->getHandlerGroupPermission();
610
                    $criteria = new CriteriaCompo(new Criteria('gperm_modid', $profile_module->getVar('mid')));
611
                    $criteria->add(new Criteria('gperm_itemid', $obj->getVar('field_id')));
612
                    return $groupperm_handler->deleteAll($criteria);
0 ignored issues
show
Bug introduced by
The method deleteAll does only exist in XoopsPersistableObjectHandler, but not in XoopsObjectHandler.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
613
                }
614
            }
615
        }
616
        return false;
617
    }
618
619
    /**
620
     * Get array of standard variable names (user table)
621
     *
622
     * @return string[]
623
     */
624
    public function getUserVars()
625
    {
626
        return array(
627
            'uid', 'uname', 'name', 'email', 'url', 'user_avatar', 'user_regdate', 'user_icq', 'user_from', 'user_sig',
628
            'user_viewemail', 'actkey', 'user_aim', 'user_yim', 'user_msnm', 'pass', 'posts', 'attachsig', 'rank',
629
            'level', 'theme', 'timezone', 'last_login', 'umode', 'uorder', 'notify_method', 'notify_mode',
630
            'user_occ', 'bio', 'user_intrest', 'user_mailok'
631
        );
632
    }
633
}
634