Completed
Push — master ( e24934...29b94d )
by
unknown
02:51
created

User::isBlocked()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
/**
3
 * This file contains only the User class.
4
 */
5
6
namespace Xtools;
7
8
use Exception;
9
use DateTime;
10
11
/**
12
 * A User is a wiki user who has the same username across all projects in an XTools installation.
13
 */
14
class User extends Model
15
{
16
17
    /** @var int The user's ID. */
18
    protected $id;
19
20
    /** @var string The user's username. */
21
    protected $username;
22
23
    /** @var string Expiry of the current block of the user */
24
    protected $blockExpiry;
25
26
    /**
27
     * Create a new User given a username.
28
     * @param string $username
29
     */
30
    public function __construct($username)
31
    {
32
        $this->username = ucfirst(trim($username));
33
    }
34
35
    /**
36
     * Get the username.
37
     * @return string
38
     */
39
    public function getUsername()
40
    {
41
        return $this->username;
42
    }
43
44
    /**
45
     * Get the user's ID on the given project.
46
     * @param Project $project
47
     * @return int
48
     */
49
    public function getId(Project $project)
50
    {
51
        return $this->getRepository()->getId($project->getDatabaseName(), $this->getUsername());
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xtools\Repository as the method getId() does only exist in the following sub-classes of Xtools\Repository: Xtools\UserRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
52
    }
53
54
    /**
55
     * Get a list of this user's groups on the given project.
56
     * @param Project $project The project.
57
     * @return string[]
58
     */
59
    public function getGroups(Project $project)
60
    {
61
        $groupsData = $this->getRepository()->getGroups($project, $this->getUsername());
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xtools\Repository as the method getGroups() does only exist in the following sub-classes of Xtools\Repository: Xtools\UserRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
62
        $groups = preg_grep('/\*/', $groupsData, PREG_GREP_INVERT);
63
        sort($groups);
64
        return $groups;
65
    }
66
67
    /**
68
     * Get a list of this user's groups on all projects.
69
     * @param Project $project A project to query; if not provided, the default will be used.
70
     */
71
    public function getGlobalGroups(Project $project = null)
72
    {
73
        return $this->getRepository()->getGlobalGroups($this->getUsername(), $project);
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xtools\Repository as the method getGlobalGroups() does only exist in the following sub-classes of Xtools\Repository: Xtools\UserRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
74
    }
75
76
    /**
77
     * Does this user exist on the given project.
78
     * @param Project $project
79
     * @return bool
80
     */
81
    public function existsOnProject(Project $project)
82
    {
83
        $id = $this->getId($project);
84
        return $id > 0;
85
    }
86
87
    /**
88
     * Is this user an Administrator on the given project?
89
     * @param Project $project The project.
90
     * @return bool
91
     */
92
    public function isAdmin(Project $project)
93
    {
94
        return (false !== array_search('sysop', $this->getGroups($project)));
95
    }
96
97
    /**
98
     * Is this user an anonymous user (IP)?
99
     * @return bool
100
     */
101
    public function isAnon()
102
    {
103
        return filter_var($this->username, FILTER_VALIDATE_IP);
104
    }
105
106
    /**
107
     * Get the expiry of the current block on the user
108
     * @param Project $project The project.
109
     * @return DateTime|bool Expiry as DateTime, true if indefinite,
110
     *                       or false if they are not blocked.
111
     */
112
    public function getBlockExpiry(Project $project)
113
    {
114
        if (isset($this->blockExpiry)) {
115
            return $this->blockExpiry;
116
        }
117
118
        $expiry = $this->getRepository()->getBlockExpiry(
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xtools\Repository as the method getBlockExpiry() does only exist in the following sub-classes of Xtools\Repository: Xtools\UserRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
119
            $project->getDatabaseName(),
120
            $this->getId($project)
121
        );
122
123
        if ($expiry === 'infinity') {
124
            $this->blockExpiry = true;
0 ignored issues
show
Documentation Bug introduced by
The property $blockExpiry was declared of type string, but true is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
125
        } elseif ($expiry === false) {
126
            $this->blockExpiry = false;
0 ignored issues
show
Documentation Bug introduced by
The property $blockExpiry was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
127
        } else {
128
            $this->blockExpiry = new DateTime($expiry);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \DateTime($expiry) of type object<DateTime> is incompatible with the declared type string of property $blockExpiry.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
129
        }
130
131
        return $this->blockExpiry;
132
    }
133
134
    /**
135
     * Is this user currently blocked on the given project?
136
     * @param Project $project The project.
137
     * @return bool
138
     */
139
    public function isBlocked(Project $project)
140
    {
141
        return $this->getBlockExpiry($project) !== false;
142
    }
143
144
    /**
145
     * Is this user the same as the current XTools user?
146
     * @return bool
147
     */
148
    public function isCurrentlyLoggedIn()
149
    {
150
        try {
151
            $ident = $this->getRepository()->getXtoolsUserInfo();
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xtools\Repository as the method getXtoolsUserInfo() does only exist in the following sub-classes of Xtools\Repository: Xtools\UserRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
152
        } catch (Exception $exception) {
153
            return false;
154
        }
155
        return isset($ident->username) && $ident->username === $this->getUsername();
156
    }
157
}
158