Completed
Push — master ( 1d153d...c087ad )
by Benedikt
03:23
created

UserController   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 0
loc 162
rs 10
c 0
b 0
f 0
wmc 12
lcom 1
cbo 6

10 Methods

Rating   Name   Duplication   Size   Complexity  
B login() 0 25 3
A register() 0 23 1
A newUser() 0 4 1
A getRegisterResponse() 0 6 1
A userId() 0 5 1
A addAdditionalLoginSpecifications() 0 4 1
A addAdditionalRegisterSpecifications() 0 4 1
A createAdditionalRegisterEntities() 0 4 1
A getLoginResponse() 0 5 1
A getCredentialSpecification() 0 11 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Tfboe\FmLib\Http\Controllers;
5
6
use Illuminate\Contracts\Hashing\Hasher;
7
use Illuminate\Http\JsonResponse;
8
use Illuminate\Http\Request;
9
use Illuminate\Support\Facades\Auth;
10
use Laravel\Lumen\Application;
11
use Tfboe\FmLib\Entity\User;
12
use Tfboe\FmLib\Exceptions\AuthenticationException;
13
use Tymon\JWTAuth\Exceptions\JWTException;
14
15
/**
16
 * Class UserController
17
 * @package App\Http\Controllers
18
 */
19
class UserController extends BaseController
20
{
21
//<editor-fold desc="Public Methods">
22
  /**
23
   * login action, checks credentials and returns token
24
   * @param Request $request the http request
25
   * @param Application $app
26
   * @return JsonResponse
27
   * @throws AuthenticationException wrong credentials or errors during creating a token
28
   */
29
  public function login(Request $request, Application $app): JsonResponse
30
  {
31
    $specification = $this->getCredentialSpecification($app);
32
    $this->addAdditionalLoginSpecifications($specification);
33
    $this->validateBySpecification($request, $specification);
34
35
36
    // grab credentials from the request
37
    $credentials = $request->only('email', 'password');
38
39
    /** @var string $token */
40
    $token = null;
41
    try {
42
      // attempt to verify the credentials and create a token for the user
43
      $token = Auth::attempt($credentials);
44
      if (!$token) {
45
        throw new AuthenticationException('invalid credentials');
46
      }
47
    } /** @noinspection PhpRedundantCatchClauseInspection */ catch (JWTException $e) {
48
      // something went wrong whilst attempting to encode the token
49
      throw new AuthenticationException('could not create token');
50
    }
51
    return $this->getLoginResponse($request, $token);
0 ignored issues
show
Documentation introduced by
$token is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
52
53
  }
54
55
  /**
56
   * register action, registers a new user with email and password
57
   *
58
   * @param Request $request the http request
59
   * @param Application $app
60
   * @return JsonResponse
61
   */
62
  public function register(Request $request, Application $app): JsonResponse
63
  {
64
    $specification = [];
65
    $specification['user'] = $this->getCredentialSpecification($app);
66
    $specification['user']['email']['validation'] .= '|unique:Tfboe\FmLib\Entity\User,email';
67
    $specification['user']['confirmedAGBVersion'] = ['validation' => 'integer|min:0'];
68
69
    $this->addAdditionalRegisterSpecifications($specification);
70
71
    $this->validateBySpecification($request, array_merge(...array_values($specification)));
72
73
    $input = $request->input();
74
    /** @var User $user */
75
76
    $user = $this->setFromSpecification($this->newUser(), $specification['user'], $input);
0 ignored issues
show
Bug introduced by
It seems like $input defined by $request->input() on line 73 can also be of type string; however, Tfboe\FmLib\Http\Control...:setFromSpecification() does only seem to accept array, 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...
77
    $this->getEntityManager()->persist($user); //sets the user id
78
79
    $this->createAdditionalRegisterEntities($user, $specification, $input);
0 ignored issues
show
Bug introduced by
It seems like $input defined by $request->input() on line 73 can also be of type string; however, Tfboe\FmLib\Http\Control...ionalRegisterEntities() does only seem to accept array, 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...
80
81
    $this->getEntityManager()->flush();
82
83
    return $this->getRegisterResponse($request, $app, $user);
84
  }
85
86
  /**
87
   * Creates a new user
88
   * @return User
89
   */
90
  protected function newUser(): User
91
  {
92
    return new User();
93
  }
94
95
  /**
96
   * Gets the response for a successful register action
97
   * @param Request $request the request
98
   * @param Application $app the application
99
   * @param User $user the newly registered user
100
   * @return JsonResponse the json response
101
   */
102
  protected function getRegisterResponse(/** @noinspection PhpUnusedParameterInspection */
103
    Request $request, /** @noinspection PhpUnusedParameterInspection */
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...
104
    Application $app, User $user)
0 ignored issues
show
Unused Code introduced by
The parameter $app 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...
105
  {
106
    return response()->json(['id' => $user->getId()]);
0 ignored issues
show
Bug introduced by
The method json does only exist in Laravel\Lumen\Http\ResponseFactory, but not in Illuminate\Http\Response.

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...
107
  }
108
109
  /**
110
   * @return JsonResponse
111
   */
112
  public function userId(): JsonResponse
113
  {
114
    /** @noinspection PhpUnhandledExceptionInspection */
115
    return response()->json(['id' => Auth::user()->getAuthIdentifier()]);
0 ignored issues
show
Bug introduced by
The method json does only exist in Laravel\Lumen\Http\ResponseFactory, but not in Illuminate\Http\Response.

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...
116
  }
117
//</editor-fold desc="Public Methods">
118
119
//<editor-fold desc="Protected Methods">
120
  /**
121
   * Gets additional input specifications for the login action
122
   * @param array $specification the specification to add to / modify
123
   */
124
  protected function addAdditionalLoginSpecifications(array &$specification)
0 ignored issues
show
Unused Code introduced by
The parameter $specification 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...
125
  {
126
    //do nothing by default
127
  }
128
129
  /**
130
   * adds additional register specifications
131
   * @param array $specification the specification to add to / modify
132
   */
133
  protected function addAdditionalRegisterSpecifications(array &$specification)
0 ignored issues
show
Unused Code introduced by
The parameter $specification 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...
134
  {
135
    //do nothing by default
136
  }
137
138
  /**
139
   * creates additional entities after registration using the specification and the given input
140
   * @param User $user the newly registered user
141
   * @param array $specification the specification
142
   * @param array $input the given request input
143
   */
144
  protected function createAdditionalRegisterEntities(User $user, array $specification, array $input)
0 ignored issues
show
Unused Code introduced by
The parameter $user 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...
Unused Code introduced by
The parameter $specification 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...
Unused Code introduced by
The parameter $input 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...
145
  {
146
    //do nothing by default
147
  }
148
149
  /**
150
   * Gets the response for a successful login action
151
   * @param Request $request the request
152
   * @param string $token the login token
153
   * @return JsonResponse the response
154
   */
155
  protected function getLoginResponse(Request $request, string $token): JsonResponse
156
  {
157
    $user = $request->user();
158
    return response()->json(['id' => $user->getId()], 200, ['jwt-token' => $token]);
0 ignored issues
show
Bug introduced by
The method json does only exist in Laravel\Lumen\Http\ResponseFactory, but not in Illuminate\Http\Response.

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...
159
  }
160
//</editor-fold desc="Protected Methods">
161
162
//<editor-fold desc="Private Methods">
163
  /**
164
   * Gets the specification for the login credentials
165
   * @param Application $app
166
   * @return array
167
   */
168
  private function getCredentialSpecification(Application $app)
169
  {
170
    /** @var Hasher $hasher */
171
    return [
172
      'email' => ['validation' => 'required|email'],
173
      'password' => ['validation' => 'required|string|min:8',
174
        'transformer' => function ($value) use ($app) {
175
          return $app['hash']->make($value);
176
        }]
177
    ];
178
  }
179
//</editor-fold desc="Private Methods">
180
}
181