ForumMemberProfile   F
last analyzed

Complexity

Total Complexity 87

Size/Duplication

Total Lines 677
Duplicated Lines 5.47 %

Coupling/Cohesion

Components 2
Dependencies 22

Importance

Changes 0
Metric Value
wmc 87
lcom 2
cbo 22
dl 37
loc 677
rs 1.3357
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A ModeratedForums() 0 5 2
A Breadcrumbs() 0 13 1
A init() 0 11 3
A show() 0 9 2
A LatestPosts() 0 10 1
A register() 0 8 1
C RegistrationForm() 0 57 10
C doregister() 9 64 11
A registerwithopenid() 0 12 2
A RegistrationWithOpenIDForm() 0 12 1
C doregisterwithopenid() 17 95 11
C processopenidresponse() 0 65 10
A edit() 0 18 4
C EditProfileForm() 0 27 8
B dosave() 11 54 5
A thanks() 0 6 1
A Link() 0 4 1
A Member() 0 11 3
A getForumHolder() 0 20 4
A getHolderSubtitle() 0 4 1
A URLSegment() 0 4 1
A MetaTags() 0 16 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ForumMemberProfile often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ForumMemberProfile, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * ForumMemberProfile is the profile pages for a given ForumMember
4
 *
5
 * @package forum
6
 */
7
class ForumMemberProfile extends Page_Controller
8
{
9
10
    private static $allowed_actions = array(
11
        'show',
12
        'register',
13
        'RegistrationForm',
14
        'registerwithopenid',
15
        'RegistrationWithOpenIDForm',
16
        'edit',
17
        'EditProfileForm',
18
        'thanks',
19
    );
20
21
    public $URLSegment = "ForumMemberProfile";
22
23
    /**
24
     * Return a set of {@link Forum} objects that
25
     * this member is a moderator of.
26
     *
27
     * @return ComponentSet
28
     */
29
    function ModeratedForums()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
30
    {
31
        $member = $this->Member();
32
        return $member ? $member->ModeratedForums() : null;
33
    }
34
35
    /**
36
     * Create breadcrumbs (just shows a forum holder link and name of user)
37
     * @return string HTML code to display breadcrumbs
38
     */
39
    public function Breadcrumbs()
40
    {
41
        $nonPageParts = array();
42
        $parts = array();
43
44
        $forumHolder = $this->getForumHolder();
45
        $member = $this->Member();
0 ignored issues
show
Unused Code introduced by
$member is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
46
47
        $parts[] = '<a href="' . $forumHolder->Link() . '">' . $forumHolder->Title . '</a>';
48
        $nonPageParts[] = _t('ForumMemberProfile.USERPROFILE', 'User Profile');
49
50
        return implode(" &raquo; ", array_reverse(array_merge($nonPageParts, $parts)));
51
    }
52
53
    /**
54
     * Initialise the controller
55
     */
56
    function init()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
57
    {
58
        Requirements::themedCSS('Forum', 'forum', 'all');
59
        $member = $this->Member() ? $this->Member() : null;
60
        $nicknameText = ($member) ? ($member->Nickname . '\'s ') : '';
61
62
        //$this->Title = DBField::create('HTMLText',Convert::raw2xml($nicknameText) . _t('ForumMemberProfile.USERPROFILE', 'User Profile'));
63
        $this->Title = DBField::create_field('HTMLText', Convert::raw2xml($nicknameText) . _t('ForumMemberProfile.USERPROFILE', 'User Profile'));
64
65
        parent::init();
66
    }
67
68
    function show($request)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
69
    {
70
        $member = $this->Member();
71
        if (!$member) {
72
            return $this->httpError(404);
73
        }
74
75
        return $this->renderWith(array('ForumMemberProfile_show', 'Page'));
76
    }
77
78
    /**
79
     * Get the latest 10 posts by this member
80
     */
81
    function LatestPosts()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
82
    {
83
        return Post::get()
84
            ->filter('AuthorID', (int)$this->urlParams['ID'])
85
            ->limit(10, 0)
86
            ->sort('Created', 'DESC')
87
            ->filterByCallback(function ($post) {
88
                return $post->canView();
89
            });
90
    }
91
92
93
    /**
94
     * Show the registration form
95
     */
96
    function register()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
97
    {
98
        return array(
99
            "Title" => _t('ForumMemberProfile.FORUMREGTITLE', 'Forum Registration'),
100
            "Subtitle" => _t('ForumMemberProfile.REGISTER', 'Register'),
101
            "Abstract" => $this->getForumHolder()->ProfileAbstract,
102
        );
103
    }
104
105
106
    /**
107
     * Factory method for the registration form
108
     *
109
     * @return Form Returns the registration form
110
     */
111
    function RegistrationForm()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
112
    {
113
        $data = Session::get("FormInfo.Form_RegistrationForm.data");
114
115
        $use_openid =
116
            ($this->getForumHolder()->OpenIDAvailable() == true) &&
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
117
            (isset($data['IdentityURL']) && !empty($data['IdentityURL'])) ||
118
            (isset($_POST['IdentityURL']) && !empty($_POST['IdentityURL']));
119
120
        $fields = singleton('Member')->getForumFields($use_openid, true);
121
122
        // If a BackURL is provided, make it hidden so the post-registration
123
        // can direct to it.
124
        if (isset($_REQUEST['BackURL'])) {
125
            $fields->push(new HiddenField('BackURL', 'BackURL', $_REQUEST['BackURL']));
126
        }
127
128
        $validator = singleton('Member')->getForumValidator(!$use_openid);
129
        $form = new Form(
130
            $this,
131
            'RegistrationForm',
132
            $fields,
133
            new FieldList(new FormAction("doregister", _t('ForumMemberProfile.REGISTER', 'Register'))),
134
            $validator
135
        );
136
137
        // Guard against automated spam registrations by optionally adding a field
138
        // that is supposed to stay blank (and is hidden from most humans).
139
        // The label and field name are intentionally common ("username"),
140
        // as most spam bots won't resist filling it out. The actual username field
141
        // on the forum is called "Nickname".
142
        if (ForumHolder::$use_honeypot_on_register) {
143
            $form->Fields()->push(
144
                new LiteralField(
145
                    'HoneyPot',
146
                    '<div style="position: absolute; left: -9999px;">' .
147
                    // We're super paranoid and don't mention "ignore" or "blank" in the label either
148
                    '<label for="RegistrationForm_username">' . _t('ForumMemberProfile.LeaveBlank', 'Don\'t enter anything here'). '</label>' .
149
                    '<input type="text" name="username" id="RegistrationForm_username" value="" />' .
150
                    '</div>'
151
                )
152
            );
153
        }
154
155
        $member = new Member();
0 ignored issues
show
Unused Code introduced by
$member is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
156
157
        // we should also load the data stored in the session. if failed
158
        if (is_array($data)) {
159
            $form->loadDataFrom($data);
160
        }
161
162
        // Optional spam protection
163
        if (class_exists('SpamProtectorManager') && ForumHolder::$use_spamprotection_on_register) {
164
            $form->enableSpamProtection();
165
        }
166
        return $form;
167
    }
168
169
170
    /**
171
     * Register a new member
172
     *
173
     * @param array $data User submitted data
174
     * @param Form $form The used form
175
     */
176
    function doregister($data, $form)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
177
    {
178
179
        // Check if the honeypot has been filled out
180
        if (ForumHolder::$use_honeypot_on_register) {
181
            if (@$data['username']) {
182
                SS_Log::log(sprintf(
183
                    'Forum honeypot triggered (data: %s)',
184
                    http_build_query($data)
185
                ), SS_Log::NOTICE);
186
                return $this->httpError(403);
187
            }
188
        }
189
190
        $forumGroup = Group::get()->filter('Code', 'forum-members')->first();
191
192
        if ($member = Member::get()->filter('Email', $data['Email'])->first()) {
193 View Code Duplication
            if ($member) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
                $form->addErrorMessage(
195
                    "Blurb",
196
                    _t('ForumMemberProfile.EMAILEXISTS', 'Sorry, that email address already exists. Please choose another.'),
197
                    "bad"
198
                );
199
200
                // Load errors into session and post back
201
                Session::set("FormInfo.Form_RegistrationForm.data", $data);
0 ignored issues
show
Documentation introduced by
$data is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
202
                return $this->redirectBack();
203
            }
204
        } elseif ($this->getForumHolder()->OpenIDAvailable()
205
               && isset($data['IdentityURL'])
206
               && ($member = Member::get()->filter('IdentityURL', $data['IdentityURL'])->first())
207
        ) {
208
            $errorMessage = _t('ForumMemberProfile.OPENIDEXISTS', 'Sorry, that OpenID is already registered. Please choose another or register without OpenID.');
209
            $form->addErrorMessage("Blurb", $errorMessage, "bad");
210
211
            // Load errors into session and post back
212
            Session::set("FormInfo.Form_RegistrationForm.data", $data);
0 ignored issues
show
Documentation introduced by
$data is of type array<string,?,{"IdentityURL":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
213
            return $this->redirectBack();
214
        } elseif ($member = Member::get()->filter('Nickname', $data['Nickname'])->first()) {
0 ignored issues
show
Unused Code introduced by
$member is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
215
            $errorMessage = _t('ForumMemberProfile.NICKNAMEEXISTS', 'Sorry, that nickname already exists. Please choose another.');
216
            $form->addErrorMessage("Blurb", $errorMessage, "bad");
217
218
            // Load errors into session and post back
219
            Session::set("FormInfo.Form_RegistrationForm.data", $data);
0 ignored issues
show
Documentation introduced by
$data is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
220
            return $this->redirectBack();
221
        }
222
223
        // create the new member
224
        $member = Object::create('Member');
225
        $form->saveInto($member);
226
227
        $member->write();
228
        $member->login();
229
230
        $member->Groups()->add($forumGroup);
231
232
        $member->extend('onForumRegister', $this->request);
233
234
        if (isset($data['BackURL']) && $data['BackURL']) {
235
            return $this->redirect($data['BackURL']);
236
        }
237
238
        return array("Form" => ForumHolder::get()->first()->ProfileAdd);
239
    }
240
241
242
    /**
243
     * Start registration with OpenID
244
     *
245
     * @param array $data Data passed by the director
246
     * @param array $message Message and message type to output
247
     * @return array Returns the needed data to render the registration form.
248
     */
249
    function registerwithopenid($data, $message = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
250
    {
251
        return array(
252
            "Title" => _t('ForumMemberProfile.SSFORUM'),
253
            "Subtitle" => _t('ForumMemberProfile.REGISTEROPENID', 'Register with OpenID'),
254
            "Abstract" => ($message)
255
                ? '<p class="' . $message['type'] . '">' .
256
                        Convert::raw2xml($message['message']) . '</p>'
257
                : "<p>" . _t('ForumMemberProfile.ENTEROPENID', 'Please enter your OpenID to continue the registration') . "</p>",
258
            "Form" => $this->RegistrationWithOpenIDForm(),
259
        );
260
    }
261
262
263
    /**
264
     * Factory method for the OpenID registration form
265
     *
266
     * @return Form Returns the OpenID registration form
267
     */
268
    function RegistrationWithOpenIDForm()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
269
    {
270
        $form = new Form(
271
            $this,
272
            'RegistrationWithOpenIDForm',
273
            new FieldList(new TextField("OpenIDURL", "OpenID URL", "", null)),
274
            new FieldList(new FormAction("doregisterwithopenid", _t('ForumMemberProfile.REGISTER', 'Register'))),
275
            new RequiredFields("OpenIDURL")
276
        );
277
278
        return $form;
279
    }
280
281
282
    /**
283
     * Register a new member
284
     */
285
    function doregisterwithopenid($data, $form)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
286
    {
287
        $openid = trim($data['OpenIDURL']);
288
        Session::set("FormInfo.Form_RegistrationWithOpenIDForm.data", $data);
289
290 View Code Duplication
        if (strlen($openid) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
291
            if (!is_null($form)) {
292
                $form->addErrorMessage(
293
                    "Blurb",
294
                    "Please enter your OpenID or your i-name.",
295
                    "bad"
296
                );
297
            }
298
            return $this->redirectBack();
299
        }
300
301
302
        $trust_root = Director::absoluteBaseURL();
303
        $return_to_url = $trust_root . $this->Link('processopenidresponse');
304
305
        $consumer = new Auth_OpenID_Consumer(new OpenIDStorage(), new SessionWrapper());
306
307
308
        // No auth request means we can't begin OpenID
309
        $auth_request = $consumer->begin($openid);
310 View Code Duplication
        if (!$auth_request) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
311
            if (!is_null($form)) {
312
                $form->addErrorMessage(
313
                    "Blurb",
314
                    "That doesn't seem to be a valid OpenID or i-name identifier. " .
315
                    "Please try again.",
316
                    "bad"
317
                );
318
            }
319
            return $this->redirectBack();
320
        }
321
322
        $SQL_identity = Convert::raw2sql($auth_request->endpoint->claimed_id);
323
        if ($member = Member::get()->filter('IdentityURL', $SQL_identity)->first()) {
0 ignored issues
show
Unused Code introduced by
$member is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
324
            if (!is_null($form)) {
325
                $form->addErrorMessage(
326
                    "Blurb",
327
                    "That OpenID or i-name is already registered. Use another one.",
328
                    "bad"
329
                );
330
            }
331
            return $this->redirectBack();
332
        }
333
334
335
        // Add the fields for which we wish to get the profile data
336
        $sreg_request = Auth_OpenID_SRegRequest::build(
337
            null,
338
            array('nickname', 'fullname', 'email', 'country')
339
        );
340
341
        if ($sreg_request) {
342
            $auth_request->addExtension($sreg_request);
343
        }
344
345
346
        if ($auth_request->shouldSendRedirect()) {
347
            // For OpenID 1, send a redirect.
348
            $redirect_url = $auth_request->redirectURL($trust_root, $return_to_url);
349
350
            if (Auth_OpenID::isFailure($redirect_url)) {
351
                displayError("Could not redirect to server: " .
352
                                         $redirect_url->message);
353
            } else {
354
                return $this->redirect($redirect_url);
355
            }
356
        } else {
357
            // For OpenID 2, use a javascript form to send a POST request to the
358
            // server.
359
            $form_id = 'openid_message';
360
            $form_html = $auth_request->formMarkup($trust_root, $return_to_url, false, array('id' => $form_id));
361
362
            if (Auth_OpenID::isFailure($form_html)) {
363
                displayError("Could not redirect to server: " .$form_html->message);
364
            } else {
365
                $page_contents = array(
366
                     "<html><head><title>",
367
                     "OpenID transaction in progress",
368
                     "</title></head>",
369
                     "<body onload='document.getElementById(\"". $form_id .
370
                       "\").submit()'>",
371
                     $form_html,
372
                     "<p>Click &quot;Continue&quot; to login. You are only seeing " .
373
                     "this because you appear to have JavaScript disabled.</p>",
374
                     "</body></html>");
375
376
                print implode("\n", $page_contents);
377
            }
378
        }
379
    }
380
381
382
383
    /**
384
     * Function to process the response of the OpenID server
385
     */
386
    function processopenidresponse()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
387
    {
388
        $consumer = new Auth_OpenID_Consumer(new OpenIDStorage(), new SessionWrapper());
389
390
        $trust_root = Director::absoluteBaseURL();
391
        $return_to_url = $trust_root . $this->Link('ProcessOpenIDResponse');
392
393
        // Complete the authentication process using the server's response.
394
        $response = $consumer->complete($return_to_url);
395
396
        if ($response->status == Auth_OpenID_SUCCESS) {
397
            Session::clear("FormInfo.Form_RegistrationWithOpenIDForm.data");
398
            $openid = $response->identity_url;
399
400
            if ($response->endpoint->canonicalID) {
401
                $openid = $response->endpoint->canonicalID;
402
            }
403
404
            $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
405
            $sreg = $sreg_resp->contents();
406
407
            // Convert the simple registration data to the needed format
408
            // try to split fullname to get firstname and surname
409
            $data = array('IdentityURL' => $openid);
410
            if (isset($sreg['nickname'])) {
411
                $data['Nickname'] = $sreg['nickname'];
412
            }
413
            if (isset($sreg['fullname'])) {
414
                $fullname = explode(' ', $sreg['fullname'], 2);
415
                if (count($fullname) == 2) {
416
                    $data['FirstName'] = $fullname[0];
417
                    $data['Surname'] = $fullname[1];
418
                } else {
419
                    $data['Surname'] = $fullname[0];
420
                }
421
            }
422
            if (isset($sreg['country'])) {
423
                $data['Country'] = $sreg['country'];
424
            }
425
            if (isset($sreg['email'])) {
426
                $data['Email'] = $sreg['email'];
427
            }
428
429
            Session::set("FormInfo.Form_RegistrationForm.data", $data);
0 ignored issues
show
Documentation introduced by
$data is of type array<string,?>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
430
            return $this->redirect($this->Link('register'));
431
        }
432
433
434
        // The server returned an error message, handle it!
435
        if ($response->status == Auth_OpenID_CANCEL) {
436
            $error_message = _t('ForumMemberProfile.CANCELLEDVERIFICATION', 'The verification was cancelled. Please try again.');
437
        } elseif ($response->status == Auth_OpenID_FAILURE) {
438
            $error_message = _t('ForumMemberProfile.AUTHENTICATIONFAILED', 'The OpenID/i-name authentication failed.');
439
        } else {
440
            $error_message = _t('ForumMemberProfile.UNEXPECTEDERROR', 'An unexpected error occured. Please try again or register without OpenID');
441
        }
442
443
        $this->RegistrationWithOpenIDForm()->addErrorMessage(
444
            "Blurb",
445
            $error_message,
446
            'bad'
447
        );
448
449
        return $this->redirect($this->Link('registerwithopenid'));
450
    }
451
452
453
    /**
454
     * Edit profile
455
     *
456
     * @return array Returns an array to render the edit profile page.
457
     */
458
    function edit()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
459
    {
460
        $holder = DataObject::get_one("ForumHolder");
461
        $form = $this->EditProfileForm();
462
463
        if (!$form && Member::currentUser()) {
464
            $form = "<p class=\"error message\">" . _t('ForumMemberProfile.WRONGPERMISSION', 'You don\'t have the permission to edit that member.') . "</p>";
465
        } elseif (!$form) {
466
            return $this->redirect('ForumMemberProfile/show/'.$this->Member()->ID);
467
        }
468
469
        return array(
470
            "Title" => "Forum",
471
            "Subtitle" => $holder->ProfileSubtitle,
472
            "Abstract" => $holder->ProfileAbstract,
473
            "Form" => $form,
474
        );
475
    }
476
477
478
    /**
479
     * Factory method for the edit profile form
480
     *
481
     * @return Form Returns the edit profile form.
482
     */
483
    function EditProfileForm()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
484
    {
485
        $member = $this->Member();
486
        $show_openid = (isset($member->IdentityURL) && !empty($member->IdentityURL));
487
488
        $fields = $member ? $member->getForumFields($show_openid) : singleton('Member')->getForumFields($show_openid);
489
        $validator = $member ? $member->getForumValidator(false) : singleton('Member')->getForumValidator(false);
490
        if ($holder = DataObject::get_one('ForumHolder', "\"DisplaySignatures\" = '1'")) {
0 ignored issues
show
Unused Code introduced by
$holder is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
491
            $fields->push(new TextareaField('Signature', 'Forum Signature'));
492
        }
493
494
        $form = new Form(
495
            $this,
496
            'EditProfileForm',
497
            $fields,
498
            new FieldList(new FormAction("dosave", _t('ForumMemberProfile.SAVECHANGES', 'Save changes'))),
499
            $validator
500
        );
501
502
        if ($member && $member->hasMethod('canEdit') && $member->canEdit()) {
503
            $member->Password = '';
504
            $form->loadDataFrom($member);
505
            return $form;
506
        }
507
508
        return null;
509
    }
510
511
512
    /**
513
     * Save member profile action
514
     *
515
     * @param array $data
516
     * @param $form
517
     */
518
    function dosave($data, $form)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
519
    {
520
        $member = Member::currentUser();
521
522
        $SQL_email = Convert::raw2sql($data['Email']);
523
        $forumGroup = DataObject::get_one('Group', "\"Code\" = 'forum-members'");
524
525
        // An existing member may have the requested email that doesn't belong to the
526
        // person who is editing their profile - if so, throw an error
527
        $existingMember = DataObject::get_one('Member', "\"Email\" = '$SQL_email'");
528
        if ($existingMember) {
529 View Code Duplication
            if ($existingMember->ID != $member->ID) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
530
                $form->addErrorMessage(
531
                    'Blurb',
532
                    _t(
533
                        'ForumMemberProfile.EMAILEXISTS',
534
                        'Sorry, that email address already exists. Please choose another.'
535
                    ),
536
                    'bad'
537
                );
538
539
                return $this->redirectBack();
540
            }
541
        }
542
543
        $nicknameCheck = DataObject::get_one(
544
            "Member",
545
            sprintf(
546
                "\"Nickname\" = '%s' AND \"Member\".\"ID\" != '%d'",
547
                Convert::raw2sql($data['Nickname']),
548
                $member->ID
549
            )
550
        );
551
552
        if ($nicknameCheck) {
553
            $form->addErrorMessage(
554
                "Blurb",
555
                _t('ForumMemberProfile.NICKNAMEEXISTS', 'Sorry, that nickname already exists. Please choose another.'),
556
                "bad"
557
            );
558
            return $this->redirectBack();
559
        }
560
561
        $form->saveInto($member);
562
        $member->write();
563
564
        if (!$member->inGroup($forumGroup)) {
565
            $forumGroup->Members()->add($member);
566
        }
567
568
        $member->extend('onForumUpdateProfile', $this->request);
569
570
        return $this->redirect('thanks');
571
    }
572
573
574
    /**
575
     * Print the "thank you" page
576
     *
577
     * Used after saving changes to a member profile.
578
     *
579
     * @return array Returns the needed data to render the page.
580
     */
581
    function thanks()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
582
    {
583
        return array(
584
            "Form" => DataObject::get_one("ForumHolder")->ProfileModify
585
        );
586
    }
587
588
589
    /**
590
     * Create a link
591
     *
592
     * @param string $action Name of the action to link to
593
     * @return string Returns the link to the passed action.
594
     */
595
    function Link($action = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
596
    {
597
        return "$this->class/$action";
598
    }
599
600
601
    /**
602
     * Return the with the passed ID (via URL parameters) or the current user
603
     *
604
     * @return null|Member Returns the member object or NULL if the member
605
     *                     was not found
606
     */
607
    function Member()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
608
    {
609
        $member = null;
0 ignored issues
show
Unused Code introduced by
$member is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
610
        if (!empty($this->urlParams['ID']) && is_numeric($this->urlParams['ID'])) {
611
            $member = DataObject::get_by_id('Member', $this->urlParams['ID']);
612
        } else {
613
            $member = Member::currentUser();
614
        }
615
616
        return $member;
617
    }
618
619
    /**
620
     * Get the forum holder controller. Sadly we can't work out which forum holder
621
     *
622
     * @return ForumHolder Returns the forum holder controller.
623
     */
624
    function getForumHolder()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
625
    {
626
        $holders = DataObject::get("ForumHolder");
627
        if ($holders) {
628
            foreach ($holders as $holder) {
629
                if ($holder->canView()) {
630
                    return $holder;
631
                }
632
            }
633
        }
634
635
        // no usable forums
636
        $messageSet = array(
637
            'default' => _t('Forum.LOGINTOPOST', 'You\'ll need to login before you can post to that forum. Please do so below.'),
638
            'alreadyLoggedIn' => _t('Forum.NOPOSTPERMISSION', 'I\'m sorry, but you do not have permission to this edit this profile.'),
639
            'logInAgain' => _t('Forum.LOGINTOPOSTAGAIN', 'You have been logged out of the forums.  If you would like to log in again to post, enter a username and password below.'),
640
        );
641
642
        return Security::permissionFailure($this, $messageSet);
643
    }
644
645
    /**
646
     * Get a subtitle
647
     */
648
    function getHolderSubtitle()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
649
    {
650
        return _t('ForumMemberProfile.USERPROFILE', 'User profile');
651
    }
652
653
654
    /**
655
     * Get the URL segment of the forum holder
656
     *
657
     */
658
    function URLSegment()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
659
    {
660
        return $this->getForumHolder()->URLSegment;
661
    }
662
663
664
    /**
665
     * This needs MetaTags because it doesn't extend SiteTree at any point
666
     */
667
    function MetaTags($includeTitle = true)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
668
    {
669
        $tags = "";
670
        $title = _t('ForumMemberProfile.FORUMUSERPROFILE', 'Forum User Profile');
671
672
        if (isset($this->urlParams['Action'])) {
673
            if ($this->urlParams['Action'] == "register") {
674
                $title = _t('ForumMemberProfile.FORUMUSERREGISTER', 'Forum Registration');
675
            }
676
        }
677
        if ($includeTitle == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
678
            $tags .= "<title>" . $title . "</title>\n";
679
        }
680
681
        return $tags;
682
    }
683
}
684