Completed
Push — master ( 054210...4c2c87 )
by Scott
03:56
created

Category::getParentCategoryIds()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 6
nc 2
nop 0
1
<?php namespace Bedard\Shop\Models;
2
3
use Lang;
4
use Model;
5
6
/**
7
 * Category Model.
8
 */
9
class Category extends Model
10
{
11
    use \October\Rain\Database\Traits\Validation;
12
13
    /**
14
     * @var string The database table used by the model.
15
     */
16
    public $table = 'bedard_shop_categories';
17
18
    /**
19
     * @var array Default attributes
20
     */
21
    public $attributes = [
22
        'description_html' => '',
23
        'description_plain' => '',
24
    ];
25
26
    /**
27
     * @var array Attribute casting
28
     */
29
    protected $casts = [
30
        'is_active' => 'boolean',
31
        'is_visible' => 'boolean',
32
    ];
33
34
    /**
35
     * @var array Guarded fields
36
     */
37
    protected $guarded = ['*'];
38
39
    /**
40
     * @var array Fillable fields
41
     */
42
    protected $fillable = [
43
        'is_active',
44
        'is_visible',
45
        'description_html',
46
        'description_plain',
47
        'name',
48
        'parent_id',
49
        'slug',
50
    ];
51
52
    /**
53
     * @var array Relations
54
     */
55
    public $belongsTo = [
56
        'parent' => 'Bedard\Shop\Models\Category',
57
    ];
58
59
    public $belongsToMany = [
60
        'discounts' => [
61
            'Bedard\Shop\Models\Discount',
62
            'table' => 'bedard_shop_category_discount',
63
        ],
64
        'products' => [
65
            'Bedard\Shop\Models\Product',
66
            'table' => 'bedard_shop_category_product',
67
            'pivot' => ['is_inherited'],
68
        ],
69
    ];
70
71
    /**
72
     * @var array Validation
73
     */
74
    public $rules = [
75
        'name' => 'required',
76
        'slug' => 'required|unique:bedard_shop_categories',
77
    ];
78
79
    /**
80
     * After save.
81
     *
82
     * @return void
83
     */
84
    public function afterSave()
85
    {
86
        $this->syncInheritedProducts();
87
    }
88
89
    /**
90
     * Before save.
91
     *
92
     * @return void
93
     */
94
    public function beforeSave()
95
    {
96
        $this->setPlainDescription();
97
        $this->setNullParentId();
98
    }
99
100
    /**
101
     * Get the parent IDs of every category
102
     *
103
     * @return array
104
     */
105
    public static function getParentCategoryIds() {
106
        $categories = self::select('id', 'parent_id')->get();
107
108
        $tree = [];
109
        foreach ($categories as $category) {
110
            $tree[$category->id] = self::walkParentCategories($categories, $category);
111
        }
112
113
        return $tree;
114
    }
115
116
    /**
117
     * Find the child ids of a parent category.
118
     *
119
     * @param  \Bedard\Shop\Models\Category|int     $parent
120
     * @param  \October\Rain\Database\Collection    $categories
121
     * @return array
122
     */
123
    public static function getChildIds($parent, \October\Rain\Database\Collection $categories = null)
124
    {
125
        if ($categories === null) {
126
            $categories = self::whereNotNull('parent_id')
127
                ->where('id', '<>', $parent)
128
                ->select('id', 'parent_id')
129
                ->get();
130
        }
131
132
        $children = [];
133
        foreach ($categories as $category) {
134
            if ($category->parent_id == $parent) {
135
                $children[] = $category->id;
136
                $children = array_merge($children, self::getChildIds($category->id, $categories));
137
            }
138
        }
139
140
        return $children;
141
    }
142
143
    public static function getParentIds($children, \October\Rain\Database\Collection $categories = null)
144
    {
145
        if (! is_array($children)) {
146
            $children = [$children];
147
        }
148
149
        if ($categories === null) {
150
            $categories = self::select('id', 'parent_id')->get();
151
        }
152
153
        $parents = [];
154
        foreach ($children as $child) {
155
            $category = $categories->filter(function ($model) use ($child) {
156
                return $model->id == $child;
157
            })->first();
158
159
            while ($category && $category->parent_id) {
160
                $parents[] = $category->parent_id;
161
                $category = $categories->filter(function ($model) use ($category) {
162
                    return $model->id == $category->parent_id;
163
                })->first();
164
            }
165
        }
166
167
        return array_unique($parents);
168
    }
169
170
    /**
171
     * Get options for the parent form field.
172
     *
173
     * @return array
174
     */
175
    public function getParentIdOptions()
176
    {
177
        $options = $this->exists
178
            ? self::where('id', '<>', $this->id)->isNotChildOf($this->id)->orderBy('name')->lists('name', 'id')
179
            : self::orderBy('name')->lists('name', 'id');
180
181
        array_unshift($options, '<em>'.Lang::get('bedard.shop::lang.categories.form.no_parent').'</em>');
182
183
        return $options;
184
    }
185
186
    /**
187
     * Query categories that are children of another category.
188
     *
189
     * @param  \October\Rain\Database\Builder   $query
190
     * @param  \Bedard\Shop\Models\Category|int $parent
191
     * @return \October\Rain\Database\Builder
192
     */
193
    public function scopeIsChildOf($query, $parent)
194
    {
195
        return $query->whereIn('id', self::getChildIds($parent));
196
    }
197
198
    /**
199
     * Query categories that are not children of another category.
200
     *
201
     * @param  \October\Rain\Database\Builder   $query
202
     * @param  \Bedard\Shop\Models\Category|int $parent
203
     * @return \October\Rain\Database\Builder
204
     */
205
    public function scopeIsNotChildOf($query, $parent)
206
    {
207
        return $query->whereNotIn('id', self::getChildIds($parent));
208
    }
209
210
    /**
211
     * Query categories that are a parent of another category.
212
     *
213
     * @param  \October\Rain\Database\Builder   $query
214
     * @param  int                              $child
215
     * @return \October\Rain\Database\Builder
216
     */
217
    public function scopeIsParentOf($query, $child)
218
    {
219
        return $query->whereIn('id', self::getParentIds($child));
220
    }
221
222
    /**
223
     * Query categories that are not a parent of another category.
224
     *
225
     * @param  \October\Rain\Database\Builder   $query
226
     * @param  int                              $child
227
     * @return \October\Rain\Database\Builder
228
     */
229
    public function scopeIsNotParentOf($query, $child)
230
    {
231
        return $query->whereNotIn('id', self::getParentIds($child));
232
    }
233
234
    /**
235
     * Convert falsey parent id values to null.
236
     *
237
     * @return void
238
     */
239
    public function setNullParentId()
240
    {
241
        if (! $this->parent_id) {
242
            $this->parent_id = null;
243
        }
244
    }
245
246
    /**
247
     * Set the plain text description_html.
248
     *
249
     * @return void
250
     */
251
    public function setPlainDescription()
252
    {
253
        $this->description_plain = strip_tags($this->description_html);
254
    }
255
256
    /**
257
     * If the parent id has changed, resync all products.
258
     *
259
     * @return void
260
     */
261
    public function syncInheritedProducts()
262
    {
263
        if ($this->isDirty('parent_id')) {
264
            Product::syncAllInheritedCategories();
265
        }
266
    }
267
268
    /**
269
     * Itterate over categories and update them with the given values.
270
     *
271
     * @param  array    $categories
272
     * @return void
273
     */
274
    public static function updateMany(array $categories)
275
    {
276
        foreach ($categories as $category) {
277
            $id = $category['id'];
278
            unset($category['id']);
279
            self::whereId($id)->update($category);
280
        }
281
    }
282
283
    /**
284
     * Walk up the category tree gathering parent IDs.
285
     *
286
     * @param  \October\Rain\Database\Collection    $categories     All categories
287
     * @param  \Bedard\Shop\Models\Category         $category       Current category being walked over
288
     * @param  array                                $tree           Tree of parent IDs
289
     * @return arrau
290
     */
291
    public static function walkParentCategories($categories, $category, $tree = [])
292
    {
293
        if ($category->parent_id !== null) {
294
            $tree[] = $category->parent_id;
295
            $tree = array_merge($tree, self::walkParentCategories($categories, $categories->find($category->parent_id)));
296
        }
297
298
        return $tree;
299
    }
300
}
301