Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.98% covered (success)
92.98%
53 / 57
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
CognateRepo
92.98% covered (success)
92.98%
53 / 57
66.67% covered (warning)
66.67%
4 / 6
11.04
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 setStatsdDataFactory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 savePage
90.00% covered (success)
90.00%
18 / 20
0.00% covered (danger)
0.00%
0 / 1
3.01
 deletePage
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
3.10
 getLinksForPage
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 invalidateAllSitesForPage
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Cognate;
4
5use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
6use MediaWiki\Linker\LinkTarget;
7use MediaWiki\Title\TitleFormatter;
8use NullStatsdDataFactory;
9use Psr\Log\LoggerInterface;
10use StatsdAwareInterface;
11use Wikimedia\Rdbms\DBReadOnlyError;
12
13/**
14 * @license GPL-2.0-or-later
15 * @author Addshore
16 */
17class CognateRepo implements StatsdAwareInterface {
18
19    /**
20     * @var CognateStore
21     */
22    private $store;
23
24    /**
25     * @var CacheInvalidator
26     */
27    private $cacheInvalidator;
28
29    /**
30     * @var TitleFormatter
31     */
32    private $titleFormatter;
33
34    /**
35     * @var LoggerInterface
36     */
37    private $logger;
38
39    /**
40     * @var StatsdDataFactoryInterface
41     */
42    private $stats;
43
44    /**
45     * @param CognateStore $store
46     * @param CacheInvalidator $cacheInvalidator
47     * @param TitleFormatter $titleFormatter
48     * @param LoggerInterface $logger
49     */
50    public function __construct(
51        CognateStore $store,
52        CacheInvalidator $cacheInvalidator,
53        TitleFormatter $titleFormatter,
54        LoggerInterface $logger
55    ) {
56        $this->store = $store;
57        $this->cacheInvalidator = $cacheInvalidator;
58        $this->titleFormatter = $titleFormatter;
59        $this->logger = $logger;
60        $this->stats = new NullStatsdDataFactory();
61    }
62
63    /**
64     * @param StatsdDataFactoryInterface $statsFactory
65     */
66    public function setStatsdDataFactory( StatsdDataFactoryInterface $statsFactory ) {
67        $this->stats = $statsFactory;
68    }
69
70    /**
71     * @param string $dbName The dbName for the site
72     * @param LinkTarget $linkTarget
73     *
74     * @return bool
75     */
76    public function savePage( $dbName, LinkTarget $linkTarget ) {
77        $this->stats->increment( 'Cognate.Repo.savePage' );
78
79        try {
80            $start = microtime( true );
81            $success = $this->store->insertPage( $dbName, $linkTarget );
82            $this->stats->timing( 'Cognate.Repo.savePage.time', 1000 * ( microtime( true ) - $start ) );
83            $this->stats->gauge( 'Cognate.Repo.savePage.inserts', $success );
84        } catch ( DBReadOnlyError $e ) {
85            return false;
86        }
87
88        if ( $success ) {
89            $this->invalidateAllSitesForPage( $dbName, $linkTarget );
90        } else {
91            $dbKey = $linkTarget->getDBkey();
92            $namespace = $linkTarget->getNamespace();
93            $this->logger->error(
94                'Probable duplicate hash for dbKey: \'' . $dbKey . '\'',
95                [
96                    'dbName' => $dbName,
97                    'namespace' => $namespace,
98                    'dbKey' => $dbKey,
99                ]
100            );
101        }
102
103        return (bool)$success;
104    }
105
106    /**
107     * @param string $dbName The dbName for the site
108     * @param LinkTarget $linkTarget
109     *
110     * @return bool
111     */
112    public function deletePage( $dbName, LinkTarget $linkTarget ) {
113        $this->stats->increment( 'Cognate.Repo.deletePage' );
114
115        try {
116            $start = microtime( true );
117            $success = $this->store->deletePage( $dbName, $linkTarget );
118            $this->stats->timing( 'Cognate.Repo.deletePage.time', 1000 * ( microtime( true ) - $start ) );
119        } catch ( DBReadOnlyError $e ) {
120            return false;
121        }
122
123        if ( $success ) {
124            $this->invalidateAllSitesForPage( $dbName, $linkTarget );
125        }
126
127        return $success;
128    }
129
130    /**
131     * @param string $dbName The dbName of the site being linked from
132     * @param LinkTarget $linkTarget of the page the links should be retrieved for
133     *
134     * @return string[] interwiki links
135     */
136    public function getLinksForPage( $dbName, LinkTarget $linkTarget ) {
137        $this->stats->increment( 'Cognate.Repo.getLinksForPage' );
138
139        $start = microtime( true );
140        $linkDetails = $this->store->selectLinkDetailsForPage( $dbName, $linkTarget );
141        $time = 1000 * ( microtime( true ) - $start );
142        $this->stats->timing( 'Cognate.Repo.getLinksForPage.time', $time );
143
144        $links = [];
145        foreach ( $linkDetails as $data ) {
146            $links[] = $this->titleFormatter->formatTitle(
147                $data['namespaceID'],
148                $data['title'],
149                '',
150                $data['interwiki']
151            );
152        }
153        return $links;
154    }
155
156    /**
157     * @param string $dbName
158     * @param LinkTarget $linkTarget
159     */
160    private function invalidateAllSitesForPage( $dbName, LinkTarget $linkTarget ) {
161        $this->stats->increment( 'Cognate.Repo.selectSitesForPage' );
162
163        $start = microtime( true );
164        $sites = $this->store->selectSitesForPage( $linkTarget );
165        $time = 1000 * ( microtime( true ) - $start );
166        $this->stats->timing( 'Cognate.Repo.selectSitesForPage.time', $time );
167
168        // In the case of a delete causing cache invalidations we need to add the local site
169        // back to the list as it has already been removed from the database.
170        $sites[] = $dbName;
171        $sites = array_values( array_unique( $sites ) );
172
173        $this->cacheInvalidator->invalidate( $sites, $linkTarget );
174    }
175
176}