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