Completed
Push — master ( f480bf...21d5d4 )
by Patrick
03:35
created

index.php ➔ obj_edit()   C

Complexity

Conditions 11
Paths 52

Size

Total Lines 53
Code Lines 30

Duplication

Lines 8
Ratio 15.09 %

Importance

Changes 0
Metric Value
cc 11
eloc 30
nc 52
nop 1
dl 8
loc 53
rs 6.2926
c 0
b 0
f 0

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
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 13 and the first side effect is on line 2.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
require_once('class.FlipREST.php');
3
require_once('class.ThemeDB.php');
4
5 View Code Duplication
if($_SERVER['REQUEST_URI'][0] == '/' && $_SERVER['REQUEST_URI'][1] == '/')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6
{
7
    $_SERVER['REQUEST_URI'] = substr($_SERVER['REQUEST_URI'], 1);
8
}
9
10
$app = new FlipREST();
11
$app->group('/themes', 'themes');
12
13
function trim_obj(&$obj)
14
{
15
    foreach($obj as $key=>$value)
16
    {
17
        if($key == '_id')
18
        {
19
            $obj['_id'] = (string)$obj['_id'];
20
        }
21
        else if(is_object($value) || is_array($value))
22
        {
23
            unset($obj[$key]);
24
        }
25
    }
26
}
27
28
function validate_user_is_admin($user)
29
{
30
   return $user->isInGroupNamed('ThemeAdmins');
31
}
32
33
function validate_user_has_access($user, $obj)
34
{
35
   if($user->isInGroupNamed('ThemeAdmins'))
36
   {
37
       return true;
38
   }
39
   return in_array($user->getUid(), $obj['registrars']);
40
}
41
42
function list_obj()
43
{
44
    global $app;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
45
    if(!$app->user)
46
    {
47
        throw new Exception('Must be logged in', ACCESS_DENIED);
48
    }
49
    $params = $app->request->params();
50
    if(isset($params['fmt']))
51
    {
52
       unset($params['fmt']);
53
    }
54
    if(isset($params['_']))
55
    {
56
       unset($params['_']);
57
    }
58
    $logo_urls = false;
59
    $db = new ThemeDB();
60
    $fields = false;
61
    if(isset($params['no_logo']))
62
    {
63
        $fields = array('logo' => false);
64
        unset($params['no_logo']);
65
    }
66
    if(isset($params['logo_url']))
67
    {
68
        $logo_urls = true;
69
        unset($params['logo_url']);
70
    }
71
    if(count($params))
72
    {
73
        $objs = $db->searchFromCollection('themes', $params, $fields);
0 ignored issues
show
Bug introduced by
It seems like $fields defined by array('logo' => false) on line 63 can also be of type array<string,false,{"logo":"false"}>; however, ThemeDB::searchFromCollection() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
74
    }
75
    else
76
    {
77
        $objs = $db->getAllFromCollection('themes', false, false, $fields);
0 ignored issues
show
Bug introduced by
It seems like $fields defined by array('logo' => false) on line 63 can also be of type array<string,false,{"logo":"false"}>; however, ThemeDB::getAllFromCollection() does only seem to accept boolean, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
78
    }
79
    if(!validate_user_is_admin($app->user))
80
    {
81
        $count = count($objs);
82
        for($i = 0; $i < $count; $i++)
83
        {
84
            trim_obj($objs[$i]);
85
        }
86
    }
87
    $count = count($objs);
88
    for($i = 0; $i < $count; $i++)
89
    {
90
        if($logo_urls && isset($objs[$i]['logo']))
91
        {
92
            $objs[$i]['logo'] = $app->request->getUrl().$app->request->getPath().'/'.$objs[$i]['_id'].'/logo';
93
        }
94
    }
95
    echo json_encode($objs);
96
}
97
98
function obj_list_with_filter($field)
99
{
100
    global $app;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
101
    if(!$app->user)
102
    {
103
        throw new Exception('Must be logged in', ACCESS_DENIED);
104
    }
105
    if(!validate_user_is_admin($app->user, $collection))
0 ignored issues
show
Bug introduced by
The variable $collection does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Unused Code introduced by
The call to validate_user_is_admin() has too many arguments starting with $collection.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
106
    {
107
        throw new Exception('User not admin', ACCESS_DENIED);
108
    }
109
    $db = new ThemeDB();
110
    $objs = $db->getAllFromCollection('themes');
111
    $res = array();
112
    $count = count($objs);
113
    for($i = 0; $i < $count; $i++)
114
    {
115
        if(isset($objs[$i][$field]))
116
        {
117
            array_push($res, $objs[$i][$field]);
118
        }
119
    }
120
    echo json_encode($res);
121
}
122
123
function obj_view($id, $field = FALSE)
124
{
125
    global $app;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
126
    if(!$app->user)
127
    {
128
        throw new Exception('Must be logged in', ACCESS_DENIED);
129
    }
130
    $db = new ThemeDB();
131
    if($id === '*')
132
    {
133
        obj_list_with_filter($field);
134
        return;
135
    }
136
    $obj = $db->getObjectFromCollectionByID('themes', $id);
137
    if($obj === FALSE)
138
    {
139
        throw new Exception('Unable to obtain object!', INTERNAL_ERROR);
140
    }
141
    else
142
    {
143
        if($app->request->params('full') === null)
144
        {
145
            if(!validate_user_is_admin($app->user))
146
            {
147
               trim_obj($obj);
148
            }
149
            else if($field === false)
150
            {
151
                trim_obj($obj);
152
            }
153
            if($field !== FALSE)
154
            {
155
                if(!is_array($obj[$field]) && strncmp($obj[$field], 'data:', 5) === 0)
156
                {
157
                    $app->fmt = 'passthru';
158
                    $str = substr($obj[$field], 5);
159
                    $type = strtok($str, ';');
160
                    strtok(',');
161
                    $str = strtok("\0");
162
                    print(base64_decode($str));
163
                    $app->response->headers->set('Content-Type', $type);
164
                }
165
                else
166
                {
167
                    echo json_encode($obj[$field]);
168
                }
169
                return;
170
            }
171
        }
172
        else
173
        {
174
            if(validate_user_has_access($app->user, $obj) === FALSE)
175
            {
176
                throw new Exception('Cannot edit object that is not yours', ACCESS_DENIED);
177
            }
178
        }
179
        echo json_encode($obj);
180
    }
181
}
182
183
function obj_add()
184
{
185
    global $app;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
186
    if(!$app->user)
187
    {
188
        throw new Exception('Must be logged in', ACCESS_DENIED);
189
    }
190
    $collection = 'themes';
0 ignored issues
show
Unused Code introduced by
$collection is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
191
    $db = new ThemeDB();
192
    $body = $app->request->getBody();
193
    $obj  = json_decode($body);
194
    $obj  = get_object_vars($obj);
195
    //Ensure minimum fields are set...
196
    if(!isset($obj['name']))
197
    {
198
        throw new Exception('Missing one or more required parameters!', INTERNAL_ERROR);
199
    }
200
    $obj['year'] = $db->getCurrentYear();
201
    if(!isset($obj['registrars']))
202
    {
203
        $obj['registrars'] = array();
204
    }
205
    array_push($obj['registrars'], $app->user->getUid());
206
    if(isset($obj['_id']) && strlen($obj['_id']) > 0)
207
    {
208
        $app->redirect('themes/'.$obj['_id'], 307);
209
        return;
210
    }
211
    else
212
    {
213
        $res = $db->addObjectToCollection('themes', $obj);
214
    }
215
    if($res === FALSE)
216
    {
217
        throw new Exception('Unable to add theme!', INTERNAL_ERROR);
218
    }
219
    else
220
    {
221
        echo json_encode(array('_id'=>(string)$res, 'url'=>$app->request->getUrl().$app->request->getPath().'/'.(string)$res));
222
    }
223
}
224
225
function obj_edit($id)
226
{
227
    global $app;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
228
    if(!$app->user)
229
    {
230
        throw new Exception('Must be logged in', ACCESS_DENIED);
231
    }
232
    $db = new ThemeDB();
233
    $old_obj = $db->getObjectFromCollectionByID('themes', $id);
234
    if(validate_user_has_access($app->user, $old_obj) === FALSE)
235
    {
236
        throw new Exception('Cannot edit object that is not yours', ACCESS_DENIED);
237
    }
238
    $obj = $app->request->params();
239
    if($obj === null || count($obj) === 0)
240
    {
241
        $body = $app->request->getBody();
242
        $obj  = json_decode($body);
243
        $obj  = get_object_vars($obj);
244
    }
245
    //Ensure minimum fields are set...
246
    if(!isset($obj['name']))
247
    {
248
        throw new Exception('Missing one or more required parameters!', INTERNAL_ERROR);
249
    }
250
    $obj['year'] = $db->getCurrentYear();
251
    if(!isset($obj['registrars']))
252
    {
253
        $obj['registrars'] = array();
254
    }
255
    $obj['registrars'] = array_merge($obj['registrars'], $old_obj['registrars']);
256
    if(validate_user_is_admin($app->user) === FALSE)
257
    {
258
        $uid = $app->user->getUid();
259
        if(!in_array($uid, $obj['registrars']))
260
        {
261
            array_push($obj['registrars'], $app->user->getUid());
262
        }
263
    }
264
    if(!isset($obj['_id']))
265
    {
266
        $obj['_id'] = $id;
267
    }
268
    $res = $db->updateObjectInCollection('themes', $obj);
269 View Code Duplication
    if($res === FALSE)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
270
    {
271
        throw new Exception('Unable to update object!', INTERNAL_ERROR);
272
    }
273
    else
274
    {
275
        echo json_encode(array('update'=>TRUE));
276
    }
277
}
278
279
function obj_delete($id)
280
{
281
    global $app;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
282
    if(!$app->user)
283
    {
284
        throw new Exception('Must be logged in', ACCESS_DENIED);
285
    }
286
    $db = new ThemeDB();
287
    $old_obj = $db->getObjectFromCollectionByID('themes', $id);
288
    if(validate_user_has_access($app->user, $old_obj) === FALSE)
289
    {
290
        throw new Exception('Cannot delete object that is not yours', ACCESS_DENIED);
291
    }
292
    $res = $db->deleteObjectFromCollection('themes', $old_obj);
293 View Code Duplication
    if($res === false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
294
    {
295
        throw new Exception('Unable to delete object!', INTERNAL_ERROR);
296
    }
297
    else
298
    {
299
        echo json_encode(array('delete'=>TRUE));
300
    }
301
}
302
303
function themes()
304
{
305
    global $app;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
306
    $app->get('', 'list_obj');
307
    $app->get('/:id(/:field)', 'obj_view');
308
    $app->post('', 'obj_add');
309
    $app->patch('/:id', 'obj_edit');
310
    $app->delete('/:id', 'obj_delete');
311
}
312
313
$app->run();
314
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
315