Completed
Push — master ( 9da9ff...cb8991 )
by Temitope
04:32
created

EmojiController::updateEmojiByPutVerb()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 28
Code Lines 16

Duplication

Lines 5
Ratio 17.86 %

Importance

Changes 14
Bugs 7 Features 1
Metric Value
c 14
b 7
f 1
dl 5
loc 28
rs 8.439
cc 5
eloc 16
nc 5
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
    /**
80
     * This method creates a new emoji.
81
     *
82
     * @param $args
83
     *
84
     * @return json $response;
85
     */
86
    public function createEmoji(Request $request, Response $response)
87
    {
88
        $requestParams = $request->getParsedBody();
89
90
        if (is_array($requestParams)) {
91
            if (!$this->checkForDuplicateEmoji($requestParams['name'])) {
92
                // Validate the user input fields
93
                $validateResponse = $this->validateUserInput(['name', 'char', 'category', 'keywords'], $requestParams);
94
95
                if (is_array($validateResponse)) {
96
                    return $response->withJson($validateResponse, 400);
97
                }
98
99
                return $this->runCreateEmoji($request, $response, $requestParams);
100
            }
101
102
            return $response->withJson(['message' => 'Emoji cannot be duplicated'], 400);
103
104
        }
105
    }
106
107
    /**
108
     * This method creates emoji and keywords associated with it.
109
     *
110
     * @param $emoji
111
     * @param $request
112
     * @param $response
113
     * @param $requestParams
114
     *
115
     * @return json response
116
     */
117
    public function runCreateEmoji($request, $response, $requestParams)
118
    {
119
        $emoji = Emoji::create([
120
            'name'       => strtolower($requestParams['name']),
121
            'char'       => $requestParams['char'],
122
            'created_at' => date('Y-m-d h:i:s'),
123
            'category'   => $requestParams['category'],
124
            'created_by' => $this->getCurrentUserId($request, $response),
125
        ]);
126
        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...
127
            $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...
128
129
            return $response->withJson($emoji->toArray(), 201);
130
131
        }
132
    }
133
134
    /**
135
     * This method updates an emoji.
136
     *
137
     * @param $request
138
     * @param $response
139
     *
140
     * @return json
141
     */
142
    public function updateEmojiByPutVerb(Request $request, Response $response, $args)
143
    {
144
        $updateParams = $request->getParsedBody();
145
146
        if (is_array($updateParams)) {
147
            $emoji = Emoji::find($args['id']);
148
149
            if (count($emoji) > 0) { // Validate the user input fields
150
                $validateResponse = $this->validateUserInput(['name', 'char', 'category'], $updateParams);
151
                if (is_array($validateResponse)) {
152
                    return $response->withJson($validateResponse, 400);
153
                }
154
155 View Code Duplication
                if (is_null($this->findTheOwner($args, $request, $response)->first())) {
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...
156
                    return $response->withJson([
157
                        'message' => 'Emoji cannot be updated because you are not the creator',
158
                    ], 401);
159
                }
160
161
                return $this->runUpdateEmoji($emoji, $response, $updateParams);
162
            }
163
164
            return $response->withJson([
165
                'message' => 'Record cannot be updated because the id supplied is invalid',
166
            ], 404);
167
            
168
        }
169
    }
170
171
    /**
172
     * This method updates an emoji.
173
     *
174
     * @param $emoji
175
     * @param $response
176
     * @param $updateParams
177
     *
178
     * @return json $response
179
     */
180
    public function runUpdateEmoji($emoji, $response, $updateParams)
181
    {
182
        $emoji->name = $updateParams['name'];
183
        $emoji->char = $updateParams['char'];
184
        $emoji->category = $updateParams['category'];
185
        $emoji->updated_at = date('Y-m-d h:i:s');
186
        $emoji->save();
187
188
        return $response->withJson(['message' => 'Record updated successfully'], 200);
189
    }
190
191
    /**
192
     * This method updates an emoji partially.
193
     *
194
     * @param $request
195
     * @param $response
196
     *
197
     * @return json
198
     */
199
    public function updateEmojiByPatchVerb(Request $request, Response $response, $args)
200
    {
201
        $upateParams = $request->getParsedBody();
202
203
        if (is_array($upateParams)) {
204
            $emoji = Emoji::find($args['id']);
205
            if (count($emoji) > 0) {
206
                //Validate user inputs
207
                $validateResponse = $this->validateUserInput(['name'], $upateParams);
208
                if (is_array($validateResponse)) {
209
                    return $response->withJson($validateResponse, 400);
210
                }
211
212 View Code Duplication
                if (is_null($this->findTheOwner($args, $request, $response)->first())) {
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...
213
                    return $response->withJson([
214
                        'message' => 'Emoji cannot be updated because you are not the creator',
215
                    ], 401);
216
                }
217
218
                $emoji->name = $upateParams['name'];
219
                $emoji->updated_at = date('Y-m-d h:i:s');
220
                $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...
221
222
                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...
223
            }
224
225
            return $response->withJson([
226
                'message' => 'No record to update because the id supplied is invalid',
227
            ], 404);
228
        }
229
    }
230
231
    /**
232
     * This method deletes an emoji.
233
     *
234
     * @param $request
235
     * @param $response
236
     * @param $args
237
     *
238
     * @return json
239
     */
240
    public function deleteEmoji(Request $request, Response $response, $args)
241
    {
242
        $emoji = Emoji::find($args['id']);
243
        if (count($emoji) > 0) {
244
            $emojis = $this->findTheOwner($args, $request, $response);
245
246
            if (! is_null($emojis)) {
247
                $emojis->delete();
248
            }
249
250
            if ($emojis) {
251
                // Delete keywords associated with the emoji
252
                Keyword::where('emoji_id', '=', $args['id'])->delete();
253
254
                return $response->withJson(['message' => 'Emoji was sucessfully deleted'], 200);
255
            }
256
257
            return $response->withJson([
258
                'message' => 'Emoji cannot be deleted because you are not the creator',
259
            ], 401);
260
        }
261
262
        return $response->withJson([
263
            'message' => 'Emoji cannot be deleted because the id supplied is invalid',
264
        ], 404);
265
    }
266
267
    /**
268
     * This method creates emoji keywords.
269
     *
270
     * @param $request
271
     * @param $response
272
     * @param $args
273
     *
274
     * @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...
275
     */
276 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...
277
    {
278
        if ($keywords) {
279
            $splittedKeywords = explode(',', $keywords);
280
281
            $created_at = date('Y-m-d h:i:s');
282
283
            foreach ($splittedKeywords as $keyword) {
284
                $emojiKeyword = Keyword::create([
285
                        'emoji_id'     => $emoji_id,
286
                        'keyword_name' => $keyword,
287
                        'created_at'   => $created_at,
288
                ]);
289
            }
290
        }
291
292
        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...
293
    }
294
295
    /**
296
     * This method format emoji result.
297
     *
298
     * @param $emojis
299
     *
300
     * @return array $emojis
301
     */
302
    public function formatEmoji(array $emojis)
303
    {
304
        foreach ($emojis as $key => &$value) {
305
            $value['created_by'] = $value['created_by']['firstname'].' '.$value['created_by']['lastname'];
306
            $value['category'] = $value['category']['category_name'];
307
            $value['keywords'] = array_map(function ($key) { return $key['keyword_name']; }, $value['keywords']);
308
        }
309
310
        return $emojis;
311
    }
312
313
    /**
314
     * This method authenticate and return user id.
315
     */
316
    public function getCurrentUserId($request, $response)
317
    {
318
        $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...
319
320
        $jwtoken = $request->getHeader('HTTP_AUTHORIZATION');
321
322
        try {
323
            if (isset($jwtoken)) {
324
                $secretKey = base64_decode(getenv('secret'));
325
326
                $jwt = json_decode($jwtoken[0], true);
327
328
                //decode the JWT using the key from config
329
                $decodedToken = JWT::decode($jwt['jwt'], $secretKey, ['HS512']);
330
331
                $tokenInfo = (array) $decodedToken;
332
333
                $userInfo = (array) $tokenInfo['dat'];
334
335
                return $userInfo['id'];
336
            }
337
        } catch (Exception $e) {
338
            return $response->withJson(['status' => $e->getMessage()], 401);
339
        }
340
    }
341
342
    /**
343
     * This method checks for duplicate emoji.
344
     *
345
     * @param $name
346
     *
347
     * @return bool true
348
     */
349
    public function checkForDuplicateEmoji($emojiName)
350
    {
351
        if (isset($emojiName)) {
352
            $emojiFound = Capsule::table('emojis')
353
            ->where('name', '=', strtolower($emojiName))
354
            ->get();
355
356
            if (count($emojiFound) > 0) {
357
                return true;
358
            }
359
        }
360
361
        return false;
362
    }
363
364
    /**
365
     * This method solves for rightful of a record
366
     */
367
    public function findTheOwner($args, $request, $response)
368
    {
369
        return Capsule::table('emojis')
370
        ->where('id', '=', $args['id'])
371
        ->where('created_by', '=', $this->getCurrentUserId($request, $response));
372
    }
373
374
    /**
375
     * This method will
376
     * verify the fields supplied by the user when posting to the API
377
     * and also validate their input for empty values.
378
     *
379
     * @param $expectedFields
380
     * @param $suppliedFields
381
     *
382
     * @return json response
383
     */
384
    public function validateUserInput(array $expectedFields, array $suppliedFields)
385
    {
386
        $counter = 0;
387
388
        if (count($suppliedFields) < count($expectedFields)) {
389
            return ['message' => 'All fields must be supplied'];
390
        } else { // Check whether the field supplied by the user is what we expect from them
391
            foreach ($suppliedFields as $key => $value) {
392
                if (!in_array($key, array_merge($expectedFields, ['created_at', 'updated_at', 'created_by']))) {
393
                    $counter++;
394
                }
395
            }
396
            if ($counter > 0) {
397
                $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...
398
399
                return ['message' => 'Unwanted fields must be removed'];
400
            } else { // Check whether all fields have corresponding values
401
                foreach ($suppliedFields as $key => $value) {
402
                    if ($value == '') {
403
                        $counter++;
404
                    }
405
                }
406
                if ($counter > 0) {
407
                    return ['message' => 'All fields are required'];
408
                } else {
409
                    return true;
410
                }
411
            }
412
        }
413
    }
414
}
415