Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
FixTreeCommand
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
2 / 2
3
100.00% covered (success)
100.00%
1 / 1
 handle
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 rebuildClosures
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace Baril\Bonsai\Console;
4
5use Baril\Bonsai\Console\Concerns\InteractsWithTree;
6use Illuminate\Console\Command;
7
8class FixTreeCommand extends Command
9{
10    use InteractsWithTree;
11
12    protected $signature = 'bonsai:fix {model : The model class}';
13    protected $description = 'Rebuilds the closures for a given tree';
14
15    public function handle()
16    {
17        $model = $this->input->getArgument('model');
18
19        $this->checkModel($model);
20
21        $this->rebuildClosures($model);
22    }
23
24    protected function rebuildClosures($model)
25    {
26        $instance = new $model();
27        $connection = $instance->getConnection();
28        $connection->transaction(function () use ($instance, $connection) {
29            $table = $instance->getTable();
30            $parentKey = $instance->getParentForeignKeyName();
31            $primaryKey = $instance->getKeyName();
32            $closureTable = $instance->getClosureTable();
33
34            // Delete old closures:
35            $connection->table($closureTable)->delete();
36
37            // Insert "self-closures":
38            $select = $connection->table($table)->select($primaryKey, $primaryKey, $connection->raw('0'));
39            $connection->table($closureTable)->insertUsing(['ancestor_id', 'descendant_id', 'depth'], $select);
40
41            // Increment depth and insert closures until there's nothing left to insert:
42            $depth = 1;
43            $continue = true;
44            while ($continue) {
45                // INSERT INTO $closureTable (ancestor_id, descendant_id, depth)
46                // SELECT closure_table.ancestor_id, main_table.$primaryKey, $depth
47                // FROM $table AS main_table
48                // INNER JOIN $closureTable AS closure_table
49                //     ON main_table.$parentKey = closure_table.descendant_id
50                // WHERE closure_table.depth = $depth - 1"
51                $select = $connection
52                    ->table($table, 'main_table')
53                    ->join(
54                        "$closureTable as closure_table",
55                        "main_table.$parentKey",
56                        '=',
57                        'closure_table.descendant_id'
58                    )
59                    ->where('closure_table.depth', '=', $depth - 1)
60                    ->select('closure_table.ancestor_id', "main_table.$primaryKey", $connection->raw((string) $depth));
61                $connection->table($closureTable)->insertUsing(['ancestor_id', 'descendant_id', 'depth'], $select);
62
63                $continue = (bool) $connection->table($closureTable)->where('depth', '=', $depth)->exists();
64                $depth++;
65            }
66        });
67
68        $this->line("<info>Rebuilt the closures for:</info> $model");
69    }
70}