BoneUserApiController::uploadAvatarAction()   B
last analyzed

Complexity

Conditions 5
Paths 35

Size

Total Lines 59
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 39
c 1
b 0
f 0
dl 0
loc 59
ccs 40
cts 40
cp 1
rs 8.9848
cc 5
nc 35
nop 1
crap 5

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Bone\User\Controller;
6
7
use Bone\Http\Response;
8
use Bone\Http\Response\HtmlResponse;
9
use Bone\I18n\I18nAwareInterface;
10
use Bone\I18n\Traits\HasTranslatorTrait;
11
use Bone\Mail\EmailMessage;
12
use Bone\Server\SiteConfig;
13
use Bone\User\Form\RegistrationForm;
14
use DateTime;
15
use Del\Entity\Country;
16
use Del\Exception\UserException;
17
use Del\Factory\CountryFactory;
18
use Del\Form\Form;
19
use Exception;
20
use Bone\Controller\Controller;
21
use Bone\Mail\Service\MailService;
22
use Bone\User\Form\PersonForm;
23
use Del\Entity\User;
24
use Del\Form\Field\FileUpload;
25
use Del\Image;
26
use Del\Service\UserService;
27
use Laminas\Diactoros\Stream;
28
use Psr\Http\Message\ResponseInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use Laminas\Diactoros\Response\JsonResponse;
31
32
class BoneUserApiController extends Controller
33
{
34
    /** @var UserService $userService */
35
    private $userService;
36
37
    /** @var string $uploadsDirectory */
38
    private $uploadsDirectory;
39
40
    /** @var string $tempDirectory */
41
    private $tempDirectory;
42
43
    /** @var string $imgDirectory */
44
    private $imgDirectory;
45
46
    /** @var MailService $mailService */
47
    private $mailService;
48
49
    /**
50
     * BoneUserController constructor.
51
     * @param UserService $userService
52
     */
53 8
    public function __construct(UserService $userService, string $uploadsDirectory, string $imgSubDir, string $tempDirectory, MailService $mailService)
54
    {
55 8
        $this->userService = $userService;
56 8
        $this->uploadsDirectory = $uploadsDirectory;
57 8
        $this->tempDirectory = $tempDirectory;
58 8
        $this->imgDirectory = $imgSubDir;
59 8
        $this->mailService = $mailService;
60
    }
61
62
    /**
63
     * @param ServerRequestInterface $request
64
     * @param array $args
65
     * @return ResponseInterface
66
     */
67 1
    public function chooseAvatarAction(ServerRequestInterface $request): ResponseInterface
68
    {
69 1
        $avatar = $request->getParsedBody()['avatar'];
70
        /** @var User $user */
71 1
        $user = $request->getAttribute('user');
72 1
        $person = $user->getPerson();
73 1
        $image = new Image('public' . $avatar);
74 1
        $avatar = str_replace('/bone-user/img/avatars/', '', $avatar);
75 1
        $file = $this->imgDirectory . $this->getFilename($avatar);
76 1
        $image->save($this->uploadsDirectory . $file);
77 1
        $person->setImage($file);
78 1
        $this->userService->getPersonSvc()->savePerson($person);
0 ignored issues
show
Deprecated Code introduced by
The function Del\Service\UserService::getPersonSvc() has been deprecated: use getPersonService() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

78
        /** @scrutinizer ignore-deprecated */ $this->userService->getPersonSvc()->savePerson($person);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
79
80 1
        return new JsonResponse([
81 1
            'result' => 'success',
82 1
            'message' => 'Avatar is now set to ' . $avatar . '.',
83 1
            'avatar' => $avatar,
84 1
        ]);
85
    }
86
87
    /**
88
     * @param ServerRequestInterface $request
89
     * @param array $args
90
     * @return ResponseInterface
91
     */
92 5
    public function uploadAvatarAction(ServerRequestInterface $request): ResponseInterface
93
    {
94 5
        $data = $request->getParsedBody();
95 5
        $form = new Form('upload');
96 5
        $file = new FileUpload('avatar');
97 5
        $file->setUploadDirectory($this->tempDirectory);
98 5
        $file->setRequired(true);
99 5
        $form->addField($file);
100
101 5
        if ($form->isValid($data)) {
0 ignored issues
show
Unused Code introduced by
The call to Del\Form\AbstractForm::isValid() has too many arguments starting with $data. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
        if ($form->/** @scrutinizer ignore-call */ isValid($data)) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
102
103
            try {
104 4
                $data = $form->getValues();
105 4
                $file = $data['avatar'];
106 4
                $sourceFileName = $this->tempDirectory . $file;
107 4
                $newFileName = $this->imgDirectory . $this->getFilename($file);
108 4
                $destinationFileName = $this->uploadsDirectory . $newFileName;
109 4
                $image = new Image($sourceFileName);
110
111 4
                if ($image->getHeight() > $image->getWidth()) { //portrait
112
113 1
                    $image->resizeToWidth(100);
114 1
                    $image->crop(100, 100);
115
116 3
                } elseif ($image->getHeight() < $image->getWidth()) { //landscape
117
118 1
                    $image->resizeToHeight(100);
119 1
                    $image->crop(100, 100);
120
121
                } else { //square
122
123 2
                    $image->resize(100, 100);
124
125
                }
126 4
                $image->save($destinationFileName, 0775);
127 4
                unlink($sourceFileName);
128
129
                /** @var User $user */
130 4
                $user = $request->getAttribute('user');
131 4
                $person = $user->getPerson();
132 4
                $person->setImage($newFileName);
133 3
                $this->userService->getPersonSvc()->savePerson($person);
0 ignored issues
show
Deprecated Code introduced by
The function Del\Service\UserService::getPersonSvc() has been deprecated: use getPersonService() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

133
                /** @scrutinizer ignore-deprecated */ $this->userService->getPersonSvc()->savePerson($person);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
134
135 3
                return new JsonResponse([
136 3
                    'result' => 'success',
137 3
                    'message' => 'Avatar now set to ' . $person->getImage(),
138 3
                    'avatar' => $person->getImage(),
139 3
                ]);
140 1
            } catch (Exception $e) {
141 1
                return new JsonResponse([
142 1
                    'result' => 'danger',
143 1
                    'message' => $e->getMessage(),
144 1
                ]);
145
            }
146
        }
147
148 1
        return new JsonResponse([
149 1
            'result' => 'danger',
150 1
            'message' => 'There was a problem with your upload.',
151 1
        ]);
152
    }
153
154
    /**
155
     * @param string $fileNameAsUploaded
156
     * @return string
157
     */
158 5
    private function getFilename(string $fileNameAsUploaded)
159
    {
160
        // break the filename up on dots
161 5
        $filenameParts = explode('.', $fileNameAsUploaded);
162
163
        // Create an array of encoded parts
164 5
        $encoded = [];
165
166
        // Loop through each part
167 5
        foreach ($filenameParts as $filenamePart) {
168
            // Url encode the filename part
169 5
            $encoded[] = urlencode($filenamePart);
170
        }
171
172
        // Create a little uniqueness, in case they upload a file with the same name
173 5
        $unique = dechex(time());
174
175
        // Pop off the last part (file extension)
176 5
        $ext = array_pop($encoded);
177
178
        // Push on the unique part
179 5
        $encoded[] = $unique;
180
181
        // Piece the encoded filename together
182 5
        $filenameOnDisk = implode('_', $encoded);
183
184
        // Add the extension
185 5
        $filenameOnDisk .= '.' . $ext;
186
187 5
        return $filenameOnDisk;
188
    }
189
190
    /**
191
     * @param ServerRequestInterface $request
192
     * @return ResponseInterface
193
     * @throws ControllerException
194
     */
195 1
    public function avatar(ServerRequestInterface $request): ResponseInterface
196
    {
197 1
        $response = new Response();
198
        /** @var User $user */
199 1
        $user = $request->getAttribute('user');
200
201 1
        if ($img = $user->getPerson()->getImage()) {
202 1
            $path = $this->uploadsDirectory . $img;
203 1
            $mimeType = $this->getMimeType($path);
204
        }
205
206
207 1
        $contents = file_get_contents($path);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $path does not seem to be defined for all execution paths leading up to this point.
Loading history...
208 1
        $stream = new Stream('php://memory', 'r+');
209 1
        $stream->write($contents);
210 1
        $response = $response->withBody($stream);
211 1
        $response = $response->withHeader('Content-Type', $mimeType);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $mimeType does not seem to be defined for all execution paths leading up to this point.
Loading history...
212
213 1
        return $response;
214
    }
215
216
    /**
217
     * @param string $path
218
     * @return string
219
     */
220 1
    private function getMimeType(string $path): string
221
    {
222 1
        $finfo = finfo_open(FILEINFO_MIME); // return mime type
223 1
        $mimeType = finfo_file($finfo, $path);
224 1
        finfo_close($finfo);
225
226 1
        return $mimeType;
227
    }
228
229
}
230