Completed
Push — master ( eb9a96...174aff )
by Gino
01:30
created

Tag::queryPostSlug()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 3
nc 2
nop 2
1
<?php
2
3
namespace GinoPane\BlogTaxonomy\Models;
4
5
use Str;
6
use RainLab\Blog\Models\Post;
7
use GinoPane\BlogTaxonomy\Plugin;
8
use October\Rain\Database\Builder;
9
use October\Rain\Database\Traits\Sluggable;
10
use October\Rain\Database\Traits\Validation;
11
use October\Rain\Database\Relations\MorphToMany;
12
13
/**
14
 * Class Tag
15
 *
16
 * @property string name
17
 * @property string slug
18
 * @property int posts_count Post count of posts associated with the tag
19
 * @property int series_posts_count Post count of posts associated with the tag via the series
20
 *
21
 * @package GinoPane\BlogTaxonomy\Models
22
 */
23
class Tag extends ModelAbstract
24
{
25
    use Sluggable;
26
    use Validation;
27
28
    const TABLE_NAME = 'ginopane_blogtaxonomy_tags';
29
30
    /** @deprecated */
31
    const CROSS_REFERENCE_TABLE_NAME = 'ginopane_blogtaxonomy_post_tag';
32
33
    const PIVOT_COLUMN = 'ginopane_blogtaxonomy_taggable';
34
35
    const PIVOT_TABLE = 'ginopane_blogtaxonomy_taggables';
36
37
    /**
38
     * @var string The database table used by the model
39
     */
40
    public $table = self::TABLE_NAME;
41
42
    /**
43
     * Specifying of implemented behaviours as strings is convenient when
44
     * the target behaviour could be missing due to disabled or not installed
45
     * plugin. You won't get an error, the plugin would simply work without model
46
     *
47
     * @var array
48
     */
49
    public $implement = ['@RainLab.Translate.Behaviors.TranslatableModel'];
50
51
    /**
52
     * Translatable properties, indexed property will be available in queries
53
     *
54
     * @var array
55
     */
56
    public $translatable = [
57
        'name',
58
        [
59
            'slug',
60
            'index' => true
61
        ]
62
    ];
63
64
    /**
65
     * @var array
66
     */
67
    protected $slugs = ['slug' => 'name'];
68
69
    /**
70
     * Relations
71
     *
72
     * @var array
73
     */
74
    public $morphedByMany = [
75
        'posts'  => [Post::class, 'name' => Tag::PIVOT_COLUMN],
76
        'series'  => [Series::class, 'name' => Tag::PIVOT_COLUMN],
77
    ];
78
79
    /**
80
     * Fillable fields
81
     *
82
     * @var array
83
     */
84
    public $fillable = [
85
        'name',
86
        'slug',
87
    ];
88
89
    /**
90
     * Validation rules
91
     *
92
     * @var array
93
     */
94
    public $rules = [
95
        'name' => "required|unique:" . self::TABLE_NAME . "|min:2|regex:/^[\w\-\. ]+$/iu",
96
        'slug' => "required|unique:" . self::TABLE_NAME . "|min:2|regex:/^[\w\-]+$/iu"
97
    ];
98
99
    /**
100
     * The tag might be created via tag list and therefore it won't have a slug
101
     */
102
    public function beforeValidate()
103
    {
104
        // Generate a URL slug for this model
105
        if (!$this->exists && !$this->slug) {
106
            $this->slug = Str::slug($this->name);
107
        }
108
    }
109
110
    /**
111
     * Validation messages
112
     *
113
     * @var array
114
     */
115
    public $customMessages = [
116
        'name.required' => Plugin::LOCALIZATION_KEY . 'form.tags.name_required',
117
        'name.unique'   => Plugin::LOCALIZATION_KEY . 'form.tags.name_unique',
118
        'name.regex'    => Plugin::LOCALIZATION_KEY . 'form.tags.name_invalid',
119
        'name.min'      => Plugin::LOCALIZATION_KEY . 'form.tags.name_too_short',
120
121
        'slug.required' => Plugin::LOCALIZATION_KEY . 'form.tags.slug_required',
122
        'slug.unique'   => Plugin::LOCALIZATION_KEY . 'form.tags.slug_unique',
123
        'slug.regex'    => Plugin::LOCALIZATION_KEY . 'form.tags.slug_invalid',
124
        'slug.min'      => Plugin::LOCALIZATION_KEY . 'form.tags.slug_too_short',
125
    ];
126
127
    /**
128
     * The attributes on which the post list can be ordered
129
     *
130
     * @var array
131
     */
132
     public static $sortingOptions = [
133
        'name asc' => Plugin::LOCALIZATION_KEY . 'order_options.name_asc',
134
        'name desc' => Plugin::LOCALIZATION_KEY . 'order_options.name_desc',
135
        'created_at asc' => Plugin::LOCALIZATION_KEY . 'order_options.created_at_asc',
136
        'created_at desc' => Plugin::LOCALIZATION_KEY . 'order_options.created_at_desc',
137
        'posts_count asc' => Plugin::LOCALIZATION_KEY . 'order_options.post_count_asc',
138
        'posts_count desc' => Plugin::LOCALIZATION_KEY . 'order_options.post_count_desc',
139
        'random' => Plugin::LOCALIZATION_KEY . 'order_options.random'
140
    ];
141
142
    /**
143
     * Returns post combined combined from posts with this tag and posts with series under this this tag
144
     *
145
     * @return int
146
     */
147
    public function getCombinedPostCountAttribute(): int
148
    {
149
        return $this->posts_count + $this->series_posts_count;
150
    }
151
152
    /**
153
     * @param array $params
154
     *
155
     * @return array
156
     */
157
    protected function getModelUrlParams(array $params): array
158
    {
159
        return [
160
            array_get($params, 'tag', 'tag') => $this->slug
161
        ];
162
    }
163
164
    /**
165
     * @param Builder $query
166
     * @param array   $options
167
     *
168
     * @return void
169
     */
170
    protected function withRelation(Builder $query, array $options)
171
    {
172
        $this->postRelation($query, $options);
173
174
        $this->seriesRelation($query, $options);
175
    }
176
177
    /**
178
     * @param Builder $query
179
     * @param array   $options
180
     */
181
    protected function queryPostSlug(Builder $query, array $options)
182
    {
183
        parent::queryPostSlug($query, $options);
184
185
        if (!empty($options['post']) && !empty($options['includeSeriesTags'])) {
186
            $query->orWhereHas('series', static function ($query) use ($options) {
187
                $query->whereHas(
188
                    'posts',
189
                    static function ($query) use ($options) {
190
                        ModelAbstract::whereTranslatableProperty($query, 'slug', $options['post']);
191
                    });
192
            });
193
        }
194
    }
195
196
    /**
197
     * @param Builder $query
198
     * @param array   $options
199
     *
200
     * @return void
201
     */
202 View Code Duplication
    private function postRelation(Builder $query, array $options)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
203
    {
204
        if (!empty($options['fetchPosts'])) {
205
            $query->with(
206
                [
207
                    'posts' => static function (MorphToMany $query) use ($options) {
208
                        $query->isPublished();
209
210
                        self::handleExceptions($query->getQuery(), $options);
211
                    }
212
                ]
213
            );
214
        }
215
216
        $query->withCount(
217
            [
218
                'posts' => static function ($query) use ($options) {
219
                    $query->isPublished();
220
221
                    self::handleExceptions($query, $options);
222
                }
223
            ]
224
        );
225
    }
226
227
    /**
228
     * @param Builder $query
229
     * @param array   $options
230
     *
231
     * @return void
232
     */
233 View Code Duplication
    private function seriesRelation(Builder $query, array $options)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
    {
235
        $query->withCount('series');
236
237
        if (!empty($options['fetchSeriesPostCount'])) {
238
            $query->with(
239
                [
240
                    'series' => static function (MorphToMany $query) use ($options) {
241
                        $query->withCount(
242
                            [
243
                                'posts' => static function ($query) use ($options) {
244
                                    $query->isPublished();
245
246
                                    self::handleExceptions($query, $options);
247
                                }
248
                            ]
249
                        );
250
                    }
251
                ]
252
            );
253
        }
254
    }
255
}
256