summaryrefslogtreecommitdiff
blob: 6fbd8a0af6eac5d473d416211c38486606b1e2b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<?php
/**
 * Handles storage / retrieval of data from message change files.
 *
 * @author Niklas Laxström
 * @license GPL-2.0-or-later
 * @since 2016.02
 * @file
 */

use MediaWiki\Extensions\Translate\MessageSync\MessageSourceChange;

class MessageChangeStorage {
	public const DEFAULT_NAME = 'default';

	/**
	 * Writes change array as a serialized file.
	 *
	 * @param MessageSourceChange[] $changes Array of changes as returned by processGroup
	 * indexed by message group id.
	 * @param string $file Which file to use.
	 */
	public static function writeChanges( array $changes, $file ) {
		$cache = \Cdb\Writer::open( $file );
		$keys = array_keys( $changes );
		$cache->set( '#keys', TranslateUtils::serialize( $keys ) );

		/**
		 * @var MessageSourceChange $change
		 */
		foreach ( $changes as $key => $change ) {
			$value = TranslateUtils::serialize( $change->getAllModifications() );
			$cache->set( $key, $value );
		}
		$cache->close();
	}

	/**
	 * Validate a name.
	 *
	 * @param string $name Which file to use.
	 * @return bool
	 */
	public static function isValidCdbName( $name ) {
		return preg_match( '/^[a-z_-]{1,100}$/i', $name );
	}

	/**
	 * Get a full path to file in a known location.
	 *
	 * @param string $name Which file to use.
	 * @return string
	 */
	public static function getCdbPath( $name ) {
		return TranslateUtils::cacheFile( "messagechanges.$name.cdb" );
	}

	/**
	 * Fetches changes for a group from the message change file.
	 * @param string $cdbPath Path of the cdb file.
	 * @param string $groupId Group Id
	 * @return MessageSourceChange
	 */
	public static function getGroupChanges( $cdbPath, $groupId ) {
		$reader = self::getCdbReader( $cdbPath );
		if ( $reader === null ) {
			return MessageSourceChange::loadModifications( [] );
		}

		$groups = TranslateUtils::deserialize( $reader->get( '#keys' ) );

		if ( !in_array( $groupId, $groups, true ) ) {
			throw new InvalidArgumentException( "Group Id - '$groupId' not found in cdb file " .
				"(path: $cdbPath)." );
		}

		return MessageSourceChange::loadModifications(
			TranslateUtils::deserialize( $reader->get( $groupId ) )
		);
	}

	/**
	 * Writes changes for a group. Has to read the changes first from the file,
	 * and then re-write them to the file.
	 * @param MessageSourceChange $changes
	 * @param string $groupId Group Id
	 * @param string $cdbPath Path of the cdb file.
	 */
	public static function writeGroupChanges( MessageSourceChange $changes, $groupId, $cdbPath ) {
		$reader = self::getCdbReader( $cdbPath );
		if ( $reader === null ) {
			return;
		}

		$groups = TranslateUtils::deserialize( $reader->get( '#keys' ) );

		$allChanges = [];
		foreach ( $groups as $id ) {
			$allChanges[$id] = MessageSourceChange::loadModifications(
				TranslateUtils::deserialize( $reader->get( $id ) )
			);
		}
		$allChanges[$groupId] = $changes;

		self::writeChanges( $allChanges, $cdbPath );
	}

	/**
	 * Validate and return a reader reference to the CDB file
	 * @param string $cdbPath
	 * @return \Cdb\Reader
	 */
	private static function getCdbReader( $cdbPath ) {
		// File not found, probably no changes.
		if ( !file_exists( $cdbPath ) ) {
			return null;
		}

		return \Cdb\Reader::open( $cdbPath );
	}

	/**
	 * Gets the last modified time for the CDB file.
	 *
	 * @param string $cdbPath
	 * @return int time of last modification (Unix timestamp)
	 */
	public static function getLastModifiedTime( $cdbPath ) {
		// File not found
		if ( !file_exists( $cdbPath ) ) {
			return null;
		}

		$stat = stat( $cdbPath );

		return $stat['mtime'];
	}

	/**
	 * Checks if the CDB file has been modified since the time given.
	 * @param string $cdbPath
	 * @param int $time Unix timestamp
	 * @return bool
	 */
	public static function isModifiedSince( $cdbPath, $time ) {
		$lastModifiedTime = self::getLastModifiedTime( $cdbPath );

		if ( $lastModifiedTime === null ) {
			throw new InvalidArgumentException( "CDB file not found - $cdbPath" );
		}

		return $lastModifiedTime <= $time;
	}
}