Passed
Push — main ( cd768a...3938b8 )
by Sugeng
02:39
created

TableSeeder::batchInsert()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 9
rs 10
cc 3
nc 2
nop 3
1
<?php
2
3
namespace diecoding\seeder;
4
5
use Faker\Factory;
6
use Yii;
7
use yii\base\NotSupportedException;
8
use yii\db\Exception;
9
use yii\db\Migration;
10
use yii\helpers\ArrayHelper;
11
12
/**
13
 * Class TableSeeder
14
 * 
15
 * @package diecoding\seeder
16
 *
17
 * @link [sugeng-sulistiyawan.github.io](sugeng-sulistiyawan.github.io)
18
 * @author Sugeng Sulistiyawan <[email protected]>
19
 * @copyright Copyright (c) 2023
20
 */
21
abstract class TableSeeder extends Migration
22
{
23
    /** @var \Faker\Generator|Factory */
24
    public $faker;
25
26
    /** @var bool `true` for truncate tables before run seeder, default `true` */
27
    public $truncateTable = true;
28
29
    /** @var string|null if `null` use `Yii::$app->language`, default `null` */
30
    public $locale;
31
32
    /** @var array */
33
    protected $insertedColumns = [];
34
35
    /** @var array */
36
    protected $batch = [];
37
38
    /**
39
     * TableSeeder constructor.
40
     * 
41
     * @param array $config
42
     */
43
    public function __construct(array $config = [])
44
    {
45
        if ($this->locale === null) {
46
            $this->locale = str_replace('-', '_', Yii::$app->language);
47
        }
48
        $this->faker = Factory::create($this->locale);
49
50
        parent::__construct($config);
51
    }
52
53
    /**
54
     * TableSeeder destructor.
55
     * 
56
     * @throws Exception
57
     * @throws NotSupportedException
58
     */
59
    public function __destruct()
60
    {
61
        if ($this->truncateTable) {
62
            $this->disableForeignKeyChecks();
63
            foreach ($this->batch as $table => $values) {
64
                $this->truncateTable($table);
65
            }
66
            $this->enableForeignKeyChecks();
67
        }
68
69
        foreach ($this->batch as $table => $values) {
70
            $total = 0;
71
            foreach ($values as $columns => $rows) {
72
                $total += count($rows);
73
                parent::batchInsert($table, explode(',', $columns), $rows);
74
            }
75
            echo "      $total row" . ($total > 1 ? 's' : null) . " inserted  in $table" . "\n";
76
        }
77
78
        $this->checkMissingColumns($this->insertedColumns);
79
    }
80
81
    /**
82
     * @return void
83
     */
84
    abstract function run();
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
85
86
    /**
87
     * @throws Exception
88
     * @throws NotSupportedException
89
     */
90
    public function disableForeignKeyChecks()
91
    {
92
        $this->db->createCommand()->checkIntegrity(false)->execute();
93
    }
94
95
    /**
96
     * @throws Exception
97
     * @throws NotSupportedException
98
     */
99
    public function enableForeignKeyChecks()
100
    {
101
        $this->db->createCommand()->checkIntegrity(true)->execute();
102
    }
103
104
    /**
105
     * Creates and executes an INSERT SQL statement.
106
     * The method will properly escape the column names, and bind the values to be inserted.
107
     * @param string $table the table that new rows will be inserted into.
108
     * @param array $columns the column data (name => value) to be inserted into the table.
109
     */
110
    public function insert($table, $columns)
111
    {
112
        $this->insertedColumns[$table] = ArrayHelper::merge(
113
            array_keys($columns),
114
            isset($this->insertedColumns[$table]) ? $this->insertedColumns[$table] : []
115
        );
116
117
        $this->batch[$table][implode(',', array_keys($columns))][] = array_values($columns);
118
    }
119
120
    /**
121
     * Creates and executes a batch INSERT SQL statement.
122
     * The method will properly escape the column names, and bind the values to be inserted.
123
     * @param string $table the table that new rows will be inserted into.
124
     * @param array $columns the column names.
125
     * @param array $rows the rows to be batch inserted into the table
126
     */
127
    public function batchInsert($table, $columns, $rows)
128
    {
129
        $this->insertedColumns[$table] = ArrayHelper::merge(
130
            $columns,
131
            isset($this->insertedColumns[$table]) ? $this->insertedColumns[$table] : []
132
        );
133
134
        foreach ($rows as $row) {
135
            $this->batch[$table][implode(',', $columns)][] = $row;
136
        }
137
    }
138
139
    /**
140
     * Check missing column
141
     *
142
     * @param array $insertedColumns
143
     * @return void
144
     */
145
    protected function checkMissingColumns($insertedColumns)
146
    {
147
        $missingColumns = [];
148
149
        foreach ($insertedColumns as $table => $columns) {
150
            $tableColumns = $this->db->getTableSchema($table)->columns;
151
152
            foreach ($tableColumns as $tableColumn) {
153
                if (!$tableColumn->autoIncrement && !in_array($tableColumn->name, $columns, true)) {
154
                    $missingColumns[$table][] = [$tableColumn->name, $tableColumn->dbType];
155
                }
156
            }
157
        }
158
159
        if (count($missingColumns)) {
160
            echo "    > " . str_pad(' MISSING COLUMNS ', 70, '#', STR_PAD_BOTH) . "\n";
161
            foreach ($missingColumns as $table => $columns) {
162
                echo "    > " . str_pad("# TABLE: $table", 69, ' ') . "#\n";
163
                foreach ($columns as [$tableColumn, $type]) {
164
                    echo "    > " . str_pad("#    $tableColumn => $type", 69, ' ') . "#\n";
165
                }
166
            }
167
            echo "    > " . str_pad('', 70, '#') . "\n";
168
        }
169
    }
170
171
    /**
172
     * @return static
173
     */
174
    public static function create()
175
    {
176
        return new static;
177
    }
178
}
179