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: // If the relation name is provided, then we're fixing an ordered relation:
29: if ($relationName) {
30: $this->fixRelation($instance, $relationName);
31: return;
32: }
33: // else, it's an orderable model.
34:
35: // Let's check that the model uses the Orderable trait:
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: // The treatment will be different whether the model is groupable or not:
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: