Completed
Pull Request — master (#52)
by Gino
01:54
created

components/RelatedPosts.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
16
/**
17
 * Class RelatedPosts
18
 *
19
 * @package GinoPane\BlogTaxonomy\Components
20
 */
21
class RelatedPosts extends ComponentAbstract
22
{
23
    const NAME = 'relatedPosts';
24
25
    use TranslateArrayTrait;
26
27
    /**
28
     * @var Collection | array
29
     */
30
    public $posts = [];
31
32
    /**
33
     * Reference to the page name for linking to posts
34
     *
35
     * @var string
36
     */
37
    public $postPage;
38
39
    /**
40
     * If the post list should be ordered by another attribute
41
     *
42
     * @var string
43
     */
44
    public $orderBy;
45
46
    /**
47
     * Limits the number of records to display
48
     *
49
     * @var int
50
     */
51
    public $limit;
52
53
    /**
54
     * Component Registration
55
     *
56
     * @return  array
57
     */
58
    public function componentDetails()
59
    {
60
        return [
61
            'name'        => Plugin::LOCALIZATION_KEY . 'components.related_posts.name',
62
            'description' => Plugin::LOCALIZATION_KEY . 'components.related_posts.description'
63
        ];
64
    }
65
66
    /**
67
     * Component Properties
68
     *
69
     * @return  array
70
     */
71
    public function defineProperties()
72
    {
73
        return [
74
            'slug' => [
75
                'title'             => Plugin::LOCALIZATION_KEY . 'components.related_posts.post_slug_title',
76
                'description'       => Plugin::LOCALIZATION_KEY . 'components.related_posts.post_slug_description',
77
                'default'           => '{{ :slug }}',
78
                'type'              => 'string'
79
            ],
80
81
            'limit' => [
82
                'title'             => Plugin::LOCALIZATION_KEY . 'components.related_posts.limit_title',
83
                'description'       => Plugin::LOCALIZATION_KEY . 'components.related_posts.limit_description',
84
                'type'              => 'string',
85
                'default'           => '0',
86
                'validationPattern' => '^[0-9]+$',
87
                'validationMessage' => Plugin::LOCALIZATION_KEY . 'components.related_posts.limit_validation_message',
88
                'showExternalParam' => false
89
            ],
90
91
            'orderBy' => [
92
                'title'       => 'rainlab.blog::lang.settings.posts_order',
93
                'description' => 'rainlab.blog::lang.settings.posts_order_description',
94
                'type'        => 'dropdown',
95
                'default'     => 'published_at asc',
96
                'showExternalParam' => false
97
            ],
98
99
            'postPage' => [
100
                'group'       => Plugin::LOCALIZATION_KEY . 'components.related_posts.links_group',
101
                'title'       => 'rainlab.blog::lang.settings.posts_post',
102
                'description' => 'rainlab.blog::lang.settings.posts_description',
103
                'type'        => 'dropdown',
104
                'default'     => 'blog/post',
105
            ],
106
        ];
107
    }
108
109
    /**
110
     * @see PostListAbstract::$postAllowedSortingOptions
111
     *
112
     * @return mixed
113
     */
114
    public function getOrderByOptions()
115
    {
116
        $order = $this->translate(
117
            array_merge(
118
                [
119
                    'relevance asc' => Plugin::LOCALIZATION_KEY . 'order_options.relevance_asc',
120
                    'relevance desc' => Plugin::LOCALIZATION_KEY . 'order_options.relevance_desc'
121
                ],
122
                PostListAbstract::$postAllowedSortingOptions
123
            )
124
        );
125
126
        asort($order);
127
128
        return $order;
129
    }
130
131
    private function prepareVars()
132
    {
133
        $this->orderBy = $this->page['orderBy'] = $this->property('orderBy');
134
135
        // Page links
136
        $this->postPage = $this->page['postPage' ] = $this->property('postPage');
137
    }
138
139
    public function getPostPageOptions()
140
    {
141
        return Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
142
    }
143
144
    /**
145
     * Load post and start building query for related posts
146
     */
147
    public function onRun()
148
    {
149
        //Prepare vars
150
        $this->prepareVars();
151
152
        $this->posts = $this->loadRelatedPosts();
153
    }
154
155
    /**
156
     * Load related posts by common tags
157
     *
158
     * @return mixed
159
     */
160
    private function loadRelatedPosts()
161
    {
162
        $post = Post::with('tags');
163
164
        ModelAbstract::whereTranslatableProperty($post, 'slug', $this->property('slug'));
165
166
        $post = $post->first();
167
168
        if (!$post || (!$tagIds = $post->tags->lists('id'))) {
169
            return null;
170
        }
171
172
        $query = Post::isPublished()
173
            ->where('id', '<>', $post->id)
174
            ->whereHas('tags', function ($tag) use ($tagIds) {
175
                $tag->whereIn('id', $tagIds);
176
            })
177
            ->with('tags');
178
179
        $this->queryOrderBy($query, $tagIds);
180
181
        if ($take = (int)$this->property('limit')) {
182
            $query->take($take);
183
        }
184
185
        $posts = $query->get();
186
187
        $this->setPostUrls($posts);
188
189
        return $posts;
190
    }
191
192
    /**
193
     * @param $query
194
     * @param $tagIds
195
     */
196
    private function queryOrderBy($query, $tagIds)
197
    {
198
        if (array_key_exists($this->orderBy, $this->getOrderByOptions())) {
199
            if ($this->orderBy === 'random') {
200
                $query->inRandomOrder();
201
            } else {
202
                list($sortField, $sortDirection) = explode(' ', $this->orderBy);
203
204
                if ($sortField === 'relevance') {
205
                    $sortField = DB::raw(
206
                        sprintf(
207
                            '(
208
                                select count(*)
209
                                from `%1$s`
210
                                where `%1$s`.`post_id` = `rainlab_blog_posts`.`id`
211
                                and `%1$s`.`tag_id` in (%2$s)
212
                            )',
213
                            Tag::CROSS_REFERENCE_TABLE_NAME,
0 ignored issues
show
Deprecated Code introduced by
The constant GinoPane\BlogTaxonomy\Mo...SS_REFERENCE_TABLE_NAME has been deprecated.

This class constant has been deprecated.

Loading history...
214
                            DB::getPdo()->quote(implode(', ', $tagIds))
215
                        )
216
                    );
217
                }
218
219
                $query->orderBy($sortField, $sortDirection);
220
            }
221
        }
222
    }
223
}
224