Completed
Push — master ( 946aec...bc2207 )
by mw
03:21
created

DatabaseLogReader::clearCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace SMW\ApprovedRevs;
4
5
use ArrayIterator;
6
use DatabaseLogEntry;
7
use DatabaseBase;
8
use MWTimestamp;
9
use Title;
10
use User;
11
12
class DatabaseLogReader {
13
14
	/**
15
	 * @var array
16
	 */
17
	private static $titleCache = [];
18
19
	/**
20
	 * @var DatabaseBase
21
	 */
22
	private $dbr;
23
24
	/**
25
	 * @var string
26
	 */
27
	private $query;
28
29
	/**
30
	 * @var string
31
	 */
32
	private $log;
33
34
	/**
35
	 * @var string
36
	 */
37
	private $dbKey;
38
39
	/**
40
	 * @var string
41
	 */
42
	private $type;
43
44
	/**
45
	 * @since 1.0
46
	 *
47
	 * @param DatabaseaBase $dbr injected connection
48
	 * @param Title|null $title
49
	 * @param string $type of log (default: approval)
50
	 */
51 6
	public function __construct( DatabaseBase $dbr, Title $title = null , $type = 'approval' ) {
52 6
		$this->dbr = $dbr;
53 6
		$this->dbKey = $title instanceof Title ? $title->getDBkey() : null;
0 ignored issues
show
Bug introduced by
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
54 6
		$this->type = $type;
55 6
	}
56
57
	/**
58
	 * @since 1.0
59
	 */
60 1
	public function clearCache() {
61 1
		self::$titleCache = [];
62 1
	}
63
64
	/**
65
	 * Fetch the query parameters for later calls
66
	 *
67
	 * @since 1.0
68
	 *
69
	 * @return array of parameters for SELECT call
70
	 */
71 5
	public function getQuery() {
72 5
		return $this->query;
73
	}
74
75
	/**
76
	 * @since 1.0
77
	 *
78
	 * @param Title|null $title
79
	 * @param string $type
80
	 *
81
	 * @return User
82
	 */
83 4
	public function getUserForLogEntry( Title $title = null, $type = 'approval' ) {
84
85 4
		$this->init( $title, $type );
86 4
		$logLine = $this->getLog()->current();
87
88 4
		if ( $logLine && $logLine->user_id ) {
89 2
			return User::newFromID( $logLine->user_id );
90
		}
91 2
	}
92
93
	/**
94
	 * @since 1.0
95
	 *
96
	 * @param Title|null $title
97
	 * @param string $type
98
	 *
99
	 * @return Timestamp
100
	 */
101 2
	public function getDateOfLogEntry( Title $title = null, $type = 'approval' ) {
102
103 2
		$this->init( $title, $type );
104 2
		$logLine = $this->getLog()->current();
105
106 2
		if ( $logLine && $logLine->log_timestamp ) {
107 1
			return new MWTimestamp( $logLine->log_timestamp );
108
		}
109 1
	}
110
111
	/**
112
	 * @since 1.0
113
	 *
114
	 * @param Title|null $title
115
	 * @param string $type
116
	 *
117
	 * @return string
118
	 */
119 2
	public function getStatusOfLogEntry( Title $title = null, $type = 'approval' ) {
120
121 2
		$this->init( $title, $type );
122 2
		$logLine = $this->getLog()->current();
123
124 2
		if ( $logLine && $logLine->log_action ) {
125 1
			return $logLine->log_action;
126
		}
127 1
	}
128
129
	/**
130
	 * Take care of loading from the cache or filling the query.
131
	 */
132 4
	private function init( $title, $type ) {
133
134 4
		$this->dbKey = $title instanceof Title ? $title->getDBkey() : null;
0 ignored issues
show
Bug introduced by
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
135 4
		$this->type = $type;
136
137 4
		if ( $this->query ) {
138 3
			return;
139
		}
140
141 4
		if ( !isset( self::$titleCache[ $this->dbKey . '#' . $this->type ] ) ) {
142 4
			$this->query = DatabaseLogEntry::getSelectQueryData();
143
144 4
			$this->query['conds'] = [
145 4
				'log_type' => $this->type,
146 4
				'log_title' => $this->dbKey
147
			];
148 4
			$this->query['options'] = [ 'ORDER BY' => 'log_timestamp desc' ];
149 4
			self::$titleCache[ $this->dbKey ] = $this;
150
		} else {
151
			$cache = self::$titleCache[ $this->dbKey . '#' . $this->type ];
152
			$this->query = $cache->getQuery();
153
			$this->log = $cache->getLog();
154
		}
155
156 4
	}
157
158
	/**
159
	 * Fetch the results using our conditions
160
	 *
161
	 * @return IResultWrapper
162
	 * @throws DBError
163
	 */
164 4
	private function getLog() {
165
166 4
		if ( $this->log !== null ) {
167 3
			return $this->log;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->log; (string) is incompatible with the return type documented by SMW\ApprovedRevs\DatabaseLogReader::getLog of type SMW\ApprovedRevs\IResultWrapper.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
168
		}
169
170 4
		$query = $this->getQuery();
171
172 4
		$this->log = $this->dbr->select(
173 4
			$query['tables'],
174 4
			$query['fields'],
175 4
			$query['conds'],
176 4
			__METHOD__,
177 4
			$query['options'],
178 4
			$query['join_conds']
179
		);
180
181 4
		if ( $this->log === null ) {
182
			$this->log = new ArrayIterator(
0 ignored issues
show
Documentation Bug introduced by
It seems like new \ArrayIterator(array...'log_action' => null))) of type object<ArrayIterator> is incompatible with the declared type string of property $log.

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...
183
				[ (object)[
184
					'user_id' => null,
185
					'log_timestamp' => null,
186
					'log_action' => null
187
				] ]
188
			);
189
		}
190
191 4
		return $this->log;
192
	}
193
194
}
195