Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 41 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
MessageChangeStorage | |
0.00% |
0 / 41 |
|
0.00% |
0 / 8 |
272 | |
0.00% |
0 / 1 |
writeChanges | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
isValidCdbName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getCdbPath | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getGroupChanges | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
writeGroupChanges | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
getCdbReader | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getLastModifiedTime | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
isModifiedSince | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace MediaWiki\Extension\Translate\Synchronization; |
5 | |
6 | use Cdb\Reader; |
7 | use Cdb\Writer; |
8 | use InvalidArgumentException; |
9 | use MediaWiki\Extension\Translate\MessageSync\MessageSourceChange; |
10 | use MediaWiki\Extension\Translate\Utilities\Utilities; |
11 | |
12 | /** |
13 | * Handles storage / retrieval of data from message change files. |
14 | * @author Niklas Laxström |
15 | * @license GPL-2.0-or-later |
16 | */ |
17 | class MessageChangeStorage { |
18 | public const DEFAULT_NAME = 'default'; |
19 | |
20 | /** |
21 | * Writes change array as a serialized file. |
22 | * @param MessageSourceChange[] $changes Array of changes as returned by processGroup |
23 | * indexed by message group id. |
24 | * @param string $file Which file to use. |
25 | */ |
26 | public static function writeChanges( array $changes, string $file ): void { |
27 | $cache = Writer::open( $file ); |
28 | $keys = array_keys( $changes ); |
29 | $cache->set( '#keys', Utilities::serialize( $keys ) ); |
30 | |
31 | foreach ( $changes as $key => $change ) { |
32 | $value = Utilities::serialize( $change->getAllModifications() ); |
33 | $cache->set( $key, $value ); |
34 | } |
35 | $cache->close(); |
36 | } |
37 | |
38 | /** Validate a file name. */ |
39 | public static function isValidCdbName( string $fileName ): bool { |
40 | return (bool)preg_match( '/^[a-z_-]{1,100}$/i', $fileName ); |
41 | } |
42 | |
43 | /** Get a full path to file in a known location. */ |
44 | public static function getCdbPath( string $fileName ): string { |
45 | return Utilities::cacheFile( "messagechanges.$fileName.cdb" ); |
46 | } |
47 | |
48 | public static function getGroupChanges( string $cdbPath, string $groupId ): MessageSourceChange { |
49 | $reader = self::getCdbReader( $cdbPath ); |
50 | if ( $reader === null ) { |
51 | return MessageSourceChange::loadModifications( [] ); |
52 | } |
53 | |
54 | $groups = Utilities::deserialize( $reader->get( '#keys' ) ); |
55 | |
56 | if ( !in_array( $groupId, $groups, true ) ) { |
57 | throw new InvalidArgumentException( "Group Id - '$groupId' not found in cdb file " . |
58 | "(path: $cdbPath)." ); |
59 | } |
60 | |
61 | return MessageSourceChange::loadModifications( |
62 | Utilities::deserialize( $reader->get( $groupId ) ) |
63 | ); |
64 | } |
65 | |
66 | /** |
67 | * Writes changes for a group. Has to read the changes first from the file |
68 | * and then re-write them to the file. |
69 | */ |
70 | public static function writeGroupChanges( |
71 | MessageSourceChange $changes, |
72 | string $groupId, |
73 | string $cdbPath |
74 | ): void { |
75 | $reader = self::getCdbReader( $cdbPath ); |
76 | if ( $reader === null ) { |
77 | return; |
78 | } |
79 | |
80 | $groups = Utilities::deserialize( $reader->get( '#keys' ) ); |
81 | |
82 | $allChanges = []; |
83 | foreach ( $groups as $id ) { |
84 | $allChanges[$id] = MessageSourceChange::loadModifications( |
85 | Utilities::deserialize( $reader->get( $id ) ) |
86 | ); |
87 | } |
88 | $allChanges[$groupId] = $changes; |
89 | |
90 | self::writeChanges( $allChanges, $cdbPath ); |
91 | } |
92 | |
93 | /** Validate and return a reader reference to the CDB file */ |
94 | private static function getCdbReader( string $cdbPath ): ?Reader { |
95 | // File not found, probably no changes. |
96 | if ( !file_exists( $cdbPath ) ) { |
97 | return null; |
98 | } |
99 | |
100 | return Reader::open( $cdbPath ); |
101 | } |
102 | |
103 | /** |
104 | * Gets the last modified time for the CDB file. |
105 | * @return int|null time of last modification (Unix timestamp) |
106 | */ |
107 | public static function getLastModifiedTime( string $cdbPath ): ?int { |
108 | // File not found |
109 | if ( !file_exists( $cdbPath ) ) { |
110 | return null; |
111 | } |
112 | |
113 | $stat = stat( $cdbPath ); |
114 | |
115 | return $stat['mtime']; |
116 | } |
117 | |
118 | /** Checks if the CDB file has been modified since the time given. */ |
119 | public static function isModifiedSince( string $cdbPath, int $unixTimestamp ): bool { |
120 | $lastModifiedTime = self::getLastModifiedTime( $cdbPath ); |
121 | |
122 | if ( $lastModifiedTime === null ) { |
123 | throw new InvalidArgumentException( "CDB file not found - $cdbPath" ); |
124 | } |
125 | |
126 | return $lastModifiedTime <= $unixTimestamp; |
127 | } |
128 | } |