1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Xtools; |
4
|
|
|
|
5
|
|
|
use Mediawiki\Api\MediawikiApi; |
6
|
|
|
use Mediawiki\Api\SimpleRequest; |
7
|
|
|
use Symfony\Component\DependencyInjection\Container; |
8
|
|
|
|
9
|
|
|
class ProjectRepository extends Repository |
10
|
|
|
{ |
11
|
|
|
|
12
|
|
|
/** @var array Project metadata. */ |
13
|
|
|
protected $metadata; |
14
|
|
|
|
15
|
|
|
/** @var string[] */ |
16
|
|
|
protected $singleMetadata; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Convenience method to get a new Project object based on a given identification string. |
20
|
|
|
* @param string $projectIdent The domain name, database name, or URL of a project. |
21
|
|
|
* @param Container $container Symfony's container. |
22
|
|
|
* @return Project |
23
|
|
|
*/ |
24
|
|
|
public static function getProject($projectIdent, Container $container) |
25
|
|
|
{ |
26
|
|
|
$project = new Project($projectIdent); |
27
|
|
|
$projectRepo = new ProjectRepository(); |
28
|
|
|
$projectRepo->setContainer($container); |
29
|
|
|
if ($container->getParameter('app.single_wiki')) { |
30
|
|
|
$projectRepo->setSingleMetadata([ |
31
|
|
|
'url' => $container->getParameter('wiki_url'), |
32
|
|
|
'dbname' => $container->getParameter('database_replica_name'), |
33
|
|
|
]); |
34
|
|
|
} |
35
|
|
|
$project->setRepository($projectRepo); |
36
|
|
|
return $project; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Get the XTools default project. |
41
|
|
|
* @param Container $container |
42
|
|
|
* @return Project |
43
|
|
|
*/ |
44
|
|
|
public static function getDefaultProject(Container $container) |
45
|
|
|
{ |
46
|
|
|
$defaultProjectName = $container->getParameter('default_project'); |
47
|
|
|
return self::getProject($defaultProjectName, $container); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* For single-wiki installations, you must manually set the wiki URL and database name |
52
|
|
|
* (because there's no meta.wiki database to query). |
53
|
|
|
* @param $metadata |
54
|
|
|
* @throws \Exception |
55
|
|
|
*/ |
56
|
|
|
public function setSingleMetadata($metadata) |
57
|
|
|
{ |
58
|
|
|
if (!array_key_exists('url', $metadata) || !array_key_exists('dbname', $metadata)) { |
59
|
|
|
$error = "Single-wiki metadata should contain 'url' and 'dbname' keys."; |
60
|
|
|
throw new \Exception($error); |
61
|
|
|
} |
62
|
|
|
$this->singleMetadata = array_intersect_key($metadata, ['url' => '', 'dbname' => '']); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Get metadata about all projects. |
67
|
|
|
* @return string[] Each item has 'dbname' and 'url' keys. |
68
|
|
|
*/ |
69
|
|
|
public function getAll() |
70
|
|
|
{ |
71
|
|
|
if ($this->singleMetadata) { |
|
|
|
|
72
|
|
|
return [$this->getOne('')]; |
|
|
|
|
73
|
|
|
} |
74
|
|
|
$wikiQuery = $this->getMetaConnection()->createQueryBuilder(); |
75
|
|
|
$wikiQuery->select(['dbname', 'url'])->from('wiki'); |
76
|
|
|
return $wikiQuery->execute()->fetchAll(); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Get metadata about one project. |
81
|
|
|
* @param string $project A project URL, domain name, or database name. |
82
|
|
|
* @return string[] With 'dbname' and 'url' keys. |
83
|
|
|
*/ |
84
|
|
|
public function getOne($project) |
85
|
|
|
{ |
86
|
|
|
// For single-wiki setups, every project is the same. |
87
|
|
|
if ($this->singleMetadata) { |
|
|
|
|
88
|
|
|
return $this->singleMetadata; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
// For muli-wiki setups, first check the cache. |
92
|
|
|
$cacheKey = "project.$project"; |
93
|
|
|
if ($this->cache->hasItem($cacheKey)) { |
94
|
|
|
return $this->cache->getItem($cacheKey)->get(); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
// Otherwise, fetch the project's metadata from the meta.wiki table. |
98
|
|
|
$wikiQuery = $this->getMetaConnection()->createQueryBuilder(); |
99
|
|
|
$wikiQuery->select(['dbname', 'url']) |
100
|
|
|
->from('wiki') |
101
|
|
|
->where($wikiQuery->expr()->eq('dbname', ':project')) |
102
|
|
|
// The meta database will have the project's URL stored as https://en.wikipedia.org |
103
|
|
|
// so we need to query for it accordingly, trying different variations the user |
104
|
|
|
// might have inputted. |
105
|
|
|
->orwhere($wikiQuery->expr()->like('url', ':projectUrl')) |
106
|
|
|
->orwhere($wikiQuery->expr() |
107
|
|
|
->like('url', ':projectUrl2')) |
108
|
|
|
->setParameter('project', $project) |
109
|
|
|
->setParameter('projectUrl', "https://$project") |
110
|
|
|
->setParameter('projectUrl2', "https://$project.org"); |
111
|
|
|
$wikiStatement = $wikiQuery->execute(); |
112
|
|
|
|
113
|
|
|
// Fetch and cache the wiki data. |
114
|
|
|
$projectMetadata = $wikiStatement->fetch(); |
115
|
|
|
$cacheItem = $this->cache->getItem($cacheKey); |
116
|
|
|
$cacheItem->set($projectMetadata) |
117
|
|
|
->expiresAfter(new \DateInterval('PT1H')); |
118
|
|
|
$this->cache->save($cacheItem); |
119
|
|
|
|
120
|
|
|
return $projectMetadata; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Get metadata about a project. |
125
|
|
|
* |
126
|
|
|
* @param string $projectUrl The project's URL. |
127
|
|
|
* @return array With 'general' and 'namespaces' keys: the former contains 'wikiName', |
128
|
|
|
* 'wikiId', 'url', 'lang', 'articlePath', 'scriptPath', 'script', 'timezone', and |
129
|
|
|
* 'timezoneOffset'; the latter contains all namespace names, keyed by their IDs. |
130
|
|
|
*/ |
131
|
|
|
public function getMetadata($projectUrl) |
132
|
|
|
{ |
133
|
|
|
if ($this->metadata) { |
|
|
|
|
134
|
|
|
return $this->metadata; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
$api = MediawikiApi::newFromPage($projectUrl); |
138
|
|
|
|
139
|
|
|
$params = ['meta' => 'siteinfo', 'siprop' => 'general|namespaces']; |
140
|
|
|
$query = new SimpleRequest('query', $params); |
141
|
|
|
|
142
|
|
|
$this->metadata = [ |
143
|
|
|
'general' => [], |
144
|
|
|
'namespaces' => [], |
145
|
|
|
]; |
146
|
|
|
|
147
|
|
|
$res = $api->getRequest($query); |
148
|
|
|
|
149
|
|
|
if (isset($res['query']['general'])) { |
150
|
|
|
$info = $res['query']['general']; |
151
|
|
|
$this->metadata['general'] = [ |
152
|
|
|
'wikiName' => $info['sitename'], |
153
|
|
|
'wikiId' => $info['wikiid'], |
154
|
|
|
'url' => $info['server'], |
155
|
|
|
'lang' => $info['lang'], |
156
|
|
|
'articlePath' => $info['articlepath'], |
157
|
|
|
'scriptPath' => $info['scriptpath'], |
158
|
|
|
'script' => $info['script'], |
159
|
|
|
'timezone' => $info['timezone'], |
160
|
|
|
'timeOffset' => $info['timeoffset'], |
161
|
|
|
]; |
162
|
|
|
|
163
|
|
|
// if ($this->container->getParameter('app.is_labs') && |
|
|
|
|
164
|
|
|
// substr($result['general']['dbName'], -2) != '_p' |
165
|
|
|
// ) { |
166
|
|
|
// $result['general']['dbName'] .= '_p'; |
167
|
|
|
// } |
168
|
|
|
} |
169
|
|
|
|
170
|
|
View Code Duplication |
if (isset($res['query']['namespaces'])) { |
|
|
|
|
171
|
|
|
foreach ($res['query']['namespaces'] as $namespace) { |
172
|
|
|
if ($namespace['id'] < 0) { |
173
|
|
|
continue; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
if (isset($namespace['name'])) { |
177
|
|
|
$name = $namespace['name']; |
178
|
|
|
} elseif (isset($namespace['*'])) { |
179
|
|
|
$name = $namespace['*']; |
180
|
|
|
} else { |
181
|
|
|
continue; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
// FIXME: Figure out a way to i18n-ize this |
185
|
|
|
if ($name === '') { |
186
|
|
|
$name = 'Article'; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
$this->metadata['namespaces'][$namespace['id']] = $name; |
190
|
|
|
} |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
return $this->metadata; |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.