RelatedPosts::componentDetails()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace GinoPane\BlogTaxonomy\Components;
4
5
use DB;
6
use Cms\Classes\Page;
7
use RainLab\Blog\Models\Post;
8
use GinoPane\BlogTaxonomy\Plugin;
9
use GinoPane\BlogTaxonomy\Models\Tag;
10
use October\Rain\Database\Collection;
11
use GinoPane\BlogTaxonomy\Models\ModelAbstract;
12
use GinoPane\BlogTaxonomy\Classes\PostListAbstract;
13
use GinoPane\BlogTaxonomy\Classes\ComponentAbstract;
14
use GinoPane\BlogTaxonomy\Classes\TranslateArrayTrait;
15
use GinoPane\BlogTaxonomy\Classes\PostListFiltersTrait;
16
17
/**
18
 * Class RelatedPosts
19
 *
20
 * @package GinoPane\BlogTaxonomy\Components
21
 */
22
class RelatedPosts extends ComponentAbstract
23
{
24
    const NAME = 'relatedPosts';
25
26
    use TranslateArrayTrait;
27
    use PostListFiltersTrait;
28
29
    /**
30
     * @var Collection | array
31
     */
32
    public $posts = [];
33
34
    /**
35
     * Reference to the page name for linking to posts
36
     *
37
     * @var string
38
     */
39
    public $postPage;
40
41
    /**
42
     * If the post list should be ordered by another attribute
43
     *
44
     * @var string
45
     */
46
    public $orderBy;
47
48
    /**
49
     * Limits the number of records to display
50
     *
51
     * @var int
52
     */
53
    public $limit;
54
55
    /**
56
     * Component Registration
57
     *
58
     * @return  array
59
     */
60
    public function componentDetails(): array
61
    {
62
        return [
63
            'name'        => Plugin::LOCALIZATION_KEY . 'components.related_posts.name',
64
            'description' => Plugin::LOCALIZATION_KEY . 'components.related_posts.description'
65
        ];
66
    }
67
68
    /**
69
     * Component Properties
70
     *
71
     * @return  array
72
     */
73
    public function defineProperties(): array
74
    {
75
        return array_merge([
76
            'slug' => [
77
                'title'             => Plugin::LOCALIZATION_KEY . 'components.related_posts.post_slug_title',
78
                'description'       => Plugin::LOCALIZATION_KEY . 'components.related_posts.post_slug_description',
79
                'default'           => '{{ :slug }}',
80
                'type'              => 'string'
81
            ],
82
83
            'limit' => [
84
                'title'             => Plugin::LOCALIZATION_KEY . 'components.related_posts.limit_title',
85
                'description'       => Plugin::LOCALIZATION_KEY . 'components.related_posts.limit_description',
86
                'type'              => 'string',
87
                'default'           => '0',
88
                'validationPattern' => '^[0-9]+$',
89
                'validationMessage' => Plugin::LOCALIZATION_KEY . 'components.related_posts.limit_validation_message',
90
                'showExternalParam' => false
91
            ],
92
93
            'orderBy' => [
94
                'title'       => 'rainlab.blog::lang.settings.posts_order',
95
                'description' => 'rainlab.blog::lang.settings.posts_order_description',
96
                'type'        => 'dropdown',
97
                'default'     => 'published_at asc',
98
                'showExternalParam' => false
99
            ],
100
101
            'postPage' => [
102
                'group'       => Plugin::LOCALIZATION_KEY . 'components.related_posts.links_group',
103
                'title'       => 'rainlab.blog::lang.settings.posts_post',
104
                'description' => 'rainlab.blog::lang.settings.posts_description',
105
                'type'        => 'dropdown',
106
                'default'     => 'blog/post',
107
            ],
108
        ], $this->getPostFilterProperties());
109
    }
110
111
    /**
112
     * @see PostListAbstract::$postAllowedSortingOptions
113
     *
114
     * @return mixed
115
     */
116
    public function getOrderByOptions()
117
    {
118
        $order = $this->translate(
119
            array_merge(
120
                [
121
                    'relevance asc' => Plugin::LOCALIZATION_KEY . 'order_options.relevance_asc',
122
                    'relevance desc' => Plugin::LOCALIZATION_KEY . 'order_options.relevance_desc'
123
                ],
124
                PostListAbstract::$postAllowedSortingOptions
125
            )
126
        );
127
128
        asort($order);
129
130
        return $order;
131
    }
132
133
    private function prepareVars()
134
    {
135
        $this->orderBy = $this->page['orderBy'] = $this->property('orderBy');
136
137
        // Page links
138
        $this->postPage = $this->page['postPage' ] = $this->property('postPage');
139
140
        // Exceptions
141
        $this->populateFilters();
142
    }
143
144
    public function getPostPageOptions()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
145
    {
146
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
147
    }
148
149
    /**
150
     * Load post and start building query for related posts
151
     */
152
    public function onRun()
153
    {
154
        //Prepare vars
155
        $this->prepareVars();
156
157
        $this->posts = $this->loadRelatedPosts();
158
    }
159
160
    /**
161
     * Load related posts by common tags
162
     *
163
     * @return mixed
164
     */
165
    private function loadRelatedPosts()
166
    {
167
        $post = Post::with('tags');
168
169
        ModelAbstract::whereTranslatableProperty($post, 'slug', $this->property('slug'));
170
171
        $post = $post->first();
172
173
        if (!$post || (!$tagIds = $post->tags->lists('id'))) {
174
            return null;
175
        }
176
177
        $query = Post::isPublished()
178
            ->where('id', '<>', $post->id)
179
            ->whereHas('tags', function ($tag) use ($tagIds) {
180
                $tag->whereIn('id', $tagIds);
181
            })
182
            ->with('tags');
183
184
        $this->handlePostFilters($query);
185
        $this->queryOrderBy($query, $tagIds);
186
187
        if ($take = (int)$this->property('limit')) {
188
            $query->take($take);
189
        }
190
191
        $posts = $query->get();
192
193
        $this->setPostUrls($posts);
194
195
        return $posts;
196
    }
197
198
    /**
199
     * @param $query
200
     * @param $tagIds
201
     */
202
    private function queryOrderBy($query, $tagIds)
203
    {
204
        if (array_key_exists($this->orderBy, $this->getOrderByOptions())) {
205
            if ($this->orderBy === 'random') {
206
                $query->inRandomOrder();
207
            } else {
208
                list($sortField, $sortDirection) = explode(' ', $this->orderBy);
209
210
                if ($sortField === 'relevance') {
211
                    $sortField = DB::raw(
212
                        sprintf(
213
                            '(
214
                                select count(*)
215
                                from `%1$s`
216
                                where
217
                                `%1$s`.`%2$s_type` = \'RainLab\Blog\Models\Post\'
218
                                and `%1$s`.`%2$s_id` = `rainlab_blog_posts`.`id`
219
                                and `%1$s`.`tag_id` in (\'%3$s\')
220
                            )',
221
                            Tag::PIVOT_TABLE,
222
                            Tag::PIVOT_COLUMN,
223
                            implode('\', \'', $tagIds)
224
                        )
225
                    );
226
                }
227
228
                $query->orderBy($sortField, $sortDirection);
229
            }
230
        }
231
    }
232
}
233