Completed
Push — master ( 67e459...845662 )
by Temitope
02:31
created

EmojiController::createEmojiKeywords()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 18
Ratio 100 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
c 4
b 2
f 0
dl 18
loc 18
rs 9.4285
cc 3
eloc 10
nc 2
nop 2
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 Psr\Http\Message\ResponseInterface as Response;
11
use Psr\Http\Message\ServerRequestInterface as Request;
12
use Illuminate\Database\Capsule\Manager as Capsule;
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(['status'], 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
            $created_at = date('Y-m-d h:i:s');
91
92
            $userId = $this->getCurrentUserId($request, $response);
93
94
            if (! $this->checkForDuplicateEmoji($requestParams['name'])) {
95
                // Validate the user input fields
96
                $validateResponse = $this->validateUserInput([
97
                    'name', 
98
                    'char', 
99
                    'category', 
100
                    'keywords'
101
                ], $requestParams);
102
103
                if (is_array($validateResponse)) {
104
                    return $response->withJson($validateResponse, 400);
105
                }
106
107
                $emojiKeyword = $requestParams['keywords'];
108
109
                $emoji = Emoji::create(
110
                [
111
                    'name'       => strtolower($requestParams['name']),
112
                    'char'       => $requestParams['char'],
113
                    'created_at' => $created_at,
114
                    'category'   => $requestParams['category'],
115
                    'created_by' => $userId,
116
                ]);
117
118
                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...
119
                    $createdKeyword = $this->createEmojiKeywords($emoji->id, $emojiKeyword);
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...
120
121
                    return $response->withJson($emoji->toArray(), 201);
122
                }
123
            }
124
125
            return $response->withJson(['message' => 'Emoji cannot be duplicated'], 400);
126
        }
127
    }
128
129
    /**
130
     * This method updates an emoji.
131
     *
132
     * @param $request
133
     * @param $response
134
     *
135
     * @return json
136
     */
137
    public function updateEmojiByPutVerb(Request $request, Response $response, $args)
138
    {
139
        $upateParams = $request->getParsedBody();
140
141
        if (is_array($upateParams)) {
142
143
            $emoji = Emoji::find($args['id']);
144
145
            if (count($emoji) > 0) {
146
                // Validate the user input fields
147
                $validateResponse =  $this->validateUserInput([
148
                    'name', 
149
                    'char', 
150
                    'category'
151
                ], $requestParams);
0 ignored issues
show
Bug introduced by
The variable $requestParams does not exist. Did you mean $request?

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
                if (is_array($validateResponse)) {
154
                    return $response->withJson($validateResponse, 400);
155
                }
156
157
                $emoji->name = $upateParams['name'];
158
                $emoji->char = $upateParams['char'];
159
                $emoji->category = $upateParams['category'];
160
                $emoji->updated_at = date('Y-m-d h:i:s');
161
                $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...
162
163
                return $response->withJson(['message' => 'Record updated successfully'], 200);
164
            }
165
166
            return $response->withJson(['message' => 'Record cannot be updated because the id supplied is invalid'], 404);
167
        }
168
    }
169
170
    /**
171
     * This method updates an emoji partially.
172
     *
173
     * @param $request
174
     * @param $response
175
     *
176
     * @return json
177
     */
178
    public function updateEmojiByPatchVerb(Request $request, Response $response, $args)
179
    {
180
        $upateParams = $request->getParsedBody();
181
182
        if (is_array($upateParams)) {
183
            $emoji = Emoji::find($args['id']);
184
185
            if (count($emoji) > 0) {
186
                //Validate user inputs 
187
                $validateResponse = $this->validateUserInput(['name'], $requestParams);
0 ignored issues
show
Bug introduced by
The variable $requestParams does not exist. Did you mean $request?

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...
188
                if (is_array($validateResponse)) {
189
                    return $response->withJson($validateResponse, 400);
190
                }
191
192
                $emoji->name = $upateParams['name'];
193
                $emoji->updated_at = date('Y-m-d h:i:s');
194
                $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...
195
196
                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...
197
            }
198
199
            return $response->withJson(['message' => 'No record to update because the id supplied is invalid'], 404);
200
        }
201
    }
202
203
    /**
204
     * This method deletes an emoji.
205
     *
206
     * @param $request
207
     * @param $response
208
     * @param $args
209
     *
210
     * @return json
211
     */
212
    public function deleteEmoji(Request $request, Response $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $request 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...
213
    {
214
        $emoji = Emoji::find($args['id']);
215
        if (count($emoji) > 0) {
216
            $emoji->delete();
0 ignored issues
show
Bug introduced by
The method delete does only exist in Illuminate\Database\Eloq...Database\Eloquent\Model, but not in Illuminate\Database\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...
217
            // Delete keywords associated with the emoji
218
            Keyword::where('emoji_id', '=', $args['id'])->delete();
219
220
            return $response->withJson(['message' => 'Emoji was sucessfully deleted'], 200);
221
        }
222
223
        return $response->withJson(['message' => 'Emoji cannot be deleted because the id supplied is invalid'], 404);
224
    }
225
226
    /**
227
     * This method creates emoji keywords.
228
     *
229
     * @param $request
230
     * @param $response
231
     * @param $args
232
     *
233
     * @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...
234
     */
235 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...
236
    {
237
        if ($keywords) {
238
            $splittedKeywords = explode(',', $keywords);
239
240
            $created_at = date('Y-m-d h:i:s');
241
242
            foreach ($splittedKeywords as $keyword) {
243
                $emojiKeyword = Keyword::create([
244
                        'emoji_id'     => $emoji_id,
245
                        'keyword_name' => $keyword,
246
                        'created_at'   => $created_at,
247
                ]);
248
            }
249
        }
250
251
        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...
252
    }
253
254
    /**
255
     * This method format emoji result
256
     *
257
     * @param $emojis
258
     *
259
     * @return array $emojis
260
     */
261
    public function formatEmoji(array $emojis)
262
    {
263
        foreach ($emojis as $key => &$value) {
264
            $value['created_by'] = $value['created_by']['firstname'].' '.$value['created_by']['lastname'];
265
            $value['category'] = $value['category']['category_name'];
266
            $value['keywords'] = array_map(function ($key) { return $key['keyword_name']; }, $value['keywords']);
267
        }
268
269
        return $emojis;
270
    }
271
272
    /**
273
     * This method authenticate and return user id.
274
     */
275
    public function getCurrentUserId($request, $response)
276
    {
277
        $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...
278
279
        $jwtoken = $request->getHeader('HTTP_AUTHORIZATION');
280
281
        try {
282
            if (isset($jwtoken)) {
283
                $secretKey = base64_decode(getenv('secret'));
284
285
                $jwt = json_decode($jwtoken[0], true);
286
287
                //decode the JWT using the key from config
288
                $decodedToken = JWT::decode($jwt['jwt'], $secretKey, ['HS512']);
289
290
                $tokenInfo = (array) $decodedToken;
291
292
                $userInfo = (array) $tokenInfo['dat'];
293
294
                return $userInfo['id'];
295
            }
296
        } catch (Exception $e) {
297
            return $response->withJson(['status' => $e->getMessage()], 401);
298
        }
299
    }
300
301
    /**
302
     * This method checks for duplicate emoji
303
     *
304
     * @param $name
305
     *
306
     * @return boolean true
307
     */
308
    public function checkForDuplicateEmoji($emojiName)
309
    {
310
        if (isset($emojiName)) {
311
            $emojiFound = Capsule::table('emojis')
312
            ->where('name', '=', strtoupper($emojiName))
313
            ->orWhere('name', '=', strtolower($emojiName))
314
            ->orWhere('name', '=', ucwords($emojiName))
315
            ->orWhere('name', '=', $emojiName)
316
            ->get();
317
            
318
            if (count($emojiFound) > 0) {
319
                return true;
320
            }
321
        }
322
        return false;
323
    }
324
325
    /**
326
     * This method will
327
     * verify the fields supplied by the user when posting to the API
328
     * and also validate their input for empty values
329
     *
330
     * @param $expectedFields
331
     * @param $suppliedFields
332
     * 
333
     * @return json response
334
     */
335
    public function validateUserInput(array $expectedFields, array $suppliedFields)
336
    {
337
        $counter = 0;
338
339
        if (count($suppliedFields) < count($expectedFields)) {
340
            return ['message' => 'All fields must be supplied'];
341
342
        } else { // Check whether the field supplied by the user is what we expect from them
343
            foreach ($suppliedFields as $key => $value) {
344
                if (! in_array($key, $expectedFields)) {
345
                    $counter++;
346
                }
347
            }
348
            if ($counter > 0) {
349
                $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...
350
                return ['message' => 'Unwanted fields must be removed'];
351
352
            } else { // Check whether all fields have corresponding values
353
                foreach ($suppliedFields as $key => $value) {
354
                    if ($value == "") {
355
                        $counter++;
356
                    }
357
                }
358
                if ($counter > 0) {
359
                    return ['message' => 'All fields are required'];
360
361
                } else {
362
                    return true;
363
364
                }
365
            }
366
        }
367
    }
368
369
}
370