Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
PersistentDatabaseCache.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\Cache;
5
6use ArrayIterator;
7use Iterator;
8use MediaWiki\Json\JsonCodec;
9use Wikimedia\Rdbms\ILoadBalancer;
10
18 private const TABLE_NAME = 'translate_cache';
19
21 private $loadBalancer;
23 private $jsonCodec;
24
25 public function __construct( ILoadBalancer $loadBalancer, JsonCodec $jsonCodec ) {
26 $this->loadBalancer = $loadBalancer;
27 $this->jsonCodec = $jsonCodec;
28 }
29
31 public function get( string ...$keynames ): array {
32 $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
33 $rows = $dbr->select(
34 self::TABLE_NAME,
35 [ 'tc_key', 'tc_value', 'tc_exptime', 'tc_tag' ],
36 [ 'tc_key ' => $keynames ],
37 __METHOD__
38 );
39
40 return $this->buildEntries( $rows );
41 }
42
43 public function getWithLock( string $keyname ): ?PersistentCacheEntry {
44 $dbr = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
45
46 $conds = [ 'tc_key' => $keyname ];
47
48 $rows = $dbr->select(
49 self::TABLE_NAME,
50 [ 'tc_key', 'tc_value', 'tc_exptime', 'tc_tag' ],
51 $conds,
52 __METHOD__,
53 [ 'FOR UPDATE' ]
54 );
55
56 $entries = $this->buildEntries( $rows );
57 return count( $entries ) ? $entries[0] : null;
58 }
59
61 public function getByTag( string $tag ): array {
62 $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
63 $rows = $dbr->select(
64 self::TABLE_NAME,
65 [ 'tc_key', 'tc_value', 'tc_exptime', 'tc_tag' ],
66 [ 'tc_tag' => $tag ],
67 __METHOD__
68 );
69
70 return $this->buildEntries( $rows );
71 }
72
73 public function has( string $keyname ): bool {
74 $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
75 $hasRow = $dbr->selectRow(
76 self::TABLE_NAME,
77 'tc_key',
78 [ 'tc_key' => $keyname ],
79 __METHOD__
80 );
81
82 return (bool)$hasRow;
83 }
84
85 public function hasEntryWithTag( string $tag ): bool {
86 $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
87 $hasRow = $dbr->selectRow(
88 self::TABLE_NAME,
89 'tc_key',
90 [ 'tc_tag' => $tag ],
91 __METHOD__
92 );
93
94 return (bool)$hasRow;
95 }
96
97 public function hasExpiredEntry( string $keyname ): bool {
98 $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
99 $row = $dbr->selectRow(
100 self::TABLE_NAME,
101 'tc_expired',
102 [ 'tc_key' => $keyname ],
103 __METHOD__
104 );
105
106 if ( $row === false ) {
107 return false;
108 }
109
110 $rows = new ArrayIterator( [ $row ] );
111 $entry = $this->buildEntries( $rows )[0];
112 return $entry->hasExpired();
113 }
114
115 public function set( PersistentCacheEntry ...$entries ): void {
116 $dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
117
118 foreach ( $entries as $entry ) {
119 $value = $this->jsonCodec->serialize( $entry->value() );
120 $rowsToInsert = [
121 'tc_key' => $entry->key(),
122 'tc_value' => $value,
123 'tc_exptime' => $entry->exptime(),
124 'tc_tag' => $entry->tag()
125 ];
126
127 $rowsToUpdate = [
128 'tc_value' => $value,
129 'tc_exptime' => $entry->exptime(),
130 'tc_tag' => $entry->tag()
131 ];
132
133 $dbw->upsert(
134 self::TABLE_NAME,
135 $rowsToInsert,
136 'tc_key',
137 $rowsToUpdate,
138 __METHOD__
139 );
140 }
141 }
142
143 public function setExpiry( string $keyname, int $expiryTime ): void {
144 $dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
145 $dbw->update(
146 self::TABLE_NAME,
147 [ 'tc_exptime' => $expiryTime ],
148 [ 'tc_key' => $keyname ],
149 __METHOD__
150 );
151 }
152
153 public function delete( string ...$keynames ): void {
154 $dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
155 $dbw->delete(
156 self::TABLE_NAME,
157 [ 'tc_key' => $keynames ],
158 __METHOD__
159 );
160 }
161
162 public function deleteEntriesWithTag( string $tag ): void {
163 $dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
164 $dbw->delete(
165 self::TABLE_NAME,
166 [ 'tc_tag' => $tag ],
167 __METHOD__
168 );
169 }
170
171 public function clear(): void {
172 $dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
173 $dbw->delete(
174 self::TABLE_NAME,
175 '*',
176 __METHOD__
177 );
178 }
179
181 private function buildEntries( Iterator $rows ): array {
182 $entries = [];
183 foreach ( $rows as $row ) {
184 $entries[] = new PersistentCacheEntry(
185 $row->tc_key,
186 $this->jsonCodec->unserialize( $row->tc_value ),
187 $row->tc_exptime ? (int)$row->tc_exptime : null,
188 $row->tc_tag
189 );
190 }
191
192 return $entries;
193 }
194}
Represents a single result from the persistent cache.
A persistent cache implementation using the database.
Defines what method should be provided by a class implementing a persistent cache.