Completed
Push — add/changelog-tooling ( 963953...b30521 )
by
unknown
866:58 queued 856:03
created

ChangeEntry::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11

Duplication

Lines 11
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 11
loc 11
rs 9.9
c 0
b 0
f 0
1
<?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase
2
/**
3
 * Class representing a change entry.
4
 *
5
 * @package automattic/jetpack-changelogger
6
 */
7
8
// phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
9
10
namespace Automattic\Jetpack\Changelog;
11
12
use DateTime;
13
use InvalidArgumentException;
14
15
/**
16
 * Class representing a change entry.
17
 */
18
class ChangeEntry {
19
20
	/**
21
	 * Entry significance.
22
	 *
23
	 * @var string|null
24
	 */
25
	protected $significance = null;
26
27
	/**
28
	 * Entry timestamp.
29
	 *
30
	 * @var DateTime
31
	 */
32
	protected $timestamp;
33
34
	/**
35
	 * Subheading the entry is under.
36
	 *
37
	 * @var string
38
	 */
39
	protected $subheading = '';
40
41
	/**
42
	 * Author of the entry.
43
	 *
44
	 * @var string
45
	 */
46
	protected $author = '';
47
48
	/**
49
	 * Content of the entry.
50
	 *
51
	 * @var string
52
	 */
53
	protected $content = '';
54
55
	/**
56
	 * Constructor.
57
	 *
58
	 * @param array $data Data for entry fields. Keys correspond to the setters, e.g. key 'content' calls `setContent()`.
59
	 * @throws InvalidArgumentException If an argument is invalid.
60
	 */
61 View Code Duplication
	public function __construct( array $data = array() ) {
62
		$data = $data + array( 'timestamp' => 'now' );
63
		foreach ( $data as $k => $v ) {
64
			$func = array( $this, 'set' . ucfirst( $k ) );
65
			if ( is_callable( $func ) ) {
66
				$func( $v );
67
			} else {
68
				throw new InvalidArgumentException( __METHOD__ . ": Unrecognized data item \"$k\"." );
69
			}
70
		}
71
	}
72
73
	/**
74
	 * Compare two ChangeEntry objects.
75
	 *
76
	 * @param ChangeEntry $a First ChangeEntry.
77
	 * @param ChangeEntry $b Second ChangeEntry.
78
	 * @param array       $config Comparison configuration. Keys are:
79
	 *        - ordering: (string[]) Order in which to consider the fields. Field
80
	 *          names correspond to getters, e.g. 'significance' =>
81
	 *          `getSignificance()`. Default ordering is subheading, content.
82
	 *        - knownSubheadings: (string[]) Change entries with these headings will
83
	 *          compare, in this order, after those with no subheading and before any
84
	 *          other subheadings.
85
	 * @return int <0 if $a should come before $b, >0 if $b should come before $a, or 0 otherwise.
86
	 * @throws InvalidArgumentException If an argument is invalid.
87
	 */
88
	public static function compare( ChangeEntry $a, ChangeEntry $b, array $config = array() ) {
89
		$config += array(
90
			'ordering'         => array( 'subheading', 'content' ),
91
			'knownSubheadings' => array(),
92
		);
93
94
		foreach ( $config['ordering'] as $field ) {
95
			// First, check for a custom comparison function.
96
			$func = array( static::class, 'compare' . ucfirst( $field ) );
97
			if ( is_callable( $func ) ) {
98
				$ret = $func( $a, $b, $config );
99
			} else {
100
				// Otherwise, just use `strnatcasecmp()`.
101
				$func = 'get' . ucfirst( $field );
102
				if ( ! is_callable( array( $a, $func ) ) || ! is_callable( array( $b, $func ) ) ) {
103
					throw new InvalidArgumentException( __METHOD__ . ': Invalid field in ordering' );
104
				}
105
				$aa  = call_user_func( array( $a, $func ) );
106
				$bb  = call_user_func( array( $b, $func ) );
107
				$ret = strnatcasecmp( $aa, $bb );
108
			}
109
			if ( 0 !== $ret ) {
110
				return $ret;
111
			}
112
		}
113
114
		return 0;
115
	}
116
117
	/**
118
	 * Get the significance.
119
	 *
120
	 * @return string|null
121
	 */
122
	public function getSignificance() {
123
		return $this->significance;
124
	}
125
126
	/**
127
	 * Set the significance.
128
	 *
129
	 * @param string|null $significance 'patch', 'minor', or 'major'.
130
	 * @returns $this
131
	 * @throws InvalidArgumentException If an argument is invalid.
132
	 */
133
	public function setSignificance( $significance ) {
134
		if ( ! in_array( $significance, array( null, 'patch', 'minor', 'major' ), true ) ) {
135
			throw new InvalidArgumentException( __METHOD__ . ": Significance must be 'patch', 'minor', or 'major' (or null)" );
136
		}
137
		$this->significance = $significance;
138
		return $this;
139
	}
140
141
	/**
142
	 * Compare significance values.
143
	 *
144
	 * @param ChangeEntry $a First entry.
145
	 * @param ChangeEntry $b Second entry.
146
	 * @param array       $config Unused.
147
	 * @return int
148
	 */
149
	protected static function compareSignificance( ChangeEntry $a, ChangeEntry $b, array $config ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
150
		static $values = array( 'major', 'minor', 'patch', null );
151
		$aa            = array_search( $a->getSignificance(), $values, true );
152
		$bb            = array_search( $b->getSignificance(), $values, true );
153
		return $aa - $bb;
154
	}
155
156
	/**
157
	 * Get the timestamp.
158
	 *
159
	 * @return DateTime
160
	 */
161
	public function getTimestamp() {
162
		return $this->timestamp;
163
	}
164
165
	/**
166
	 * Set the timestamp.
167
	 *
168
	 * @param DateTime|string $timestamp Timestamp to set.
169
	 * @returns $this
170
	 * @throws InvalidArgumentException If an argument is invalid.
171
	 */
172 View Code Duplication
	public function setTimestamp( $timestamp ) {
173
		if ( ! $timestamp instanceof DateTime ) {
174
			try {
175
				$timestamp = new DateTime( $timestamp );
176
			} catch ( \Exception $ex ) {
177
				throw new InvalidArgumentException( __METHOD__ . ': Invalid timestamp', 0, $ex );
178
			}
179
		}
180
		$this->timestamp = $timestamp;
181
		return $this;
182
	}
183
184
	/**
185
	 * Compare timestamps.
186
	 *
187
	 * @param ChangeEntry $a First entry.
188
	 * @param ChangeEntry $b Second entry.
189
	 * @param array       $config Unused.
190
	 * @return int
191
	 */
192
	protected static function compareTimestamp( ChangeEntry $a, ChangeEntry $b, array $config ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
193
		$aa = $a->getTimestamp();
194
		$bb = $b->getTimestamp();
195
		return $aa < $bb ? -1 : ( $aa > $bb ? 1 : 0 );
196
	}
197
198
	/**
199
	 * Get the subheading.
200
	 *
201
	 * @return string
202
	 */
203
	public function getSubheading() {
204
		return $this->subheading;
205
	}
206
207
	/**
208
	 * Set the subheading.
209
	 *
210
	 * @param string $subheading Subheading to set.
211
	 * @returns $this
212
	 */
213
	public function setSubheading( $subheading ) {
214
		$this->subheading = (string) $subheading;
215
		return $this;
216
	}
217
218
	/**
219
	 * Compare subheadings.
220
	 *
221
	 * @param ChangeEntry $a First entry.
222
	 * @param ChangeEntry $b Second entry.
223
	 * @param array       $config Used for 'knownSubheadings'.
224
	 * @return int
225
	 */
226
	protected static function compareSubheading( ChangeEntry $a, ChangeEntry $b, array $config ) {
227
		$aa = $a->getSubheading();
228
		$bb = $b->getSubheading();
229
230
		// If they're equal, just return that.
231
		$cmp = strnatcasecmp( $aa, $bb );
232
		if ( 0 === $cmp ) {
233
			return 0;
234
		}
235
236
		// Empty string comes first.
237
		if ( '' === $aa ) {
238
			return -1;
239
		}
240
		if ( '' === $bb ) {
241
			return 1;
242
		}
243
244
		// Search for known values.
245
		foreach ( $config['knownSubheadings'] as $v ) {
246
			if ( strnatcasecmp( $aa, $v ) === 0 ) {
247
				return -1;
248
			}
249
			if ( strnatcasecmp( $bb, $v ) === 0 ) {
250
				return 1;
251
			}
252
		}
253
254
		// Fallback.
255
		return $cmp;
256
	}
257
258
	/**
259
	 * Get the author.
260
	 *
261
	 * @return string
262
	 */
263
	public function getAuthor() {
264
		return $this->author;
265
	}
266
267
	/**
268
	 * Set the author.
269
	 *
270
	 * @param string $author Author to set.
271
	 * @returns $this
272
	 */
273
	public function setAuthor( $author ) {
274
		$this->author = (string) $author;
275
		return $this;
276
	}
277
278
	/**
279
	 * Get the content.
280
	 *
281
	 * @return string
282
	 */
283
	public function getContent() {
284
		return $this->content;
285
	}
286
287
	/**
288
	 * Set the content.
289
	 *
290
	 * @param string $content Content to set.
291
	 * @returns $this
292
	 */
293
	public function setContent( $content ) {
294
		$this->content = (string) $content;
295
		return $this;
296
	}
297
298
}
299