Completed
Push — master ( fe21f6...32ec36 )
by Konstantinos
03:59
created

ProfileController   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 120
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 66.67%
Metric Value
wmc 16
lcom 1
cbo 12
dl 0
loc 120
ccs 2
cts 3
cp 0.6667
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setup() 0 4 1
C editAction() 0 39 7
A confirmAction() 0 20 4
A showAction() 0 4 1
B sendConfirmationMessage() 0 29 3
1
<?php
2
3
use BZIon\Form\Creator\ProfileFormCreator;
4
use Symfony\Component\HttpFoundation\RedirectResponse;
5
use Symfony\Component\HttpFoundation\Request;
6
7
class ProfileController extends HTMLController
8
{
9 1
    public function setup()
10
    {
11 1
        $this->requireLogin();
12
    }
13
14
    /**
15
     * Edit a profile
16
     *
17
     * @param  Player  $me      The player's profile to edit
18
     * @param  Request $request
19
     * @param  bool $self    Whether a player is editing their own profile,
20
     *                          instead of an admin editing another player's
21
     *                          profile
22
     * @return array
23
     */
24
    public function editAction(Player $me, Request $request, $self = true)
25
    {
26
        $creator = new ProfileFormCreator($me);
27
        $creator->setEditingSelf($self);
28
        $form = $creator->create()->handleRequest($request);
29
30
        if ($form->isValid()) {
31
            if (!$self && $form->has('verify_email') && $form->get('verify_email')->isClicked()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Symfony\Component\Form\FormInterface as the method isClicked() does only exist in the following implementations of said interface: Symfony\Component\Form\SubmitButton.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
32
                // An admin is editing a form and has chosen to verify a
33
                // player's e-mail address
34
                $me->setVerified(true);
35
36
                // Reset the form so that the "verify email" button gets hidden
37
                $form = $creator->create()->handleRequest($request);
38
            } else {
39
                $creator->update($form, $me);
40
41
                $email = $form->get('email')->getData();
42
                if ($email !== $me->getEmailAddress()) {
43
                    // User has changed their address, send a confirmation mail
44
                    $me->setEmailAddress($email);
45
46
                    if ($self) {
47
                        $this->sendConfirmationMessage($me);
48
                    } else {
49
                        // Admins can set users' e-mail addresses at will, without
50
                        // having to send them confirmation messages
51
                        $me->setVerified(true);
52
                    }
53
                }
54
            }
55
        }
56
57
        return $this->render('Profile/edit.html.twig', array(
58
            "editingSelf" => $self,
59
            "player"      => $me,
60
            "form"        => $form->createView()
61
        ));
62
    }
63
64
    /**
65
     * @todo Expire verification codes
66
     */
67
    public function confirmAction(Player $me, $token)
68
    {
69
        if (!$me->getEmailAddress()) {
70
            throw new ForbiddenException("You need to have an e-mail address to confirm!");
71
        }
72
73
        if ($me->isVerified()) {
74
            throw new ForbiddenException("You have already been verified");
75
        }
76
77
        if (!$me->isCorrectConfirmCode($token)) {
78
            throw new ForbiddenException("Invalid verification code");
79
        }
80
81
        $me->setVerified(true);
82
83
        $this->getFlashBag()->add('success', "Your e-mail address has been successfully verified");
84
85
        return new RedirectResponse($me->getUrl());
86
    }
87
88
    public function showAction(Player $me)
89
    {
90
        return new RedirectResponse($me->getUrl());
91
    }
92
93
    /**
94
     * Send a confirmation e-mail to a player
95
     * @param Player $player The receiving player
96
     */
97
    private function sendConfirmationMessage($player)
98
    {
99
        if ($player->getConfirmCode() === null) {
100
            // The player has no confirmation code, don't send them a message
101
            return;
102
        }
103
104
        $from = $this->container->getParameter('bzion.email.from');
105
        $title = $this->container->getParameter('bzion.site.name');
106
107
        if (!$from) {
108
            $this->getLogger()->addError('Unable to send verification e-mail message to player due to the "From:" address not being specified', array(
109
                'player' => array('id' => $player->getId(), 'username' => $player->getUsername())
110
            ));
111
            return;
112
        }
113
114
        $message = Swift_Message::newInstance()
115
            ->setSubject($title . ' Email Confirmation')
116
            ->setFrom(array($from => $title))
117
            ->setTo($player->getEmailAddress())
118
            ->setBody($this->render('Email/confirm.txt.twig',  array('player' => $player)))
119
            ->addPart($this->render('Email/confirm.html.twig', array('player' => $player)), 'text/html');
120
121
        $this->container->get('mailer')->send($message);
122
123
        $this->getFlashBag()->add('info',
124
            'Please check your inbox in order to confirm your email address.');
125
    }
126
}
127