Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 48 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
ReferenceClarifier | |
0.00% |
0 / 48 |
|
0.00% |
0 / 5 |
306 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getWhatLinksHereProps | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
30 | |||
getWikiReferences | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
getObjectLink | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 | |||
loadReferencesForPage | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | |
3 | namespace Flow; |
4 | |
5 | use Flow\Data\ManagerGroup; |
6 | use Flow\Exception\CrossWikiException; |
7 | use Flow\Model\Reference; |
8 | use Flow\Model\UUID; |
9 | use Flow\Model\WikiReference; |
10 | use MediaWiki\Title\Title; |
11 | use MediaWiki\WikiMap\WikiMap; |
12 | |
13 | class ReferenceClarifier { |
14 | /** @var ManagerGroup */ |
15 | protected $storage; |
16 | /** @var UrlGenerator */ |
17 | protected $urlGenerator; |
18 | /** @var WikiReference[][][] */ |
19 | protected $referenceCache; |
20 | |
21 | public function __construct( ManagerGroup $storage, UrlGenerator $urlGenerator ) { |
22 | $this->storage = $storage; |
23 | $this->urlGenerator = $urlGenerator; |
24 | $this->referenceCache = []; |
25 | } |
26 | |
27 | public function getWhatLinksHereProps( $row, Title $from, Title $to ) { |
28 | $ids = []; |
29 | $props = []; |
30 | $references = $this->getWikiReferences( $from, $to ); |
31 | |
32 | // Collect referenced workflow ids and load them so we can generate |
33 | // links to their pages |
34 | foreach ( $references as $reference ) { |
35 | $id = $reference->getWorkflowId(); |
36 | // utilize array key to de-duplicate |
37 | $ids[$id->getAlphadecimal()] = $id; |
38 | } |
39 | |
40 | // Don't need to do anything with them, they are automatically |
41 | // passed into url generator when loaded. |
42 | $this->storage->getMulti( 'Workflow', $ids ); |
43 | |
44 | // Messages that can be used here: |
45 | // * flow-whatlinkshere-header |
46 | // * flow-whatlinkshere-post |
47 | // * flow-whatlinkshere-post-summary |
48 | // Topic is plain text and do not have links. |
49 | foreach ( $references as $reference ) { |
50 | if ( $reference->getType() === WikiReference::TYPE_CATEGORY ) { |
51 | // While it might make sense to have backlinks from categories to |
52 | // a page in what links here, thats not what mediawiki currently does. |
53 | continue; |
54 | } |
55 | try { |
56 | $url = $this->getObjectLink( $reference->getWorkflowId(), $reference->getObjectType(), $reference->getObjectId() ); |
57 | $props[] = wfMessage( 'flow-whatlinkshere-' . $reference->getObjectType(), $url )->parse(); |
58 | } catch ( CrossWikiException $e ) { |
59 | // Ignore expected cross-wiki exception. |
60 | // Gerrit 136280 would add a wiki field to the query in |
61 | // loadReferencesForPage(), we can remove catching the exception |
62 | // in here once it's merged |
63 | } |
64 | } |
65 | |
66 | return $props; |
67 | } |
68 | |
69 | /** |
70 | * @param Title $from |
71 | * @param Title $to |
72 | * @return WikiReference[] |
73 | */ |
74 | public function getWikiReferences( Title $from, Title $to ) { |
75 | if ( !isset( $this->referenceCache[$from->getPrefixedDBkey()] ) ) { |
76 | $this->loadReferencesForPage( $from ); |
77 | } |
78 | |
79 | $fromT = $from->getPrefixedDBkey(); |
80 | $toT = 'title:' . $to->getPrefixedDBkey(); |
81 | |
82 | return $this->referenceCache[$fromT][$toT] ?? []; |
83 | } |
84 | |
85 | /** |
86 | * @param UUID $workflow |
87 | * @param string $objectType |
88 | * @param UUID $objectId |
89 | * @return string Full URL |
90 | */ |
91 | protected function getObjectLink( UUID $workflow, $objectType, UUID $objectId ) { |
92 | if ( $objectType === 'post' ) { |
93 | $anchor = $this->urlGenerator->postLink( null, $workflow, $objectId ); |
94 | } elseif ( $objectType === 'header' || $objectType === 'post-summary' ) { |
95 | $anchor = $this->urlGenerator->workflowLink( null, $workflow ); |
96 | } else { |
97 | wfDebugLog( 'Flow', __METHOD__ . ": Unknown \$objectType: $objectType" ); |
98 | $anchor = $this->urlGenerator->workflowLink( null, $workflow ); |
99 | } |
100 | |
101 | return $anchor->getFullURL(); |
102 | } |
103 | |
104 | protected function loadReferencesForPage( Title $from ) { |
105 | /** @var Reference[] $allReferences */ |
106 | $allReferences = []; |
107 | |
108 | foreach ( [ 'WikiReference', 'URLReference' ] as $refType ) { |
109 | // find() returns null for error or empty result |
110 | $res = $this->storage->find( |
111 | $refType, |
112 | [ |
113 | 'ref_src_wiki' => WikiMap::getCurrentWikiId(), |
114 | 'ref_src_namespace' => $from->getNamespace(), |
115 | 'ref_src_title' => $from->getDBkey(), |
116 | ] |
117 | ); |
118 | |
119 | if ( $res ) { |
120 | /* |
121 | * We're "cheating", we have no PK! |
122 | * We used to have a unique index (on all columns), but the size |
123 | * of the index was too small (urls can be pretty long...) |
124 | * We have no data integrity reasons to want to ensure unique |
125 | * entries, and the code actually does a good job of only |
126 | * inserting uniques. Still, I'll do a sanity check and get rid |
127 | * of duplicates, should there be any... |
128 | */ |
129 | $res = array_unique( $res ); |
130 | $allReferences = array_merge( $allReferences, $res ); |
131 | } |
132 | } |
133 | |
134 | $cache = []; |
135 | foreach ( $allReferences as $reference ) { |
136 | if ( !isset( $cache[$reference->getTargetIdentifier()] ) ) { |
137 | $cache[$reference->getTargetIdentifier()] = []; |
138 | } |
139 | |
140 | $cache[$reference->getTargetIdentifier()][] = $reference; |
141 | } |
142 | |
143 | $this->referenceCache[$from->getPrefixedDBkey()] = $cache; |
144 | } |
145 | } |