Completed
Push — 1 ( 09ec5d...553b9e )
by Morven
03:37
created

Users_Register_Controller::Menu()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
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
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
15
{
16
17
    /**
18
     * URL That you can access this from
19
     *
20
     * @config
21
     */
22
    private static $url_segment = "users/register";
0 ignored issues
show
Unused Code introduced by
The property $url_segment is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
23
24
    /**
25
     * Current actions available to this controller
26
     *
27
     * @var array
28
     */
29
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
Unused Code introduced by
The property $allowed_actions is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
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->exists()) {
46
            return $member->sendVerificationEmail();            
47
        }
48
49
        return false;
50
    }
51
52
    /**
53
     * Get the link to this controller
54
     * 
55
     * @param string $action
0 ignored issues
show
Documentation introduced by
Should the type for parameter $action not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
56
     * @return string
57
     */
58
    public function Link($action = null)
59
    {
60
        return Controller::join_links(
61
            $this->config()->url_segment,
62
            $action
63
        );
64
    }
65
66
    /**
67
     * Get an absolute link to this controller
68
     *
69
     * @param string $action
0 ignored issues
show
Documentation introduced by
Should the type for parameter $action not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
70
     * @return false|string
71
     */
72
    public function AbsoluteLink($action = null)
73
    {
74
        return Director::absoluteURL($this->Link($action));
75
    }
76
77
    /**
78
     * Get a relative (to the root url of the site) link to this
79
     * controller
80
     *
81
     * @param string $action
0 ignored issues
show
Documentation introduced by
Should the type for parameter $action not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
82
     * @return string
83
     */
84
    public function RelativeLink($action = null)
85
    {
86
        return Controller::join_links(
87
            $this->Link($action)
88
        );
89
    }
90
91
    /**
92
     * If content controller exists, return it's menu function
93
     * @param int $level Menu level to return.
94
     * @return ArrayList
95
     */
96 View Code Duplication
    public function getMenu($level = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
97
    {
98
        if (class_exists(ContentController::class)) {
99
            $controller = Injector::inst()->get(ContentController::class);
100
            return $controller->getMenu($level);
101
        }
102
    }
103
104
    public function Menu($level)
0 ignored issues
show
Unused Code introduced by
The parameter $level 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...
105
    {
106
        return $this->getMenu();
107
    }
108
109
    /**
110
     * Default action this controller will deal with
111
     *
112
     * @param SS_HTTPRequest $request
113
     * @return HTMLText
114
     */
115
    public function index(SS_HTTPRequest $request)
0 ignored issues
show
Unused Code introduced by
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...
116
    {
117
        $this->customise(array(
118
            'Title'     => _t('Users.Register', 'Register'),
119
            'MetaTitle' => _t('Users.Register', 'Register'),
120
            'Form'      => $this->RegisterForm(),
121
        ));
122
123
        $this->extend("updateIndexAction");
124
125
        return $this->renderWith(array(
126
            "Users_Register",
127
            "Users",
128
            "Page"
129
        ));
130
    }
131
132
133
    /**
134
     * Send a verification email to the user provided (if verification
135
     * emails are enabled and account is not already verified)
136
     *
137
     * @param SS_HTTPRequest $request
138
     * @return HTMLText
139
     */
140
    public function sendverification(SS_HTTPRequest $request)
0 ignored issues
show
Unused Code introduced by
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...
141
    {
142
        // If we don't allow verification emails, return an error
143
        if (!Users::config()->send_verification_email) {
144
            return $this->httpError(400);
145
        }
146
147
        $sent = false;
148
149
        if (Member::currentUserID()) {
150
            $member = Member::currentUser();
151
        } else {
152
            $member = Member::get()->byID($this->getRequest()->param("ID"));
153
        }
154
155
        if ($member && !$member->isVerified()) {
156
            $sent = $this->send_verification_email($member);
157
        }
158
159
        $this->customise(array(
160
            "Title" => _t('Users.AccountVerification','Account Verification'),
161
            "MetaTitle" => _t('Users.AccountVerification','Account Verification'),
162
            "Content" => $this->renderWith(
163
                "UsersSendVerificationContent",
164
                array("Sent" => $sent)
165
            ),
166
            "Sent" => $sent
167
        ));
168
169
        $this->extend("updateSendVerificationAction");
170
171
        return $this->renderWith(array(
172
            "Users_Register_sendverification",
173
            "Users",
174
            "Page"
175
        ));
176
    }
177
178
179
    /**
180
     * Verify the provided user (ID) using the verification code (Other
181
     * ID) provided
182
     *
183
     * @param SS_HTTPRequest $request
184
     * @return HTMLText
185
     */
186
    public function verify(SS_HTTPRequest $request)
0 ignored issues
show
Unused Code introduced by
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...
187
    {   
188
        $member = Member::get()->byID($this->getRequest()->param("ID"));
189
        $code = $this->getRequest()->param("OtherID");
190
        $verify = false;
191
192
        // Check verification group exists, if not, make it
193
        // Add a verified users group (only used if we turn on
194
        // verification)
195
        $verify_groups = Group::get()
196
            ->filter("Code", Users::config()->verification_groups);
197
198
        $this->extend("onBeforeVerify", $member);
199
200
        if (($member && $code) && $code == $member->VerificationCode) {
201
            foreach ($verify_groups as $group) {
202
                $group->Members()->add($member);
203
                $verify = true;
204
            }
205
        }
206
207
        $this->customise(array(
208
            "Title" => _t('Users.AccountVerification','Account Verification'),
209
            "MetaTitle" => _t('Users.AccountVerification','Account Verification'),
210
            "Content" => $this->renderWith(
211
                "UsersVerifyContent",
212
                array("Verify" => $verify)
213
            ),
214
            "Verify" => $verify
215
        ));
216
217
        $this->extend("onAfterVerify", $member);
218
219
        return $this->renderWith(array(
220
            "Users_Register_verify",
221
            "Users",
222
            "Page"
223
        ));
224
    }
225
226
    /**
227
     * Registration form
228
     *
229
     * @return Form
230
     */
231
    public function RegisterForm()
0 ignored issues
show
Coding Style introduced by
RegisterForm uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
232
    {
233
234
        // If back URL set, push to session
235
        if (isset($_REQUEST['BackURL'])) {
236
            Session::set('BackURL', $_REQUEST['BackURL']);
237
        }
238
239
        $config = Users::config();
240
241
        // Setup form fields
242
        $fields = FieldList::create(
243
            TextField::create("FirstName"),
244
            TextField::create("Surname"),
245
            EmailField::create("Email"),
246
            $password_field = ConfirmedPasswordField::create("Password")
247
        );
248
249
        $password_field->minLength = $config->get("password_min_length");
250
        $password_field->maxLength = $config->get("password_max_length");
251
        $password_field->requireStrongPassword = $config->get("password_require_strong");
252
253
        // Setup form actions
254
        $actions = new FieldList(
255
            FormAction::create("doRegister", "Register")
256
                ->addExtraClass("btn")
257
                ->addExtraClass("btn-green")
258
        );
259
260
        // Setup required fields
261
        $required = new RequiredFields(array(
262
            "FirstName",
263
            "Surname",
264
            "Email",
265
            "Password"
266
        ));
267
268
        $form = Form::create(
269
            $this,
270
            "RegisterForm",
271
            $fields,
272
            $actions,
273
            $required
274
        )->addExtraClass("forms")
275
        ->addExtraClass("forms-columnar");
276
277
        $this->extend("updateRegisterForm", $form);
278
279
        $session_data = Session::get("Form.{$form->FormName()}.data");
280
281
        if ($session_data && is_array($session_data)) {
282
            $form->loadDataFrom($session_data);
283
            Session::clear("Form.{$form->FormName()}.data");
284
        }
285
286
        return $form;
287
    }
288
289
    /**
290
     * Register a new member. This action is deigned to be intercepted at 2
291
     * points:
292
     *
293
     *  - Modify the initial member filter (so that you can perfom bespoke
294
     *    member filtering
295
     *
296
     *  - Modify the member user before saving (so we can add extra permissions
297
     *    etc)
298
     *
299
     * @param array $data User submitted data
300
     * @param Form $form Registration form
301
     */
302
    public function doRegister($data, $form)
303
    {
304
        $filter = array();
305
306
        if (isset($data['Email'])) {
307
            $filter['Email'] = $data['Email'];
308
        }
309
310
        $this->extend("updateMemberFilter", $filter);
311
312
        // Check if a user already exists
313
        if ($member = Member::get()->filter($filter)->first()) {
314
            if ($member) {
315
                $form->addErrorMessage(
316
                    "Blurb",
317
                    "Sorry, an account already exists with those details.",
318
                    "bad"
319
                );
320
321
                // Load errors into session and post back
322
                unset($data["Password"]);
323
                Session::set("Form.{$form->FormName()}.data", $data);
0 ignored issues
show
Documentation introduced by
$data is of type array<string,?,{"Email":"?"}>, 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...
324
325
                return $this->redirectBack();
326
            }
327
        }
328
329
        $member = Member::create();
330
        $member->Register($data);
0 ignored issues
show
Bug introduced by
The method Register() does not exist on Member. Did you maybe mean registerFailedLogin()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
331
332
        $this->extend("updateNewMember", $member, $data);
333
334
        $session_url = Session::get("BackURL");
335
        $request_url = $this->getRequest()->requestVar("BackURL");
336
337
        // If a back URL is used in session.
338
        if (!empty($session_url)) {
339
            $redirect_url = $session_url;
340
        } elseif (!empty($request_url)) {
341
            $redirect_url = $request_url;
342
        } else {
343
            $controller = Injector::inst()->get("Users_Account_Controller");
344
            $redirect_url = $controller->Link();
345
        }
346
347
        return $this->redirect($redirect_url);
348
    }
349
}
350