Test Failed
Push — hotfix/fix-counts ( 9a2e54...d16e24 )
by Paul
03:31
created

SiteReviews::getExcerptSplit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 7
ccs 0
cts 7
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules\Html\Partials;
4
5
use GeminiLabs\SiteReviews\Database\OptionManager;
6
use GeminiLabs\SiteReviews\Database\ReviewManager;
7
use GeminiLabs\SiteReviews\Defaults\SiteReviewsDefaults;
8
use GeminiLabs\SiteReviews\Helper;
9
use GeminiLabs\SiteReviews\Modules\Date;
10
use GeminiLabs\SiteReviews\Modules\Html\Builder;
11
use GeminiLabs\SiteReviews\Modules\Html\ReviewHtml;
12
use GeminiLabs\SiteReviews\Modules\Html\ReviewsHtml;
13
use GeminiLabs\SiteReviews\Modules\Polylang;
14
use GeminiLabs\SiteReviews\Modules\Schema;
15
use GeminiLabs\SiteReviews\Review;
16
use GeminiLabs\SiteReviews\Reviews;
17
use IntlRuleBasedBreakIterator;
18
use WP_Post;
19
20
class SiteReviews
21
{
22
    /**
23
     * @var array
24
     */
25
    public $args;
26
27
    /**
28
     * @var Review
29
     */
30
    public $current;
31
32
    /**
33
     * @var array
34
     */
35
    public $options;
36
37
    /**
38
     * @var Reviews
39
     */
40
    protected $reviews;
41
42
    /**
43
     * @param Reviews|null $reviews
44
     * @return ReviewsHtml
45
     */
46
    public function build(array $args = [], $reviews = null)
47
    {
48
        $this->args = glsr(SiteReviewsDefaults::class)->merge($args);
49
        $this->options = glsr(Helper::class)->flattenArray(glsr(OptionManager::class)->all());
50
        $this->reviews = $reviews instanceof Reviews
51
            ? $reviews
52
            : glsr(ReviewManager::class)->get($args);
53
        $this->generateSchema();
54
        return $this->buildReviews();
55
    }
56
57
    /**
58
     * @return ReviewHtml
59
     */
60
    public function buildReview(Review $review)
61
    {
62
        $review = apply_filters('site-reviews/review/build/before', $review);
63
        $this->current = $review;
64
        $renderedFields = [];
65
        foreach ($review as $key => $value) {
66
            $method = glsr(Helper::class)->buildMethodName($key, 'buildOption');
67
            $field = method_exists($this, $method)
68
                ? $this->$method($key, $value)
69
                : apply_filters('site-reviews/review/build/'.$key, false, $value, $this, $review);
70
            if (false === $field) {
71
                continue;
72
            }
73
            $renderedFields[$key] = $field;
74
        }
75
        $this->wrap($renderedFields, $review);
76
        $renderedFields = apply_filters('site-reviews/review/build/after', $renderedFields, $review);
77
        $this->current = null;
78
        return new ReviewHtml($review, (array) $renderedFields);
79
    }
80
81
    /**
82
     * @return ReviewsHtml
83
     */
84
    public function buildReviews()
85
    {
86
        $renderedReviews = [];
87
        foreach ($this->reviews as $index => $review) {
88
            $renderedReviews[] = $this->buildReview($review);
89
        }
90
        return new ReviewsHtml($renderedReviews, $this->reviews->max_num_pages, $this->args);
91
    }
92
93
    /**
94
     * @return void
95
     */
96
    public function generateSchema()
97
    {
98
        if (!wp_validate_boolean($this->args['schema'])) {
99
            return;
100
        }
101
        glsr(Schema::class)->store(
102
            glsr(Schema::class)->build($this->args)
103
        );
104
    }
105
106
    /**
107
     * @param string $key
108
     * @param string $path
109
     * @return bool
110
     */
111
    public function isHidden($key, $path = '')
112
    {
113
        $isOptionEnabled = !empty($path)
114
            ? $this->isOptionEnabled($path)
115
            : true;
116
        return in_array($key, $this->args['hide']) || !$isOptionEnabled;
117
    }
118
119
    /**
120
     * @param string $key
121
     * @param string $value
122
     * @return void|string
123
     */
124
    protected function buildOptionAssignedTo($key, $value)
125
    {
126
        if ($this->isHidden($key, 'settings.reviews.assigned_links')) {
127
            return;
128
        }
129
        $post = glsr(Polylang::class)->getPost($value);
130
        if (!($post instanceof WP_Post)) {
131
            return;
132
        }
133
        $permalink = glsr(Builder::class)->a(get_the_title($post->ID), [
134
            'href' => get_the_permalink($post->ID),
135
        ]);
136
        $assignedTo = sprintf(__('Review of %s', 'site-reviews'), $permalink);
137
        return '<span>'.$assignedTo.'</span>';
138
    }
139
140
    /**
141
     * @param string $key
142
     * @param string $value
143
     * @return void|string
144
     */
145
    protected function buildOptionAuthor($key, $value)
146
    {
147
        if (!$this->isHidden($key)) {
148
            return '<span>'.$value.'</span>';
149
        }
150
    }
151
152
    /**
153
     * @param string $key
154
     * @param string $value
155
     * @return void|string
156
     */
157
    protected function buildOptionAvatar($key, $value)
158
    {
159
        if ($this->isHidden($key, 'settings.reviews.avatars')) {
160
            return;
161
        }
162
        $size = $this->getOption('settings.reviews.avatars_size', 40);
163
        return glsr(Builder::class)->img([
164
            'height' => $size,
165
            'src' => $this->generateAvatar($value),
166
            'style' => sprintf('width:%1$spx; height:%1$spx;', $size),
167
            'width' => $size,
168
        ]);
169
    }
170
171
    /**
172
     * @param string $key
173
     * @param string $value
174
     * @return void|string
175
     */
176
    protected function buildOptionContent($key, $value)
177
    {
178
        $text = $this->normalizeText($value);
179
        if (!$this->isHiddenOrEmpty($key, $text)) {
180
            return '<p>'.$text.'</p>';
181
        }
182
    }
183
184
    /**
185
     * @param string $key
186
     * @param string $value
187
     * @return void|string
188
     */
189
    protected function buildOptionDate($key, $value)
190
    {
191
        if ($this->isHidden($key)) {
192
            return;
193
        }
194
        $dateFormat = $this->getOption('settings.reviews.date.format', 'default');
195
        if ('relative' == $dateFormat) {
196
            $date = glsr(Date::class)->relative($value);
197
        } else {
198
            $format = 'custom' == $dateFormat
199
                ? $this->getOption('settings.reviews.date.custom', 'M j, Y')
200
                : (string) get_option('date_format');
201
            $date = date_i18n($format, strtotime($value));
202
        }
203
        return '<span>'.$date.'</span>';
204
    }
205
206
    /**
207
     * @param string $key
208
     * @param string $value
209
     * @return void|string
210
     */
211
    protected function buildOptionRating($key, $value)
212
    {
213
        if (!$this->isHiddenOrEmpty($key, $value)) {
214
            return glsr_star_rating($value);
215
        }
216
    }
217
218
    /**
219
     * @param string $key
220
     * @param string $value
221
     * @return void|string
222
     */
223
    protected function buildOptionResponse($key, $value)
224
    {
225
        if ($this->isHiddenOrEmpty($key, $value)) {
226
            return;
227
        }
228
        $title = sprintf(__('Response from %s', 'site-reviews'), get_bloginfo('name'));
229
        $text = $this->normalizeText($value);
230
        $text = '<p><strong>'.$title.'</strong></p><p>'.$text.'</p>';
231
        $response = glsr(Builder::class)->div($text, ['class' => 'glsr-review-response-inner']);
232
        $background = glsr(Builder::class)->div(['class' => 'glsr-review-response-background']);
233
        return $response.$background;
234
    }
235
236
    /**
237
     * @param string $key
238
     * @param string $value
239
     * @return void|string
240
     */
241
    protected function buildOptionTitle($key, $value)
242
    {
243
        if ($this->isHidden($key)) {
244
            return;
245
        }
246
        if (empty($value)) {
247
            $value = __('No Title', 'site-reviews');
248
        }
249
        return '<h3>'.$value.'</h3>';
250
    }
251
252
    /**
253
     * @param string $avatarUrl
254
     * @return string
255
     */
256
    protected function generateAvatar($avatarUrl)
257
    {
258
        if (!$this->isOptionEnabled('settings.reviews.avatars_regenerate') || 'local' != $this->current->review_type) {
259
            return $avatarUrl;
260
        }
261
        $authorIdOrEmail = get_the_author_meta('ID', $this->current->user_id);
262
        if (empty($authorIdOrEmail)) {
263
            $authorIdOrEmail = $this->current->email;
264
        }
265
        if ($newAvatar = get_avatar_url($authorIdOrEmail)) {
266
            return $newAvatar;
267
        }
268
        return $avatarUrl;
269
    }
270
271
    /**
272
     * @param string $text
273
     * @return string
274
     */
275
    protected function getExcerpt($text)
276
    {
277
        $limit = intval($this->getOption('settings.reviews.excerpts_length', 55));
278
        $split = extension_loaded('intl')
279
            ? $this->getExcerptIntlSplit($text, $limit)
280
            : $this->getExcerptSplit($text, $limit);
281
        $hiddenText = substr($text, $split);
282
        if (!empty($hiddenText)) {
283
            $showMore = glsr(Builder::class)->span($hiddenText, [
284
                'class' => 'glsr-hidden glsr-hidden-text',
285
                'data-show-less' => __('Show less', 'site-reviews'),
286
                'data-show-more' => __('Show more', 'site-reviews'),
287
            ]);
288
            $text = ltrim(substr($text, 0, $split)).$showMore;
289
        }
290
        return $text;
291
    }
292
293
    /**
294
     * @param string $text
295
     * @param int $limit
296
     * @return int
297
     */
298
    protected function getExcerptIntlSplit($text, $limit)
299
    {
300
        $words = IntlRuleBasedBreakIterator::createWordInstance('');
301
        $words->setText($text);
302
        $count = 0;
303
        foreach ($words as $offset) {
304
            if (IntlRuleBasedBreakIterator::WORD_NONE === $words->getRuleStatus()) {
305
                continue;
306
            }
307
            ++$count;
308
            if ($count != $limit) {
309
                continue;
310
            }
311
            return $offset;
312
        }
313
        return strlen($text);
314
    }
315
316
    /**
317
     * @param string $text
318
     * @param int $limit
319
     * @return int
320
     */
321
    protected function getExcerptSplit($text, $limit)
322
    {
323
        if (str_word_count($text, 0) > $limit) {
324
            $words = array_keys(str_word_count($text, 2));
325
            return $words[$limit];
326
        }
327
        return strlen($text);
328
    }
329
330
    /**
331
     * @param string $path
332
     * @param mixed $fallback
333
     * @return mixed
334
     */
335
    protected function getOption($path, $fallback = '')
336
    {
337
        if (array_key_exists($path, $this->options)) {
338
            return $this->options[$path];
339
        }
340
        return $fallback;
341
    }
342
343
    /**
344
     * @param string $key
345
     * @param string $value
346
     * @return bool
347
     */
348
    protected function isHiddenOrEmpty($key, $value)
349
    {
350
        return $this->isHidden($key) || empty($value);
351
    }
352
353
    /**
354
     * @param string $path
355
     * @return bool
356
     */
357
    protected function isOptionEnabled($path)
358
    {
359
        return 'yes' == $this->getOption($path);
360
    }
361
362
    /**
363
     * @param string $text
364
     * @return string
365
     */
366
    protected function normalizeText($text)
367
    {
368
        $text = wp_kses($text, wp_kses_allowed_html());
369
        $text = convert_smilies(strip_shortcodes($text));
370
        $text = str_replace(']]>', ']]&gt;', $text);
371
        $text = preg_replace('/(\R){2,}/', '$1', $text);
372
        if ($this->isOptionEnabled('settings.reviews.excerpts')) {
373
            $text = $this->getExcerpt($text);
374
        }
375
        return wptexturize(nl2br($text));
376
    }
377
378
    /**
379
     * @return void
380
     */
381
    protected function wrap(array &$renderedFields, Review $review)
382
    {
383
        $renderedFields = apply_filters('site-reviews/review/wrap', $renderedFields, $review);
384
        array_walk($renderedFields, function (&$value, $key) use ($review) {
385
            $value = apply_filters('site-reviews/review/wrap/'.$key, $value, $review);
386
            if (empty($value)) {
387
                return;
388
            }
389
            $value = glsr(Builder::class)->div($value, [
390
                'class' => 'glsr-review-'.$key,
391
            ]);
392
        });
393
    }
394
}
395