Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
37.50% covered (danger)
37.50%
15 / 40
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserTuple
37.50% covered (danger)
37.50%
15 / 40
20.00% covered (danger)
20.00%
1 / 5
191.04
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
12
 newFromUser
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 newFromArray
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
56
 toArray
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 createUser
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace Flow\Model;
4
5use Flow\Exception\CrossWikiException;
6use Flow\Exception\FlowException;
7use Flow\Exception\InvalidDataException;
8use MediaWiki\User\User;
9use MediaWiki\WikiMap\WikiMap;
10
11/**
12 * Small value object holds the values necessary to uniquely identify
13 * a user across multiple wiki's.
14 */
15class UserTuple {
16    /**
17     * @var string The wiki the user belongs to
18     */
19    public $wiki;
20
21    /**
22     * @var int The id of the user, or 0 for anonymous
23     */
24    public $id;
25
26    /**
27     * @var string|null The ip of the user, null if logged in.
28     */
29    public $ip;
30
31    /**
32     * @param string $wiki The wiki the user belongs to
33     * @param int|string $id The id of the user, or 0 for anonymous
34     * @param string|null $ip The ip of the user, blank string for no ip.
35     *  null special case pass-through to be removed.
36     * @throws InvalidDataException
37     */
38    public function __construct( $wiki, $id, $ip ) {
39        if ( !is_int( $id ) ) {
40            if ( ctype_digit( (string)$id ) ) {
41                $id = (int)$id;
42            } else {
43                throw new InvalidDataException( 'User id must be an integer' );
44            }
45        }
46        if ( $id < 0 ) {
47            throw new InvalidDataException( 'User id must be >= 0' );
48        }
49        if ( !$wiki ) {
50            throw new InvalidDataException( 'No wiki provided' );
51        }
52        if ( $id === 0 && ( $ip === null || strlen( $ip ) === 0 ) ) {
53            throw new InvalidDataException( 'User has no id and no ip' );
54        }
55        if ( $id !== 0 && $ip && strlen( $ip ) !== 0 ) {
56            throw new InvalidDataException( 'User has both id and ip' );
57        }
58        // @todo assert ip is ipv4 or ipv6, but do we really want
59        // that on every anon user we load from storage?
60
61        $this->wiki = $wiki;
62        $this->id = $id;
63        $this->ip = (string)$ip ?: null;
64    }
65
66    public static function newFromUser( User $user ) {
67        return new self(
68            WikiMap::getCurrentWikiId(),
69            $user->getId(),
70            $user->isRegistered() ? null : $user->getName()
71        );
72    }
73
74    public static function newFromArray( array $user, $prefix = '' ) {
75        $wiki = "{$prefix}wiki";
76        $id = "{$prefix}id";
77        $ip = "{$prefix}ip";
78
79        if (
80            isset( $user[$wiki] )
81            && array_key_exists( $id, $user ) && array_key_exists( $ip, $user )
82            // $user[$id] === 0 is special case when when IRC formatter mocks up objects
83            && ( $user[$id] || $user[$ip] || $user[$id] === 0 )
84        ) {
85            return new self( $user["{$prefix}wiki"], $user["{$prefix}id"], $user["{$prefix}ip"] );
86        } else {
87            return null;
88        }
89    }
90
91    public function toArray( $prefix = '' ) {
92        return [
93            "{$prefix}wiki" => $this->wiki,
94            "{$prefix}id" => $this->id,
95            "{$prefix}ip" => $this->ip
96        ];
97    }
98
99    public function createUser() {
100        if ( $this->wiki !== WikiMap::getCurrentWikiId() ) {
101            throw new CrossWikiException( 'Can only retrieve same-wiki users' );
102        }
103        if ( $this->id ) {
104            return User::newFromId( $this->id );
105        } elseif ( !$this->ip ) {
106            throw new FlowException( 'Either $userId or $userIp must be set.' );
107        } else {
108            return User::newFromName( $this->ip, /* $validate = */ false );
109        }
110    }
111}