Issues (281)

Branch: master

src/Frontend/Modules/Profiles/Actions/Settings.php (1 issue)

1
<?php
2
3
namespace Frontend\Modules\Profiles\Actions;
4
5
use ForkCMS\Utility\Thumbnails;
6
use Frontend\Core\Engine\Base\Block as FrontendBaseBlock;
7
use Frontend\Core\Engine\Form as FrontendForm;
8
use Frontend\Core\Engine\Model;
9
use Frontend\Core\Language\Language as FL;
10
use Frontend\Core\Engine\Navigation as FrontendNavigation;
11
use Frontend\Modules\Profiles\Engine\Authentication as FrontendProfilesAuthentication;
12
use Frontend\Modules\Profiles\Engine\Model as FrontendProfilesModel;
13
use Frontend\Modules\Profiles\Engine\Profile;
14
use Symfony\Component\Intl\Intl;
15
use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException;
16
17
class Settings extends FrontendBaseBlock
18
{
19
    /**
20
     * @var FrontendForm
21
     */
22
    private $form;
23
24
    /**
25
     * @var Profile
26
     */
27
    private $profile;
28
29
    public function execute(): void
30
    {
31
        if (!FrontendProfilesAuthentication::isLoggedIn()) {
32
            throw new InsufficientAuthenticationException('You need to log in to change your settings');
33
        }
34
35
        parent::execute();
36
        $this->loadTemplate();
37
        $this->profile = FrontendProfilesAuthentication::getProfile();
38
39
        $this->buildForm();
40
        $this->handleForm();
41
        $this->parse();
42
    }
43
44
    private function getGenderOptions(): array
45
    {
46
        return [
47
            'male' => \SpoonFilter::ucfirst(FL::getLabel('Male')),
48
            'female' => \SpoonFilter::ucfirst(FL::getLabel('Female')),
49
        ];
50
    }
51
52
    private function getBirthDateOptions(): array
53
    {
54
        return [
55
            'days' => range(1, 31),
56
            'months' => \SpoonLocale::getMonths(LANGUAGE),
57
            'years' => range(date('Y'), 1900),
58
        ];
59
    }
60
61
    private function getBirthDate(): array
62
    {
63
        $birthDate = $this->profile->getSetting('birth_date');
64
65
        return array_combine(
66
            ['year', 'month', 'day'],
67
            (empty($birthDate) ? ['', '', ''] : explode('-', $birthDate))
68
        );
69
    }
70
71
    private function buildForm(): void
72
    {
73
        $this->form = new FrontendForm('updateSettings', null, null, 'updateSettingsForm');
74
75
        $this->form
76
            ->addText('display_name', $this->profile->getDisplayName())
77
            ->setAttribute('autocomplete', 'username')
78
            ->makeRequired()
79
        ;
80
        if (!$this->displayNameCanStillBeChanged()) {
81
            $this->form->getField('display_name')->setAttribute('disabled', 'disabled');
82
        }
83
        $this->form
84
            ->addText('first_name', $this->profile->getSetting('first_name'))
85
            ->setAttribute('autocomplete', 'given-name')
86
        ;
87
        $this->form
88
            ->addText('last_name', $this->profile->getSetting('last_name'))
89
            ->setAttribute('autocomplete', 'family-name')
90
        ;
91
        $this->form->addText('email', $this->profile->getEmail())->setAttribute('disabled', 'disabled');
92
        $this->form
93
            ->addText('city', $this->profile->getSetting('city'))
94
            ->setAttribute('autocomplete', 'address-level2')
95
        ;
96
        $this->form
97
            ->addDropdown(
98
                'country',
99
                Intl::getRegionBundle()->getCountryNames(LANGUAGE),
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Component\Intl\Intl::getRegionBundle() has been deprecated: since Symfony 4.3, to be removed in 5.0. Use {@see Countries} instead. ( Ignorable by Annotation )

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

99
                /** @scrutinizer ignore-deprecated */ Intl::getRegionBundle()->getCountryNames(LANGUAGE),

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...
100
                $this->profile->getSetting('country')
101
            )
102
            ->setDefaultElement('')
103
            ->setAttribute('autocomplete', 'country-name')
104
        ;
105
        $this->form
106
            ->addDropdown(
107
                'gender',
108
                $this->getGenderOptions(),
109
                $this->profile->getSetting('gender')
110
            )
111
            ->setDefaultElement('')
112
            ->setAttribute('autocomplete', 'sex')
113
        ;
114
        ['days' => $days, 'months' => $months, 'years' => $years] = $this->getBirthDateOptions();
115
        ['year' => $birthYear, 'month' => $birthMonth, 'day' => $birthDay] = $this->getBirthDate();
116
        $this->form
117
            ->addDropdown('day', array_combine($days, $days), $birthDay)
118
            ->setAttribute('autocomplete', 'bday-day')
119
            ->setDefaultElement('')
120
        ;
121
        $this->form
122
            ->addDropdown('month', $months, $birthMonth)
123
            ->setAttribute('autocomplete', 'bday-month')
124
            ->setDefaultElement('')
125
        ;
126
        $this->form
127
            ->addDropdown('year', array_combine($years, $years), (int) $birthYear)
128
            ->setAttribute('autocomplete', 'bday-year')
129
            ->setDefaultElement('')
130
        ;
131
        $this->form->addImage('avatar');
132
        $this->form->addTextarea('about', $this->profile->getSetting('about'));
133
    }
134
135
    private function parse(): void
136
    {
137
        if ($this->url->getParameter('settingsUpdated') === 'true') {
138
            $this->template->assign('updateSettingsSuccess', true);
139
        }
140
141
        // assign avatar the current avatar for the preview image
142
        $this->template->assign('avatar', (string) $this->profile->getSetting('avatar', ''));
143
144
        $this->form->parse($this->template);
145
146
        // display name changes
147
        $this->template->assign('maxDisplayNameChanges', FrontendProfilesModel::MAX_DISPLAY_NAME_CHANGES);
148
        $this->template->assign(
149
            'displayNameChangesLeft',
150
            FrontendProfilesModel::MAX_DISPLAY_NAME_CHANGES - $this->profile->getSetting('display_name_changes')
151
        );
152
    }
153
154
    private function getAmountOfDisplayNameChanges(): int
155
    {
156
        return (int) FrontendProfilesModel::getSetting($this->profile->getId(), 'display_name_changes');
157
    }
158
159
    private function displayNameCanStillBeChanged(): bool
160
    {
161
        return FrontendProfilesModel::displayNameCanStillBeChanged($this->profile);
162
    }
163
164
    private function validateForm(): bool
165
    {
166
        $txtDisplayName = $this->form->getField('display_name');
167
        $ddmDay = $this->form->getField('day');
168
        $ddmMonth = $this->form->getField('month');
169
        $ddmYear = $this->form->getField('year');
170
171
        if ($this->displayNameCanStillBeChanged()
172
            && $this->profile->getDisplayName() !== $txtDisplayName->getValue()
173
            && $txtDisplayName->isFilled(FL::getError('FieldIsRequired'))
174
            && FrontendProfilesModel::existsDisplayName($txtDisplayName->getValue(), $this->profile->getId())) {
175
            $txtDisplayName->addError(FL::getError('DisplayNameExists'));
176
        }
177
178
        // birthdate is not required but if one is filled we need all
179
        if ($ddmMonth->isFilled() || $ddmDay->isFilled() || $ddmYear->isFilled()) {
180
            // valid birth date?
181
            if (!checkdate($ddmMonth->getValue(), $ddmDay->getValue(), $ddmYear->getValue())) {
182
                $ddmYear->addError(FL::getError('DateIsInvalid'));
183
            }
184
        }
185
186
        // do some basic image checks if an avatar was uploaded
187
        $this->form->getField('avatar')->isFilled();
188
189
        return $this->form->isCorrect();
190
    }
191
192
    private function displayNameWasChanged(): bool
193
    {
194
        $txtDisplayName = $this->form->getField('display_name');
195
196
        if (!$this->displayNameCanStillBeChanged()
197
            || $this->profile->getDisplayName() === $txtDisplayName->getValue()) {
198
            // no change or not allowed to change the display name
199
            return false;
200
        }
201
202
        $this->profile->setDisplayName($txtDisplayName->getValue());
203
        $this->profile->setUrl(FrontendProfilesModel::getUrl($txtDisplayName->getValue(), $this->profile->getId()));
204
205
        FrontendProfilesModel::update(
206
            $this->profile->getId(),
207
            [
208
                'display_name' => $this->profile->getDisplayName(),
209
                'url' => $this->profile->getUrl(),
210
            ]
211
        );
212
213
        return true;
214
    }
215
216
    private function handleForm(): void
217
    {
218
        if (!$this->form->isSubmitted()) {
219
            return;
220
        }
221
222
        if (!$this->validateForm()) {
223
            $this->template->assign('updateSettingsHasFormError', true);
224
225
            return;
226
        }
227
228
        $displayNameChanges = $this->getAmountOfDisplayNameChanges();
229
        if ($this->displayNameWasChanged()) {
230
            ++$displayNameChanges;
231
        }
232
233
        $this->profile->setSettings(
234
            [
235
                'display_name_changes' => $displayNameChanges,
236
                'first_name' => $this->form->getField('first_name')->getValue(),
237
                'last_name' => $this->form->getField('last_name')->getValue(),
238
                'city' => $this->form->getField('city')->getValue(),
239
                'country' => $this->form->getField('country')->getValue(),
240
                'gender' => $this->form->getField('gender')->getValue(),
241
                'birth_date' => $this->getSubmittedBirthDate(),
242
                'avatar' => $this->getAvatar(),
243
                'about' => $this->form->getField('about')->getValue(),
244
            ]
245
        );
246
247
        $this->redirect(
248
            FrontendNavigation::getUrlForBlock($this->getModule(), $this->getAction()) . '?settingsUpdated=true'
249
        );
250
    }
251
252
    private function getAvatar(): ?string
253
    {
254
        $currentAvatar = $this->profile->getSetting('avatar');
255
        if (!$this->form->getField('avatar')->isFilled()) {
256
            return $currentAvatar;
257
        }
258
259
        $baseAvatarPath = FRONTEND_FILES_PATH . '/Profiles/Avatars/';
260
        $this->get(Thumbnails::class)->delete($baseAvatarPath, $currentAvatar);
261
262
        $newAvatar = $this->profile->getUrl() . '.' . $this->form->getField('avatar')->getExtension();
263
264
        $this->form->getField('avatar')->generateThumbnails($baseAvatarPath, $newAvatar);
265
266
        return $newAvatar;
267
    }
268
269
    private function getSubmittedBirthDate(): ?string
270
    {
271
        if (!$this->form->getField('year')->isFilled()) {
272
            return null;
273
        }
274
275
        return sprintf(
276
            '%1$s-%2$s-%3$s',
277
            $this->form->getField('year')->getValue(),
278
            str_pad($this->form->getField('month')->getValue(), 2, '0', STR_PAD_LEFT),
279
            str_pad($this->form->getField('day')->getValue(), 2, '0', STR_PAD_LEFT)
280
        );
281
    }
282
}
283