Passed
Push — feature/collation ( 3b40b8...35613b )
by Kit Loong
64:11
created

IndexGenerator::generate()   B

Complexity

Conditions 11
Paths 25

Size

Total Lines 40
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 24
c 1
b 0
f 0
nc 25
nop 3
dl 0
loc 40
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: liow.kitloong
5
 * Date: 2020/03/29
6
 */
7
8
namespace KitLoong\MigrationsGenerator\Generators;
9
10
use Doctrine\DBAL\Schema\Index;
11
use Illuminate\Support\Collection;
12
use KitLoong\MigrationsGenerator\MigrationMethod\IndexType;
13
use KitLoong\MigrationsGenerator\MigrationsGeneratorSetting;
14
use KitLoong\MigrationsGenerator\Repositories\PgSQLRepository;
15
use KitLoong\MigrationsGenerator\Repositories\SQLSrvRepository;
16
17
class IndexGenerator
18
{
19
    private $decorator;
20
    private $pgSQLRepository;
21
    private $sqlSrvRepository;
22
23
    public function __construct(Decorator $decorator, PgSQLRepository $pgSQLRepository, SQLSrvRepository $sqlSrvRepository)
24
    {
25
        $this->decorator = $decorator;
26
        $this->pgSQLRepository = $pgSQLRepository;
27
        $this->sqlSrvRepository = $sqlSrvRepository;
28
    }
29
30
    /**
31
     * @param  string  $table
32
     * @param  Index[]  $indexes
33
     * @param  bool  $ignoreIndexNames
34
     * @return Collection[]
35
     */
36
    public function generate(string $table, $indexes, bool $ignoreIndexNames): array
37
    {
38
        $singleColIndexes = collect([]);
39
        $multiColIndexes = collect([]);
40
41
        // Doctrine/Dbal doesn't return spatial information from PostgreSQL
42
        // Use raw SQL here to create $spatial index name list.
43
        $spatials = $this->getSpatialList($table);
44
45
        foreach ($indexes as $index) {
46
            $indexField = [
47
                'field' => array_map([$this->decorator, 'addSlash'], $index->getColumns()),
48
                'type' => IndexType::INDEX,
49
                'args' => [],
50
            ];
51
52
            if ($index->isPrimary()) {
53
                $indexField['type'] = IndexType::PRIMARY;
54
            } elseif ($index->isUnique()) {
55
                $indexField['type'] = IndexType::UNIQUE;
56
            } elseif ((
57
                    count($index->getFlags()) > 0 && $index->hasFlag('spatial')
58
                ) || $spatials->contains($index->getName())) {
59
                $indexField['type'] = IndexType::SPATIAL_INDEX;
60
            }
61
62
            if (!$index->isPrimary()) {
63
                if (!$ignoreIndexNames && !$this->useLaravelStyleDefaultName($table, $index, $indexField['type'])) {
64
                    $indexField['args'][] = $this->decorateName($index->getName());
65
                }
66
            }
67
68
            if (count($index->getColumns()) === 1) {
69
                $singleColIndexes->put($this->decorator->addSlash($index->getColumns()[0]), $indexField);
70
            } else {
71
                $multiColIndexes->push($indexField);
72
            }
73
        }
74
75
        return ['single' => $singleColIndexes, 'multi' => $multiColIndexes];
76
    }
77
78
    private function getLaravelStyleDefaultName(string $table, array $columns, string $type): string
79
    {
80
        if ($type === IndexType::PRIMARY) {
81
            return 'PRIMARY';
82
        }
83
84
        $index = strtolower($table.'_'.implode('_', $columns).'_'.$type);
85
        return str_replace(['-', '.'], '_', $index);
86
    }
87
88
    private function useLaravelStyleDefaultName(string $table, Index $index, string $type): bool
89
    {
90
        return $this->getLaravelStyleDefaultName($table, $index->getColumns(), $type) === $index->getName();
91
    }
92
93
    private function decorateName(string $name): string
94
    {
95
        return "'".$this->decorator->addSlash($name)."'";
96
    }
97
98
    /**
99
     * Doctrine/Dbal doesn't return spatial information from PostgreSQL
100
     * Use raw SQL here to create $spatial index name list.
101
     * @param  string  $table
102
     * @return \Illuminate\Support\Collection Spatial index name list
103
     */
104
    private function getSpatialList(string $table): Collection
105
    {
106
        switch (app(MigrationsGeneratorSetting::class)->getPlatform()) {
107
            case Platform::POSTGRESQL:
108
                return $this->pgSQLRepository->getSpatialIndexNames($table);
109
            case Platform::SQLSERVER:
110
                return $this->sqlSrvRepository->getSpatialIndexNames($table);
111
            default:
112
                return collect([]);
113
        }
114
    }
115
}
116