Completed
Push — master ( f2b61c...ad8d22 )
by Temitope
03:08
created

EmojiController::updateEmojiByPutVerb()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 12

Duplication

Lines 8
Ratio 40 %

Importance

Changes 11
Bugs 5 Features 1
Metric Value
c 11
b 5
f 1
dl 8
loc 20
rs 9.2
cc 4
eloc 12
nc 4
nop 3
1
<?php
2
/**
3
 * @author   Temitope Olotin <[email protected]>
4
 * @license  <https://opensource.org/license/MIT> MIT
5
 */
6
namespace Laztopaz\EmojiRestfulAPI;
7
8
use Exception;
9
use Firebase\JWT\JWT;
10
use Illuminate\Database\Capsule\Manager as Capsule;
11
use Psr\Http\Message\ResponseInterface as Response;
12
use Psr\Http\Message\ServerRequestInterface as Request;
13
14
class EmojiController
15
{
16
    private $auth;
17
18
    public function __construct(Oauth $auth)
19
    {
20
        $this->auth = $auth;
21
    }
22
23
    /**
24
     * This method list all emojis.
25
     *
26
     * @param $response
27
     *
28
     * @return json $emojis
29
     */
30
    public function listAllEmoji(Response $response)
31
    {
32
        $emojis = Emoji::with('keywords', 'category', 'created_by')
33
        ->get()
34
        ->toArray();
35
36
        if (count($emojis) > 0) {
37
            return $response
38
            ->withJson($this->formatEmoji($emojis), 200);
39
        }
40
41
        return $response->withJson(['message' => 'No Emoji to display now'], 404);
42
    }
43
44
    /**
45
     * This method get a single emoji.
46
     *
47
     * @param $response
48
     * @param $args
49
     *
50
     * @return json $emoji
51
     */
52
    public function getSingleEmoji(Response $response, $args)
53
    {
54
        $emoji = null;
55
56
        if ($args['id']) {
57
            $emoji = Emoji::where('id', '=', $args['id'])
58
            ->with('keywords', 'category', 'created_by')
59
            ->get();
60
61
            if (count($emoji) <= 0) {
62
                $emoji = Emoji::where('name', '=', strtolower($args['id']))
63
                ->with('keywords', 'category', 'created_by')
64
                ->get();
65
            }
66
        }
67
68
        $emoji = $emoji->toArray();
69
70
        if (count($emoji) > 0) {
71
            return $response
72
            ->withJson($this->formatEmoji($emoji), 200);
73
        }
74
75
        return $response->withJson(['message' => 'Emoji not found'], 404);
76
    }
77
78
    /**
79
     * This method creates a new emoji.
80
     *
81
     * @param $args
82
     *
83
     * @return json $response;
84
     */
85
    public function createEmoji(Request $request, Response $response)
86
    {
87
        $requestParams = $request->getParsedBody();
88
89
        if (is_array($requestParams)) {
90 View Code Duplication
            if (!$this->checkForDuplicateEmoji($requestParams['name'])) {
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...
91
                // Validate the user input fields
92
                $validateResponse = $this->validateUserInput(['name','char','category','keywords',], $requestParams);
93
94
                if (is_array($validateResponse)) {
95
                    return $response->withJson($validateResponse, 400);
96
                }
97
                return $this->runCreateEmoji($request, $response, $requestParams);
98
                
99
            }
100
101
            return $response->withJson(['message' => 'Emoji cannot be duplicated'], 400);
102
        }
103
    }
104
105
    /**
106
     *
107
     * This method creates emoji and keywords associated with it
108
     * @param $emoji
109
     * @param $request
110
     * @param $response
111
     * @param $requestParams
112
     *
113
     * @return json response
114
     */
115
    public function runCreateEmoji($request, $response, $requestParams)
116
    {
117
        $emoji = Emoji::create([
118
            'name'       => strtolower($requestParams['name']),
119
            'char'       => $requestParams['char'],
120
            'created_at' => date('Y-m-d h:i:s'),
121
            'category'   => $requestParams['category'],
122
            'created_by' => $this->getCurrentUserId($request, $response),
123
        ]);
124
        if ($emoji->id) {
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Laztopaz\EmojiRestfulAPI\Emoji>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
125
            $createdKeyword = $this->createEmojiKeywords($emoji->id, $requestParams['keywords']);
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Laztopaz\EmojiRestfulAPI\Emoji>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Unused Code introduced by
$createdKeyword 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...
126
127
            return $response->withJson($emoji->toArray(), 201);
128
        }
129
    }
130
131
    /**
132
     * This method updates an emoji.
133
     *
134
     * @param $request
135
     * @param $response
136
     *
137
     * @return json
138
     */
139
    public function updateEmojiByPutVerb(Request $request, Response $response, $args)
140
    {
141
        $upateParams = $request->getParsedBody();
142
        if (is_array($upateParams)) {
143
            $emoji = Emoji::find($args['id']);
144
145 View Code Duplication
            if (count($emoji) > 0) { // Validate the user input fields
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...
146
                $validateResponse = $this->validateUserInput(['name','char','category',], $upateParams);
147
                if (is_array($validateResponse)) {
148
                    return $response->withJson($validateResponse, 400);
149
                }
150
151
                return $this->runUpdateEmoji($emoji, $response, $updateParams);
0 ignored issues
show
Bug introduced by
The variable $updateParams does not exist. Did you mean $upateParams?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
152
            }
153
154
            return $response->withJson([
155
                'message' => 'Record cannot be updated because the id supplied is invalid'
156
            ], 404);
157
        }
158
    }
159
160
    /**
161
     * This method updates an emoji
162
     *
163
     * @param $emoji
164
     * @param $response
165
     * @param $updateParams
166
     *
167
     * @return json $response
168
     */
169
    public function runUpdateEmoji($emoji, $response, $updateParams)
0 ignored issues
show
Unused Code introduced by
The parameter $updateParams is not used and could be removed.

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

Loading history...
170
    {
171
        $emoji->name = $upateParams['name'];
0 ignored issues
show
Bug introduced by
The variable $upateParams does not exist. Did you mean $updateParams?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
172
        $emoji->char = $upateParams['char'];
0 ignored issues
show
Bug introduced by
The variable $upateParams does not exist. Did you mean $updateParams?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
173
        $emoji->category = $upateParams['category'];
0 ignored issues
show
Bug introduced by
The variable $upateParams does not exist. Did you mean $updateParams?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
174
        $emoji->updated_at = date('Y-m-d h:i:s');
175
        $emoji->save();
176
177
        return $response->withJson(['message' => 'Record updated successfully'], 200);
178
    }
179
180
    /**
181
     * This method updates an emoji partially.
182
     *
183
     * @param $request
184
     * @param $response
185
     *
186
     * @return json
187
     */
188
    public function updateEmojiByPatchVerb(Request $request, Response $response, $args)
189
    {
190
        $upateParams = $request->getParsedBody();
191
192
        if (is_array($upateParams)) {
193
            $emoji = Emoji::find($args['id']);
194
            if (count($emoji) > 0) {
195
                //Validate user inputs
196
                $validateResponse = $this->validateUserInput(['name'], $upateParams);
197
                if (is_array($validateResponse)) {
198
                    return $response->withJson($validateResponse, 400);
199
                }
200
201
                $emoji->name = $upateParams['name'];
202
                $emoji->updated_at = date('Y-m-d h:i:s');
203
                $emoji->save();
0 ignored issues
show
Bug introduced by
The method save does only exist in Illuminate\Database\Eloquent\Model, but not in Illuminate\Database\Eloq...ase\Eloquent\Collection.

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...
204
205
                return $response->withJson($emoji->toArray(), 200);
0 ignored issues
show
Bug introduced by
The method toArray does only exist in Illuminate\Database\Eloq...Database\Eloquent\Model, but not in Illuminate\Database\Eloquent\Builder.

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...
206
            }
207
208
            return $response->withJson([
209
                'message' => 'No record to update because the id supplied is invalid'
210
            ], 404);
211
        }
212
    }
213
214
    /**
215
     * This method deletes an emoji.
216
     *
217
     * @param $request
218
     * @param $response
219
     * @param $args
220
     *
221
     * @return json
222
     */
223
    public function deleteEmoji(Request $request, Response $response, $args)
224
    {
225
        $emoji = Emoji::find($args['id']);
226
        if (count($emoji) > 0) {
227
            $emojis = Capsule::table('emojis')
228
            ->where('id', '=', $args['id'])
229
            ->where('created_by', '=', $this->getCurrentUserId($request, $response))
230
            ->delete();
231
232
            if ($emojis) {
233
                // Delete keywords associated with the emoji
234
                Keyword::where('emoji_id', '=', $args['id'])->delete();
235
236
                return $response->withJson(['message' => 'Emoji was sucessfully deleted'], 200);
237
            }
238
239
            return $response->withJson([
240
                'message' => 'Emoji cannot be deleted because you are not the creator'
241
            ], 401);
242
        }
243
244
        return $response->withJson([
245
            'message' => 'Emoji cannot be deleted because the id supplied is invalid'
246
        ], 404);
247
    }
248
249
    /**
250
     * This method creates emoji keywords.
251
     *
252
     * @param $request
253
     * @param $response
254
     * @param $args
255
     *
256
     * @return $id
0 ignored issues
show
Documentation introduced by
The doc-type $id could not be parsed: Unknown type name "$id" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
257
     */
258 View Code Duplication
    public function createEmojiKeywords($emoji_id, $keywords)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
259
    {
260
        if ($keywords) {
261
            $splittedKeywords = explode(',', $keywords);
262
263
            $created_at = date('Y-m-d h:i:s');
264
265
            foreach ($splittedKeywords as $keyword) {
266
                $emojiKeyword = Keyword::create([
267
                        'emoji_id'     => $emoji_id,
268
                        'keyword_name' => $keyword,
269
                        'created_at'   => $created_at,
270
                ]);
271
            }
272
        }
273
274
        return $emojiKeyword->id;
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Laztopaz\EmojiRestfulAPI\Keyword>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Bug introduced by
The variable $emojiKeyword does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
275
    }
276
277
    /**
278
     * This method format emoji result.
279
     *
280
     * @param $emojis
281
     *
282
     * @return array $emojis
283
     */
284
    public function formatEmoji(array $emojis)
285
    {
286
        foreach ($emojis as $key => &$value) {
287
            $value['created_by'] = $value['created_by']['firstname'].' '.$value['created_by']['lastname'];
288
            $value['category'] = $value['category']['category_name'];
289
            $value['keywords'] = array_map(function ($key) { return $key['keyword_name']; }, $value['keywords']);
290
        }
291
292
        return $emojis;
293
    }
294
295
    /**
296
     * This method authenticate and return user id.
297
     */
298
    public function getCurrentUserId($request, $response)
299
    {
300
        $loadEnv = DatabaseConnection::loadEnv();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $loadEnv is correct as \Laztopaz\EmojiRestfulAP...seConnection::loadEnv() (which targets Laztopaz\EmojiRestfulAPI...seConnection::loadEnv()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Unused Code introduced by
$loadEnv 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...
301
302
        $jwtoken = $request->getHeader('HTTP_AUTHORIZATION');
303
304
        try {
305
            if (isset($jwtoken)) {
306
                $secretKey = base64_decode(getenv('secret'));
307
308
                $jwt = json_decode($jwtoken[0], true);
309
310
                //decode the JWT using the key from config
311
                $decodedToken = JWT::decode($jwt['jwt'], $secretKey, ['HS512']);
312
313
                $tokenInfo = (array) $decodedToken;
314
315
                $userInfo = (array) $tokenInfo['dat'];
316
317
                return $userInfo['id'];
318
            }
319
        } catch (Exception $e) {
320
            return $response->withJson(['status' => $e->getMessage()], 401);
321
        }
322
    }
323
324
    /**
325
     * This method checks for duplicate emoji.
326
     *
327
     * @param $name
328
     *
329
     * @return bool true
330
     */
331
    public function checkForDuplicateEmoji($emojiName)
332
    {
333
        if (isset($emojiName)) {
334
            $emojiFound = Capsule::table('emojis')
335
            ->where('name', '=', strtolower($emojiName))
336
            ->get();
337
338
            if (count($emojiFound) > 0) {
339
                return true;
340
            }
341
        }
342
343
        return false;
344
    }
345
346
    /**
347
     * This method will
348
     * verify the fields supplied by the user when posting to the API
349
     * and also validate their input for empty values.
350
     *
351
     * @param $expectedFields
352
     * @param $suppliedFields
353
     *
354
     * @return json response
355
     */
356
    public function validateUserInput(array $expectedFields, array $suppliedFields)
357
    {
358
        $counter = 0;
359
360
        if (count($suppliedFields) < count($expectedFields)) {
361
            return ['message' => 'All fields must be supplied'];
362
        } else { // Check whether the field supplied by the user is what we expect from them
363
            foreach ($suppliedFields as $key => $value) {
364
                if (!in_array($key, array_merge($expectedFields, ['created_at', 'updated_at', 'created_by']))) {
365
                    $counter++;
366
                }
367
            }
368
            if ($counter > 0) {
369
                $counter = 0;
0 ignored issues
show
Unused Code introduced by
$counter 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...
370
371
                return ['message' => 'Unwanted fields must be removed'];
372
            } else { // Check whether all fields have corresponding values
373
                foreach ($suppliedFields as $key => $value) {
374
                    if ($value == '') {
375
                        $counter++;
376
                    }
377
                }
378
                if ($counter > 0) {
379
                    return ['message' => 'All fields are required'];
380
                } else {
381
                    return true;
382
                }
383
            }
384
        }
385
    }
386
}
387