Completed
Push — 1 ( 13c7dd...13037b )
by Morven
01:38
created

code/control/Users_Register_Controller.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Base controller class for users to register. Provides extension hooks to
5
 * allow third party overwriting of both index and register form actions
6
 *
7
 * This controller is also used to allow registered accounts to "verify"
8
 * their details via email.
9
 *
10
 * This is done by adding verified users to the groups stipulated by the
11
 * $verification_groups config variable
12
 *
13
 */
14
class Users_Register_Controller extends Controller
15
{
16
17
    /**
18
     * URL That you can access this from
19
     *
20
     * @config
21
     */
22
    private static $url_segment = "users/register";
23
24
    /**
25
     * Current actions available to this controller
26
     *
27
     * @var array
28
     */
29
    private static $allowed_actions = array(
30
        "index",
31
        "sendverification",
32
        "verify",
33
        "RegisterForm"
34
    );
35
36
    /**
37
     * Internal function designed to allow us to send a verification
38
     * email from multiple locations
39
     *
40
     * @param $member Member object to send email to
41
     * @return boolean
42
     */
43
    protected function send_verification_email(Member $member)
44
    {
45
        if ($member) {
46
            $subject = _t("Users.PleaseVerify", "Please verify your account");
47
            if (Users::config()->send_email_from) {
48
                $from = Users::config()->send_email_from;
49
            } else {
50
                $from = Email::config()->admin_email;
51
            }
52
53
            $body = $this->renderWith(
54
                'UsersAccountVerification',
55
                array(
56
                    "Link" => Controller::join_links(
57
                        Director::absoluteBaseURL(),
58
                        $this->config()->url_segment,
59
                        "verify",
60
                        $member->ID,
61
                        $member->VerificationCode
62
                    )
63
                )
64
            );
65
66
            $email = new Email($from, $member->Email, $subject, $body);
67
            $email->sendPlain();
68
69
            return true;
70
        }
71
72
        return false;
73
    }
74
75
    /**
76
     * Get the link to this controller
77
     * 
78
     * @param string $action
79
     * @return string|null
80
     */
81
    public function Link($action = null)
82
    {
83
        return Controller::join_links(
84
            $this->config()->url_segment,
85
            $action
86
        );
87
    }
88
89
    /**
90
     * Get an absolute link to this controller
91
     *
92
     * @param string $action
93
     * @return string|null
94
     */
95
    public function AbsoluteLink($action = null)
96
    {
97
        return Director::absoluteURL($this->Link($action));
98
    }
99
100
    /**
101
     * Get a relative (to the root url of the site) link to this
102
     * controller
103
     *
104
     * @param string $action
105
     * @return string|null
106
     */
107
    public function RelativeLink($action = null)
108
    {
109
        return Controller::join_links(
110
            $this->Link($action)
111
        );
112
    }
113
114
    /**
115
     * Default action this controller will deal with
116
     *
117
     * @param SS_HTTPRequest $request
118
     * @return string
0 ignored issues
show
Should the return type not be HTMLText?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
119
     */
120
    public function index(SS_HTTPRequest $request)
121
    {
122
        $this->customise(array(
123
            'Title'     => "Register",
124
            'ClassName' => 'RegisterPage',
125
            'Content'   => '',
126
            'Form'      => $this->RegisterForm(),
127
        ));
128
129
        $this->extend("updateIndexAction");
130
131
        return $this->renderWith(array(
132
            "Users_Register",
133
            "Users",
134
            "Page"
135
        ));
136
    }
137
138
139
    /**
140
     * Send a verification email to the user provided (if verification
141
     * emails are enabled and account is not already verified)
142
     *
143
     * @param SS_HTTPRequest $request
144
     * @return string
0 ignored issues
show
Should the return type not be HTMLText?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
145
     */
146
    public function sendverification(SS_HTTPRequest $request)
0 ignored issues
show
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
147
    {
148
        $sent = false;
149
150
        if (Member::currentUserID()) {
151
            $member = Member::currentUser();
152
        } else {
153
            $member = Member::get()->byID($this->request->param("ID"));
154
        }
155
156
        if ($member && !$member->isVerified() && Users::config()->send_verification_email) {
157
            $sent = $this->send_verification_email($member);
158
        } else {
159
            $sent = false;
160
        }
161
162
        $this->customise(array(
163
            "ClassName" => "RegisterPage",
164
            "Sent" => $sent
165
        ));
166
167
        return $this->renderWith(array(
168
            "Users_Register_sendverification",
169
            "Users",
170
            "Page"
171
        ));
172
    }
173
174
175
    /**
176
     * Verify the provided user (ID) using the verification code (Other
177
     * ID) provided
178
     *
179
     * @param SS_HTTPRequest $request
180
     * @return string
0 ignored issues
show
Should the return type not be HTMLText?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
181
     */
182
    public function verify(SS_HTTPRequest $request)
0 ignored issues
show
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
183
    {
184
        $member = Member::get()->byID($this->request->param("ID"));
185
        $code = $this->request->param("OtherID");
186
        $verify = false;
187
188
        // Check verification group exists, if not, make it
189
        // Add a verified users group (only used if we turn on
190
        // verification)
191
        $verify_groups = Group::get()
192
            ->filter("Code", Users::config()->verification_groups);
193
194
        $this->extend("onBeforeVerify", $member);
195
196
        if (($member && $code) && $code == $member->VerificationCode) {
197
            foreach ($verify_groups as $group) {
198
                $group->Members()->add($member);
199
                $verify = true;
200
            }
201
        }
202
203
        $this->customise(array(
204
            "ClassName" => "RegisterPage",
205
            "Verify" => $verify
206
        ));
207
208
        $this->extend("onAfterVerify", $member);
209
210
        return $this->renderWith(array(
211
            "Users_Register_verify",
212
            "Users",
213
            "Page"
214
        ));
215
    }
216
217
    /**
218
     * Registration form
219
     *
220
     * @return Form
221
     */
222
    public function RegisterForm()
223
    {
224
225
        // If back URL set, push to session
226
        if (isset($_REQUEST['BackURL'])) {
227
            Session::set('BackURL', $_REQUEST['BackURL']);
228
        }
229
230
        // Setup form fields
231
        $fields = FieldList::create(
232
            TextField::create("FirstName"),
233
            TextField::create("Surname"),
234
            EmailField::create("Email"),
235
            ConfirmedPasswordField::create("Password")
236
        );
237
238
        // Setup form actions
239
        $actions = new FieldList(
240
            FormAction::create("doRegister", "Register")
241
                ->addExtraClass("btn")
242
                ->addExtraClass("btn-green")
243
        );
244
245
        // Setup required fields
246
        $required = new RequiredFields(array(
247
            "FirstName",
248
            "Surname",
249
            "Email",
250
            "Password"
251
        ));
252
253
        $form = Form::create($this, "RegisterForm", $fields, $actions, $required)
254
            ->addExtraClass("forms")
255
            ->addExtraClass("forms-columnar");
256
257
        $this->extend("updateRegisterForm", $form);
258
259
        $session_data = Session::get("Form.{$form->FormName()}.data");
260
261
        if ($session_data && is_array($session_data)) {
262
            $form->loadDataFrom($session_data);
263
            Session::clear("Form.{$form->FormName()}.data");
264
        }
265
266
        return $form;
267
    }
268
269
    /**
270
     * Register a new member. This action is deigned to be intercepted at 2
271
     * points:
272
     *
273
     *  - Modify the initial member filter (so that you can perfom bespoke
274
     *    member filtering
275
     *
276
     *  - Modify the member user before saving (so we can add extra permissions
277
     *    etc)
278
     *
279
     * @param array $data User submitted data
280
     * @param Form $form Registration form
281
     */
282
    public function doRegister($data, $form)
283
    {
284
        $filter = array();
285
286
        if (isset($data['Email'])) {
287
            $filter['Email'] = $data['Email'];
288
        }
289
290
        $this->extend("updateMemberFilter", $filter);
291
292
        // Check if a user already exists
293
        if ($member = Member::get()->filter($filter)->first()) {
294
            if ($member) {
295
                $form->addErrorMessage(
296
                    "Blurb",
297
                    "Sorry, an account already exists with those details.",
298
                    "bad"
299
                );
300
301
                // Load errors into session and post back
302
                unset($data["Password"]);
303
                Session::set("Form.{$form->FormName()}.data", $data);
304
305
                return $this->redirectBack();
306
            }
307
        }
308
309
        $member = Member::create();
310
        $form->saveInto($member);
311
312
        // Set verification code for this user
313
        $member->VerificationCode = sha1(mt_rand() . mt_rand());
314
        $member->write();
315
316
        // Add member to any groups that have been specified
317
        if (count(Users::config()->new_user_groups)) {
318
            $groups = Group::get()->filter(array(
319
                "Code" => Users::config()->new_user_groups
320
            ));
321
322
            foreach ($groups as $group) {
323
                $group->Members()->add($member);
324
                $group->write();
325
            }
326
        }
327
328
        $this->extend("updateNewMember", $member, $data);
329
330
        // Send a verification email, if needed
331
        if (Users::config()->send_verification_email) {
332
            $this->send_verification_email($member);
333
        }
334
335
        // Login (if enabled)
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
336
        if (Users::config()->login_after_register) {
337
            $member->LogIn(isset($data['Remember']));
338
        }
339
340
        $session_url = Session::get("BackURL");
341
        $request_url = $this->getRequest()->requestVar("BackURL");
342
343
        // If a back URL is used in session.
344
        if (!empty($session_url)) {
345
            $redirect_url = $session_url;
346
        } elseif (!empty($request_url)) {
347
            $redirect_url = $request_url;
348
        } else {
349
            $controller = Injector::inst()->get("Users_Account_Controller");
350
            $redirect_url = $controller->Link();
351
        }
352
353
        return $this->redirect($redirect_url);
354
    }
355
}
356