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