ProfileHelper::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 10
dl 0
loc 14
rs 10
c 0
b 0
f 0

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
/*
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