ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
PostingReplySubjectBuilder.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
24{
25 private const string EXPECTED_REPLY_PREFIX_END = ':';
26 private const string EXPECTED_NUMBER_WRAPPER_CHAR_START_PATTERN = '\\(';
27 private const string EXPECTED_NUMBER_WRAPPER_CHAR_END_PATTERN = '\\)';
28 private const string EXPECTED_NUMBER_WRAPPER_CHAR_START = '(';
29 private const string EXPECTED_NUMBER_WRAPPER_CHAR_END = ')';
30
32 private static ?array $f = null;
33
34 private readonly string $reply_prefix;
35 private readonly string $optimized_repeated_reply_prefix;
36
42 {
43 $this->reply_prefix = trim($reply_prefix);
44 $this->optimized_repeated_reply_prefix = trim($optimized_repeated_reply_prefix);
45
46 if (self::$f === null) {
47 self::$f = [
48 'strpos' => function (string $haystack, string $needle, ?int $offset = 0) {
49 return function_exists('mb_strpos') ? mb_strpos($haystack, $needle, $offset, 'UTF-8') : strpos(
50 $haystack,
51 $needle,
52 $offset
53 );
54 },
55 'strrpos' => function (string $haystack, string $needle, ?int $offset = 0) {
56 return function_exists('mb_strrpos') ? mb_strrpos($haystack, $needle, $offset, 'UTF-8') : strrpos(
57 $haystack,
58 $needle,
59 $offset
60 );
61 },
62 'strlen' => function (string $string): int {
63 return function_exists('mb_strlen') ? mb_strlen($string, 'UTF-8') : strlen($string);
64 },
65 'substr' => function (string $string, int $start, ?int $length = null): string {
66 return function_exists('mb_substr') ? mb_substr($string, $start, $length, 'UTF-8') : substr(
67 $string,
68 $start,
69 $length
70 );
71 }
72 ];
73 }
74 }
75
76 public function build(string $subject_of_parent_posting): string
77 {
78 $subject_of_parent_posting = trim($subject_of_parent_posting);
79 $subject_of_reply = '';
80
82 if ((self::$f['substr'])(
84 -((self::$f['strlen'])(self::EXPECTED_REPLY_PREFIX_END))
85 ) !== self::EXPECTED_REPLY_PREFIX_END) {
87 }
88
90 if ((self::$f['substr'])(
92 -((self::$f['strlen'])(self::EXPECTED_REPLY_PREFIX_END))
93 ) !== self::EXPECTED_REPLY_PREFIX_END) {
95 }
96
97 $optimized_repeated_reply_prefix_start = substr_replace(
99 self::EXPECTED_NUMBER_WRAPPER_CHAR_START,
100 (self::$f['strrpos'])($reply_prefix, self::EXPECTED_REPLY_PREFIX_END),
101 (self::$f['strlen'])(self::EXPECTED_REPLY_PREFIX_END)
102 );
103
104 $optimized_repeated_reply_prefix_begin_pattern = preg_quote(
105 (self::$f['substr'])(
106 $optimized_repeated_reply_prefix_start,
107 0,
108 (self::$f['strrpos'])(
109 $optimized_repeated_reply_prefix_start,
110 self::EXPECTED_NUMBER_WRAPPER_CHAR_START
111 )
112 ),
113 '/'
114 );
115
116 $optimized_repeated_reply_prefix_regex = implode('', [
117 '/^',
118 $optimized_repeated_reply_prefix_begin_pattern,
119 '\s*?' . self::EXPECTED_NUMBER_WRAPPER_CHAR_START_PATTERN . '\s*?\d+\s*?' . self::EXPECTED_NUMBER_WRAPPER_CHAR_END_PATTERN,
120 '/'
121 ]);
122
123 if (preg_match($optimized_repeated_reply_prefix_regex, $subject_of_parent_posting)) {
124 // i.e. $subj_of_parent_posting = "Re(12):" or "Re (12):"
126 $subject_of_parent_posting
127 );
128 } else {
129 // i.e. $subj_of_parent_posting = "Re: Re: Re: ..."
131 $subject_of_parent_posting,
134 );
135 }
136
137 return $subject_of_reply;
138 }
139
141 string $subject_of_parent_posting,
142 string $effective_reply_prefix,
143 string $effective_optimized_repeated_reply_prefix
144 ): string {
145 $subject_of_reply = $subject_of_parent_posting;
146
147 $reply_prefix_start = (self::$f['substr'])(
148 $effective_reply_prefix,
149 0,
151 );
152
153 $repeated_reply_prefix_regex = implode('', [
154 '/^',
155 '(' . preg_quote($reply_prefix_start, '/') . '\s*' . self::EXPECTED_REPLY_PREFIX_END . '\s*)+',
156 '/'
157 ]);
158
159 $matches = null;
160 preg_match($repeated_reply_prefix_regex, $subject_of_parent_posting, $matches);
161 $number_of_repetitions = isset($matches[0]) ?
162 preg_match_all(
163 '/' . preg_quote($reply_prefix_start, '/') . '\s*' . self::EXPECTED_REPLY_PREFIX_END . '\s*/',
164 $matches[0]
165 ) : 0;
166
167 if ($number_of_repetitions >= 1) {
168 // i.e. $final_subject = "Re: Re: Re: ... " -> "Re(4):"
169 $number_of_repetitions++;
170 $subject_of_reply = sprintf(
171 $effective_optimized_repeated_reply_prefix,
172 $number_of_repetitions
173 ) . ' ' . trim(str_replace($matches[0], '', $subject_of_parent_posting));
174 } elseif ($number_of_repetitions === 0) {
175 // the first reply to a thread
176 $subject_of_reply = $effective_reply_prefix . ' ' . $subject_of_parent_posting;
177 }
178
179 return $subject_of_reply;
180 }
181
182 private function handleSubjectStartsWithOptimizedRepetitionReplyPattern(string $subject_of_parent_posting): string
183 {
184 $subject_of_reply = $subject_of_parent_posting;
185
186 $wrapper_start_pos = (self::$f['strpos'])($subject_of_parent_posting, self::EXPECTED_NUMBER_WRAPPER_CHAR_START);
187 $wrapper_end_pos = (self::$f['strpos'])($subject_of_parent_posting, self::EXPECTED_NUMBER_WRAPPER_CHAR_END);
188
189 if ($wrapper_start_pos === false || $wrapper_end_pos === false || $wrapper_end_pos < $wrapper_start_pos) {
190 return $subject_of_reply;
191 }
192
193 $length = $wrapper_end_pos - $wrapper_start_pos;
194 $wrapper_start_pos++;
195
196 $txt_num_replies = (self::$f['substr'])($subject_of_parent_posting, $wrapper_start_pos, $length - 1);
197 if (is_numeric($txt_num_replies) && $txt_num_replies > 0) {
198 $number_of_replies = ((int) trim($txt_num_replies)) + 1;
199 $subject_of_reply = (self::$f['substr'])(
200 $subject_of_parent_posting,
201 0,
202 $wrapper_start_pos
203 ) . $number_of_replies . (self::$f['substr'])(
204 $subject_of_parent_posting,
205 $wrapper_end_pos
206 );
207 }
208
209 return $subject_of_reply;
210 }
211}
__construct(string $reply_prefix, string $optimized_repeated_reply_prefix)
handleSubjectStartsWithOptimizedRepetitionReplyPattern(string $subject_of_parent_posting)
handleSubjectWithoutReplyPrefixOrRepeatedReplyPrefix(string $subject_of_parent_posting, string $effective_reply_prefix, string $effective_optimized_repeated_reply_prefix)