ProfileHelper::squareSize()   C
last analyzed

Complexity

Conditions 14
Paths 5

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 15
nc 5
nop 1
dl 0
loc 21
rs 6.2666
c 0
b 0
f 0

How to fix   Complexity   

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
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula - https://ziku.la/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Zikula\UsersBundle\Helper;
15
16
use Symfony\Bundle\SecurityBundle\Security;
17
use Symfony\Component\DependencyInjection\Attribute\Autowire;
18
use Symfony\Component\HttpFoundation\RequestStack;
19
use Symfony\Component\Routing\RouterInterface;
20
use Zikula\UsersBundle\Entity\User;
21
use Zikula\UsersBundle\ProfileConstant;
22
use Zikula\UsersBundle\Repository\UserRepositoryInterface;
23
use function Symfony\Component\String\s;
24
25
class ProfileHelper
26
{
27
    public function __construct(
28
        private readonly RouterInterface $router,
29
        private readonly RequestStack $requestStack,
30
        private readonly Security $security,
31
        private readonly UserRepositoryInterface $userRepository,
32
        private readonly GravatarHelper $gravatarHelper,
33
        #[Autowire(param: 'kernel.project_dir')]
34
        private readonly string $projectDir,
35
        #[Autowire(param: 'profile_property_prefix')]
36
        private readonly string $prefix,
37
        private readonly string $avatarImagePath,
38
        private readonly string $avatarDefaultImage,
39
        private readonly bool $gravatarEnabled
40
    ) {
41
    }
42
43
    public function getDisplayName($userId = null): string
44
    {
45
        $userEntity = $this->findUser($userId);
46
        if (!$userEntity) {
0 ignored issues
show
introduced by
$userEntity is of type Zikula\UsersBundle\Entity\User, thus it always evaluated to true.
Loading history...
47
            throw new \InvalidArgumentException('Invalid userId provided');
48
        }
49
50
        $key = $this->prefix . ':' . ProfileConstant::ATTRIBUTE_NAME_DISPLAY_NAME;
51
        if ($userEntity->getAttributes()->containsKey($key)) {
52
            return $userEntity->getAttributes()->get($key)->getValue();
53
        }
54
55
        return $userEntity->getUsername();
56
    }
57
58
    public function getFullName($userId = null): string
59
    {
60
        $userEntity = $this->findUser($userId);
61
        if (!$userEntity) {
0 ignored issues
show
introduced by
$userEntity is of type Zikula\UsersBundle\Entity\User, thus it always evaluated to true.
Loading history...
62
            throw new \InvalidArgumentException('Invalid userId provided');
63
        }
64
65
        $key1 = $this->prefix . ':' . ProfileConstant::ATTRIBUTE_NAME_FIRST_NAME;
66
        $key2 = $this->prefix . ':' . ProfileConstant::ATTRIBUTE_NAME_LAST_NAME;
67
        $attributes = $userEntity->getAttributes();
68
        if ($attributes->containsKey($key1) && $attributes->containsKey($key2)) {
69
            return $attributes->get($key1)->getValue() . ' ' . $attributes->get($key2)->getValue();
70
        }
71
72
        return $userEntity->getUsername();
73
    }
74
75
    public function getProfileUrl($userId = null): string
76
    {
77
        $userEntity = $this->findUser($userId);
78
        if (!$userEntity) {
0 ignored issues
show
introduced by
$userEntity is of type Zikula\UsersBundle\Entity\User, thus it always evaluated to true.
Loading history...
79
            throw new \InvalidArgumentException('Invalid userId provided');
80
        }
81
82
        return $this->router->generate('zikulaprofilebundle_profile_display', ['userId' => $userEntity->getId()]);
83
    }
84
85
    public function getAvatar($userId = null, array $parameters = []): string
86
    {
87
        $userEntity = $this->findUser($userId);
88
        if (!$userEntity) {
0 ignored issues
show
introduced by
$userEntity is of type Zikula\UsersBundle\Entity\User, thus it always evaluated to true.
Loading history...
89
            throw new \InvalidArgumentException('Invalid userId provided');
90
        }
91
92
        $avatarPath = $this->avatarImagePath;
93
        $userAttributes = $userEntity->getAttributes();
94
        $key = $this->prefix . ':avatar';
95
        $avatar = $userAttributes[$key] ? $userAttributes[$key]->getValue() : $this->avatarDefaultImage;
96
97
        $avatarUrl = '';
98
        if (!in_array($avatar, ['blank.gif', 'blank.jpg'], true)) {
99
            if (isset($avatar) && !empty($avatar) && $avatar !== $this->avatarDefaultImage && file_exists($this->projectDir . '/' . $avatarPath . '/' . $avatar)) {
100
                $request = $this->requestStack->getCurrentRequest();
101
                if (null !== $request) {
102
                    $avatarPath = s($avatarPath)->after('public/')->toString();
103
                    $avatarUrl = $request->getSchemeAndHttpHost() . $request->getBasePath() . '/' . $avatarPath . '/' . $avatar;
104
                }
105
            } elseif (true === $this->gravatarEnabled) {
106
                $parameters = $this->squareSize($parameters);
107
                $avatarUrl = $this->gravatarHelper->getGravatarUrl($userEntity->getEmail(), $parameters);
108
            }
109
        }
110
111
        if (empty($avatarUrl)) {
112
            // e.g. blank.gif or empty avatars
113
            return '';
114
        }
115
116
        if (!isset($parameters['class'])) {
117
            $parameters['class'] = 'img-fluid img-thumbnail';
118
        }
119
        $attributes = ' class="' . str_replace('"', '', htmlspecialchars($parameters['class'])) . '"';
120
        $attributes .= isset($parameters['width']) ? ' width="' . (int) $parameters['width'] . '"' : '';
121
        $attributes .= isset($parameters['height']) ? ' height="' . (int) $parameters['height'] . '"' : '';
122
123
        $result = '<img src="' . str_replace('"', '', htmlspecialchars($avatarUrl)) . '" title="' . str_replace('"', '', htmlspecialchars($userEntity->getUsername())) . '" alt="' . str_replace('"', '', htmlspecialchars($userEntity->getUsername())) . '"' . $attributes . ' />';
124
125
        return $result;
126
    }
127
128
    /**
129
     * Finds a certain user based on either it's id or it's name.
130
     *
131
     * @param int|string $userId The user's id or name
132
     */
133
    private function findUser($userId = null): ?User
134
    {
135
        if (empty($userId)) {
136
            return $this->security->getUser();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->security->getUser() could return the type Symfony\Component\Security\Core\User\UserInterface which includes types incompatible with the type-hinted return Zikula\UsersBundle\Entity\User|null. Consider adding an additional type-check to rule them out.
Loading history...
137
        }
138
139
        if (is_numeric($userId)) {
140
            return $this->userRepository->find($userId);
141
        }
142
143
        // select user id by user name
144
        $results = $this->userRepository->searchActiveUser(['operator' => '=', 'operand' => $userId], 1);
0 ignored issues
show
Unused Code introduced by
The call to Zikula\UsersBundle\Repos...ace::searchActiveUser() has too many arguments starting with 1. ( Ignorable by Annotation )

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

144
        /** @scrutinizer ignore-call */ 
145
        $results = $this->userRepository->searchActiveUser(['operator' => '=', 'operand' => $userId], 1);

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...
145
        if (!count($results)) {
146
            return null;
147
        }
148
149
        return $results[0];
150
    }
151
152
    /**
153
     * Checks and updates the avatar image size parameters.
154
     */
155
    private function squareSize(array $parameters = []): array
156
    {
157
        if (!isset($parameters['size'])) {
158
            if (isset($parameters['width']) || isset($parameters['height'])) {
159
                $hasWidth = isset($parameters['width']);
160
                $hasHeight = isset($parameters['height']);
161
                if (($hasWidth && !$hasHeight) || ($hasWidth && $hasHeight && $parameters['width'] < $parameters['height'])) {
162
                    $parameters['size'] = $parameters['width'];
163
                } elseif ((!$hasWidth && $hasHeight) || ($hasWidth && $hasHeight && $parameters['width'] > $parameters['height'])) {
164
                    $parameters['size'] = $parameters['height'];
165
                } else {
166
                    $parameters['size'] = 80;
167
                }
168
            } else {
169
                $parameters['size'] = 80;
170
            }
171
        }
172
        $parameters['width'] = $parameters['size'];
173
        $parameters['height'] = $parameters['size'];
174
175
        return $parameters;
176
    }
177
}
178