1: | <?php |
2: | |
3: | namespace Baril\Orderly\Console; |
4: | |
5: | use Baril\Orderly\Relations\BelongsToManyOrderable; |
6: | use Illuminate\Console\Command; |
7: | use Illuminate\Database\Eloquent\Model; |
8: | |
9: | class FixPositionsCommand extends Command |
10: | { |
11: | protected $signature = 'orderly:fix-positions |
12: | {model : The model class.} |
13: | {relationName? : The relationship to fix.}'; |
14: | protected $description = 'Rebuild the position column for a given orderable model or relation'; |
15: | |
16: | protected $chunks = 200; |
17: | |
18: | public function handle() |
19: | { |
20: | $model = $this->argument('model'); |
21: | $relationName = $this->argument('relationName'); |
22: | if (!class_exists($model) || !is_subclass_of($model, Model::class)) { |
23: | $this->error($model . ' is not a valid model class!'); |
24: | return; |
25: | } |
26: | $instance = new $model(); |
27: | |
28: | |
29: | if ($relationName) { |
30: | $this->fixRelation($instance, $relationName); |
31: | return; |
32: | } |
33: | |
34: | |
35: | |
36: | if (!method_exists($model, 'getOrderColumn')) { |
37: | $this->error('{model} must be a valid model class and use the Orderable trait!'); |
38: | return; |
39: | } |
40: | |
41: | |
42: | if ($instance->getGroupColumn()) { |
43: | $this->fixGroupable($instance); |
44: | } else { |
45: | $this->fixUngroupable($instance); |
46: | } |
47: | $this->info('Done!'); |
48: | } |
49: | |
50: | protected function fixUngroupable($instance) |
51: | { |
52: | $this->fixPositions($instance->newQuery()->ordered(), $instance); |
53: | } |
54: | |
55: | protected function fixGroupable($instance) |
56: | { |
57: | $column = (array) $instance->getGroupColumn(); |
58: | $query = $instance->newQueryWithoutScopes()->getQuery() |
59: | ->distinct() |
60: | ->select($column); |
61: | foreach ($column as $col) { |
62: | $query->orderBy($col); |
63: | } |
64: | $query->chunk($this->chunks, function ($groups) use ($instance, $column) { |
65: | foreach ($groups as $item) { |
66: | $group = []; |
67: | foreach ($column as $col) { |
68: | $group[] = $item->$col; |
69: | } |
70: | $query = $instance->newQuery()->whereGroup($group)->ordered(); |
71: | $this->fixPositions($query, $instance); |
72: | $this->line('<info>Fixed for group:</info> ' . implode(',', $group)); |
73: | } |
74: | }); |
75: | } |
76: | |
77: | protected function fixRelation($instance, $relationName) |
78: | { |
79: | try { |
80: | $relation = $instance->$relationName(); |
81: | if (!$relation instanceof BelongsToManyOrderable) { |
82: | $this->error($relationName . ' is not a valid belongs-to-many-ordered relationship!'); |
83: | return; |
84: | } |
85: | } catch (\Exception $e) { |
86: | $this->error($relationName . ' is not a valid relationship!'); |
87: | return; |
88: | } |
89: | |
90: | $query = $instance->newQuery() |
91: | ->select($instance->getKeyName()) |
92: | ->orderBy($instance->getKeyName()); |
93: | $query->chunk($this->chunks, function ($items) use ($relationName) { |
94: | foreach ($items as $item) { |
95: | $relation = $item->$relationName(); |
96: | $related = $relation->ordered()->get(); |
97: | $rownum = 0; |
98: | $related->each(function ($item) use ($relation, &$rownum) { |
99: | $id = $item->{$relation->getPivotAccessor()}->{$relation->getRelatedPivotKeyName()}; |
100: | $relation->updateExistingPivot($id, [ |
101: | $relation->getOrderColumn() => ++$rownum, |
102: | ], false); |
103: | }); |
104: | $this->line("<info>Fixed for model:</info> {$item->getKey()}"); |
105: | } |
106: | }); |
107: | } |
108: | |
109: | protected function fixPositions($query, $instance) |
110: | { |
111: | $query->updateColumnWithRowNumber($instance->getOrderColumn()); |
112: | } |
113: | } |
114: | |