Passed
Push — master ( 8b9089...a51f69 )
by MusikAnimal
01:23
created

Project::getCacheKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * This file contains only the Project class.
4
 */
5
6
namespace Xtools;
7
8
use Mediawiki\Api\MediawikiApi;
9
use Symfony\Component\VarDumper\VarDumper;
10
11
/**
12
 * A Project is a single wiki that XTools is querying.
13
 */
14
class Project extends Model
15
{
16
17
    /** @var string The project name as supplied by the user. */
18
    protected $nameUnnormalized;
19
20
    /** @var string[] Basic metadata about the project */
21
    protected $metadata;
22
23
    /** @var string[] Project's 'dbName', 'url' and 'lang'. */
24
    protected $basicInfo;
25
26
    /**
27
     * Whether the user being queried for in this session
28
     *   has opted in to restricted statistics
29
     * @var bool
30
     */
31
    protected $userOptedIn;
32
33
    /**
34
     * Create a new Project.
35
     * @param string $nameOrUrl The project's database name or URL.
36
     */
37 85
    public function __construct($nameOrUrl)
38
    {
39 85
        $this->nameUnnormalized = $nameOrUrl;
40 85
    }
41
42
    /**
43
     * Unique identifier this Project, to be used in cache keys.
44
     * @see Repository::getCacheKey()
45
     * @return string
46
     */
47
    public function getCacheKey()
48
    {
49
        return $this->getDatabaseName();
50
    }
51
52
    /**
53
     * Get 'dbName', 'url' and 'lang' of the project, the relevant basic info
54
     *   we can get from the meta database. This is all you need to make
55
     *   database queries. More comprehensive metadata can be fetched with
56
     *   getMetadata() at the expense of an API call, which may be cached.
57
     * @return string[]
58
     */
59 39
    protected function getBasicInfo()
60
    {
61 39
        if (empty($this->basicInfo)) {
62 39
            $this->basicInfo = $this->getRepository()->getOne($this->nameUnnormalized);
63
        }
64 38
        return $this->basicInfo;
65
    }
66
67
    /**
68
     * Get full metadata about the project. See ProjectRepository::getMetadata
69
     *   for more information.
70
     * @return string[]
71
     */
72 15
    protected function getMetadata()
73
    {
74 15
        if (empty($this->metadata)) {
75 15
            $url = $this->getBasicInfo()['url'];
76 14
            $this->metadata = $this->getRepository()->getMetadata($url);
77
        }
78 14
        return $this->metadata;
79
    }
80
81
    /**
82
     * Does this project exist?
83
     * @return bool
84
     */
85 8
    public function exists()
86
    {
87 8
        return !empty($this->getDomain());
88
    }
89
90
    /**
91
     * The unique domain name of this project, without protocol or path components.
92
     * This should be used as the canonical project identifier.
93
     *
94
     * @return string
95
     */
96 19
    public function getDomain()
97
    {
98 19
        $url = isset($this->getBasicInfo()['url']) ? $this->getBasicInfo()['url'] : '';
99 19
        return parse_url($url, PHP_URL_HOST);
100
    }
101
102
    /**
103
     * The name of the database for this project.
104
     *
105
     * @return string
106
     */
107 13
    public function getDatabaseName()
108
    {
109 13
        return isset($this->getBasicInfo()['dbName']) ? $this->getBasicInfo()['dbName'] : '';
110
    }
111
112
    /**
113
     * The language for this project.
114
     *
115
     * @return string
116
     */
117 2
    public function getLang()
118
    {
119 2
        return isset($this->getBasicInfo()['lang']) ? $this->getBasicInfo()['lang'] : '';
120
    }
121
122
    /**
123
     * The project URL is the fully-qualified domain name, with protocol and trailing slash.
124
     *
125
     * @param bool $withTrailingSlash Whether to append a slash.
126
     * @return string
127
     */
128 13
    public function getUrl($withTrailingSlash = true)
129
    {
130 13
        return rtrim($this->getBasicInfo()['url'], '/') . ($withTrailingSlash ? '/' : '');
131
    }
132
133
    /**
134
     * Get a MediawikiApi object for this Project.
135
     *
136
     * @return MediawikiApi
137
     */
138
    public function getApi()
139
    {
140
        return $this->getRepository()->getMediawikiApi($this);
141
    }
142
143
    /**
144
     * The base URL path of this project (that page titles are appended to).
145
     * For some wikis the title (apparently) may not be at the end.
146
     * Replace $1 with the article name.
147
     *
148
     * @link https://www.mediawiki.org/wiki/Manual:$wgArticlePath
149
     *
150
     * @return string
151
     */
152 4 View Code Duplication
    public function getArticlePath()
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...
153
    {
154 4
        $metadata = $this->getMetadata();
155 4
        return isset($metadata['general']['articlePath'])
156 4
            ? $metadata['general']['articlePath']
157 4
            : '/wiki/$1';
158
    }
159
160
    /**
161
     * The URL path of the directory that contains index.php, with no trailing slash.
162
     * Defaults to '/w' which is the same as the normal WMF set-up.
163
     *
164
     * @link https://www.mediawiki.org/wiki/Manual:$wgScriptPath
165
     *
166
     * @return string
167
     */
168 2 View Code Duplication
    public function getScriptPath()
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...
169
    {
170 2
        $metadata = $this->getMetadata();
171 2
        return isset($metadata['general']['scriptPath'])
172 2
            ? $metadata['general']['scriptPath']
173 2
            : '/w';
174
    }
175
176
    /**
177
     * The URL path to index.php
178
     * Defaults to '/w/index.php' which is the same as the normal WMF set-up.
179
     *
180
     * @return string
181
     */
182 1
    public function getScript()
183
    {
184 1
        $metadata = $this->getMetadata();
185 1
        return isset($metadata['general']['script'])
186 1
            ? $metadata['general']['script']
187 1
            : $this->getScriptPath() . '/index.php';
188
    }
189
190
    /**
191
     * The full URL to api.php
192
     *
193
     * @return string
194
     */
195 6
    public function getApiUrl()
196
    {
197 6
        return rtrim($this->getUrl(), '/') . $this->getRepository()->getApiPath();
198
    }
199
200
    /**
201
     * Get this project's title, the human-language full title of the wiki (e.g. "English
202
     * Wikipedia" or
203
     */
204 1
    public function getTitle()
205
    {
206 1
        $metadata = $this->getMetadata();
207
        return $metadata['general']['wikiName'].' ('.$this->getDomain().')';
208
    }
209
210
    /**
211
     * Get an array of this project's namespaces and their IDs.
212
     *
213
     * @return string[] Keys are IDs, values are names.
214
     */
215 8
    public function getNamespaces()
216
    {
217 8
        $metadata = $this->getMetadata();
218 8
        return $metadata['namespaces'];
219
    }
220
221
    /**
222
     * Get the title of the Main Page.
223
     * @return string
224
     */
225 1 View Code Duplication
    public function getMainPage()
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...
226
    {
227 1
        $metadata = $this->getMetadata();
228 1
        return isset($metadata['general']['mainpage'])
229 1
            ? $metadata['general']['mainpage']
230 1
            : '';
231
    }
232
233
    /**
234
     * Get a list of users who are in one of the given user groups.
235
     * @param string[] User groups to search for.
236
     * @return string[] User groups keyed by user name.
237
     */
238 1
    public function getUsersInGroups($groups)
239
    {
240 1
        $users = [];
241 1
        $usersAndGroups = $this->getRepository()->getUsersInGroups($this, $groups);
242 1
        foreach ($usersAndGroups as $userAndGroup) {
243 1
            $username = $userAndGroup['user_name'];
244 1
            if (isset($users[$username])) {
245 1
                array_push($users[$username], $userAndGroup['ug_group']);
246
            } else {
247 1
                $users[$username] = [$userAndGroup['ug_group']];
248
            }
249
        }
250 1
        return $users;
251
    }
252
253
    /**
254
     * Get the name of the page on this project that the user must create in order to opt in for
255
     * restricted statistics display.
256
     * @param User $user
257
     * @return string
258
     */
259 2
    public function userOptInPage(User $user)
260
    {
261 2
        $localPageName = 'User:' . $user->getUsername() . '/EditCounterOptIn.js';
262 2
        return $localPageName;
263
    }
264
265
    /**
266
     * Has a user opted in to having their restricted statistics displayed to anyone?
267
     * @param User $user
268
     * @return bool
269
     */
270 3
    public function userHasOptedIn(User $user)
271
    {
272
        // 1. First check to see if the whole project has opted in.
273 3
        if (!$this->userOptedIn) {
274 3
            $optedInProjects = $this->getRepository()->optedIn();
275 3
            $this->userOptedIn = in_array($this->getDatabaseName(), $optedInProjects);
276
        }
277 3
        if ($this->userOptedIn) {
278 1
            return true;
279
        }
280
281
        // 2. Then see if the currently-logged-in user is requesting their own statistics.
282 2
        if ($user->isCurrentlyLoggedIn()) {
283
            return true;
284
        }
285
286
        // 3. Then see if the user has opted in on this project.
287 2
        $userNsId = 2;
288
        // Remove namespace since we're querying the database and supplying a namespace ID.
289 2
        $optInPage = preg_replace('/^User:/', '', $this->userOptInPage($user));
290 2
        $localExists = $this->getRepository()->pageHasContent($this, $userNsId, $optInPage);
291 2
        if ($localExists) {
292
            return true;
293
        }
294
295
        // 4. Lastly, see if they've opted in globally on the default project or Meta.
296 2
        $globalPageName = $user->getUsername() . '/EditCounterGlobalOptIn.js';
297 2
        $globalProject = $this->getRepository()->getGlobalProject();
298 2
        if ($globalProject instanceof Project) {
299
            $globalExists = $globalProject->getRepository()
300
                ->pageHasContent($globalProject, $userNsId, $globalPageName);
301
            if ($globalExists) {
302
                return true;
303
            }
304
        }
305
306 2
        return false;
307
    }
308
309
    /**
310
     * Does this project support page assessments?
311
     * @return bool
312
     */
313 2
    public function hasPageAssessments()
314
    {
315 2
        return (bool) $this->getRepository()->getAssessmentsConfig($this->getDomain());
316
    }
317
318
    /**
319
     * Get the image URL of the badge for the given page assessment
320
     * @param  string $class  Valid classification for project, such as 'Start', 'GA', etc.
321
     * @return string         URL to image
322
     */
323 2
    public function getAssessmentBadgeURL($class)
324
    {
325 2
        $config = $this->getRepository()->getAssessmentsConfig($this->getDomain());
326
327 2
        if (isset($config['class'][$class])) {
328 2
            return "https://upload.wikimedia.org/wikipedia/commons/" . $config['class'][$class]['badge'];
329 2
        } elseif (isset($config['class']['Unknown'])) {
330 2
            return "https://upload.wikimedia.org/wikipedia/commons/" . $config['class']['Unknown']['badge'];
331
        } else {
332
            return "";
333
        }
334
    }
335
336
    /**
337
     * Normalize and quote a table name for use in SQL.
338
     * @param string $tableName
339
     * @param string|null $tableExtension Optional table extension, which will only get used if we're on Labs.
340
     * @return string Fully-qualified and quoted table name.
341
     */
342 1
    public function getTableName($tableName, $tableExtension = null)
343
    {
344 1
        return $this->getRepository()->getTableName($this->getDatabaseName(), $tableName, $tableExtension);
345
    }
346
}
347