Passed
Push — master ( 7c51ba...a22fab )
by Peter
04:20
created

Create::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 20
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Admin\Console\Commands\ApiClient;
6
7
use AbterPhp\Admin\Domain\Entities\ApiClient;
8
use AbterPhp\Admin\Orm\AdminResourceRepo;
9
use AbterPhp\Admin\Orm\ApiClientRepo;
10
use AbterPhp\Admin\Orm\UserRepo;
11
use AbterPhp\Framework\Authorization\CacheManager;
12
use AbterPhp\Framework\Crypto\Crypto;
13
use Hackzilla\PasswordGenerator\Generator\ComputerPasswordGenerator as PasswordGenerator;
0 ignored issues
show
Bug introduced by
The type Hackzilla\PasswordGenera...mputerPasswordGenerator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use Opulence\Console\Commands\Command;
15
use Opulence\Console\Requests\Argument;
16
use Opulence\Console\Requests\ArgumentTypes;
17
use Opulence\Console\Requests\Option;
18
use Opulence\Console\Requests\OptionTypes;
19
use Opulence\Console\Responses\IResponse;
20
use Opulence\Orm\IUnitOfWork;
21
use ZxcvbnPhp\Zxcvbn;
22
23
class Create extends Command
24
{
25
    const COMMAND_NAME            = 'apiclient:create';
26
    const COMMAND_DESCRIPTION     = 'Creates a new API client';
27
    const COMMAND_SUCCESS         = '<success>New API client is created. ID: <b>%s</b></success>';
28
    const COMMAND_DRY_RUN_MESSAGE = '<info>Dry run prevented creating new API client.</info>';
29
30
    const ARGUMENT_USER        = 'user';
31
    const ARGUMENT_DESCRIPTION = 'description';
32
    const ARGUMENT_RESOURCES   = 'resources';
33
34
    const OPTION_DRY_RUN    = 'dry-run';
35
    const SHORTENED_DRY_RUN = 'd';
36
37
    const RESPONSE_SECRET = '<info>Secret generated: <b>%s</b></info>';
38
39
    /** @var UserRepo */
40
    protected $userRepo;
41
42
    /** @var AdminResourceRepo */
43
    protected $adminResourceRepo;
44
45
    /** @var ApiClientRepo */
46
    protected $apiClientRepo;
47
48
    /** @var PasswordGenerator */
49
    protected $passwordGenerator;
50
51
    /** @var Crypto */
52
    protected $crypto;
53
54
    /** @var IUnitOfWork */
55
    protected $unitOfWork;
56
57
    /** @var CacheManager */
58
    protected $cacheManager;
59
60
    /** @var Zxcvbn */
61
    protected $zxcvbn;
62
63
    /**
64
     * Create constructor.
65
     *
66
     * @param UserRepo          $userRepo
67
     * @param AdminResourceRepo $adminResourceRepo
68
     * @param ApiClientRepo     $apiClientRepo
69
     * @param PasswordGenerator $passwordGenerator
70
     * @param Crypto            $crypto
71
     * @param IUnitOfWork       $unitOfWork
72
     * @param CacheManager      $cacheManager
73
     * @param Zxcvbn            $zxcvbn
74
     */
75
    public function __construct(
76
        UserRepo $userRepo,
77
        AdminResourceRepo $adminResourceRepo,
78
        ApiClientRepo $apiClientRepo,
79
        PasswordGenerator $passwordGenerator,
80
        Crypto $crypto,
81
        IUnitOfWork $unitOfWork,
82
        CacheManager $cacheManager,
83
        Zxcvbn $zxcvbn
84
    ) {
85
        $this->userRepo          = $userRepo;
86
        $this->adminResourceRepo = $adminResourceRepo;
87
        $this->apiClientRepo     = $apiClientRepo;
88
        $this->passwordGenerator = $passwordGenerator;
89
        $this->crypto            = $crypto;
90
        $this->unitOfWork        = $unitOfWork;
91
        $this->cacheManager      = $cacheManager;
92
        $this->zxcvbn            = $zxcvbn;
93
94
        parent::__construct();
95
    }
96
97
    /**
98
     * @inheritdoc
99
     */
100
    protected function define()
101
    {
102
        $this->setName(static::COMMAND_NAME)
103
            ->setDescription(static::COMMAND_DESCRIPTION)
104
            ->addArgument(
105
                new Argument(
106
                    static::ARGUMENT_USER,
107
                    ArgumentTypes::REQUIRED,
108
                    'User Identifier (Email or Username)'
109
                )
110
            )
111
            ->addArgument(
112
                new Argument(
113
                    static::ARGUMENT_DESCRIPTION,
114
                    ArgumentTypes::REQUIRED,
115
                    'Description'
116
                )
117
            )
118
            ->addArgument(
119
                new Argument(
120
                    static::ARGUMENT_RESOURCES,
121
                    ArgumentTypes::REQUIRED,
122
                    'Resources (Comma separated list)'
123
                )
124
            )
125
            ->addOption(
126
                new Option(
127
                    static::OPTION_DRY_RUN,
128
                    static::SHORTENED_DRY_RUN,
129
                    OptionTypes::OPTIONAL_VALUE,
130
                    'Dry run (default: 0)',
131
                    '0'
132
                )
133
            );
134
    }
135
136
    /**
137
     * @inheritdoc
138
     */
139
    protected function doExecute(IResponse $response)
140
    {
141
        $userIdentifier = $this->getArgumentValue(static::ARGUMENT_USER);
142
143
        try {
144
            $user = $this->userRepo->find($userIdentifier);
145
            if (!$user) {
146
                throw new \RuntimeException();
147
            }
148
149
            $adminResources = $this->getAdminResources($user->getId());
150
151
            $rawSecret        = $this->passwordGenerator->generatePassword();
152
            $preparedPassword = $this->crypto->prepareSecret($rawSecret);
153
            $packedPassword   = $this->crypto->hashCrypt($preparedPassword);
154
155
            $apiClient = $this->getApiClient($user->getId(), $packedPassword, $adminResources);
156
157
            $this->apiClientRepo->add($apiClient);
158
        } catch (\Exception $e) {
159
            if ($e->getPrevious()) {
160
                $response->writeln(sprintf('<error>%s</error>', $e->getPrevious()->getMessage()));
161
            }
162
            $response->writeln(sprintf('<fatal>%s</fatal>', $e->getMessage()));
163
164
            return;
165
        }
166
167
168
        $dryRun = (bool)$this->getOptionValue(static::OPTION_DRY_RUN);
169
        if ($dryRun) {
170
            $this->unitOfWork->dispose();
171
            $response->writeln(static::COMMAND_DRY_RUN_MESSAGE);
172
173
            return;
174
        }
175
176
        try {
177
            $this->unitOfWork->commit();
178
            $this->cacheManager->clearAll();
179
        } catch (\Exception $e) {
180
            if ($e->getPrevious()) {
181
                $response->writeln(sprintf('<error>%s</error>', $e->getPrevious()->getMessage()));
182
            }
183
            $response->writeln(sprintf('<fatal>%s</fatal>', $e->getMessage()));
184
185
            return;
186
        }
187
188
        $response->writeln(sprintf(static::RESPONSE_SECRET, $rawSecret));
189
        $response->writeln(sprintf(static::COMMAND_SUCCESS, $apiClient->getId()));
190
    }
191
192
    /**
193
     * @param string          $userId
194
     * @param string          $packedPassword
195
     * @param AdminResource[] $adminResources
196
     *
197
     * @return ApiClient
198
     * @throws \Opulence\Orm\OrmException
199
     * @throws \RuntimeException
200
     */
201
    protected function getApiClient(string $userId, string $packedPassword, array $adminResources): ApiClient
202
    {
203
        $description = $this->getArgumentValue(static::ARGUMENT_DESCRIPTION);
204
        $resources   = $this->getArgumentValue(static::ARGUMENT_RESOURCES);
0 ignored issues
show
Unused Code introduced by
The assignment to $resources is dead and can be removed.
Loading history...
205
206
        return new ApiClient(
207
            '',
208
            $userId,
209
            $description,
210
            $packedPassword,
211
            $adminResources
212
        );
213
    }
214
215
    /**
216
     * @param string $userId
217
     *
218
     * @return AdminResource[]
219
     */
220
    protected function getAdminResources(string $userId): array
221
    {
222
        $resources = explode(',', $this->getArgumentValue(static::ARGUMENT_RESOURCES));
223
        if (!$resources) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $resources of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
224
            return [];
225
        }
226
227
        $adminResources = [];
228
        foreach ($this->adminResourceRepo->getByUserId($userId) as $adminResource) {
229
            if (!in_array($adminResource->getIdentifier(), $resources, true)) {
230
                continue;
231
            }
232
233
            $adminResources[] = $adminResource;
234
        }
235
236
        if (count($resources) != count($adminResources)) {
237
            throw new \RuntimeException('User does not have all requested resources');
238
        }
239
240
        return $adminResources;
241
    }
242
}
243