1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Elgg\Database; |
4
|
|
|
|
5
|
|
|
use Elgg\Cli\Command; |
6
|
|
|
use Elgg\Cli\Progress; |
7
|
|
|
use Elgg\Database\Seeds\Seed; |
8
|
|
|
use Elgg\EventsService; |
9
|
|
|
use Elgg\I18n\Translator; |
10
|
|
|
use Elgg\Invoker; |
11
|
|
|
|
12
|
|
|
/** |
13
|
|
|
* Seeder class |
14
|
|
|
* |
15
|
|
|
* Populates the database with rows for testing |
16
|
|
|
* |
17
|
|
|
* @internal |
18
|
|
|
*/ |
19
|
|
|
class Seeder { |
20
|
|
|
|
21
|
|
|
protected EventsService $events; |
22
|
|
|
|
23
|
|
|
protected Progress $progress; |
24
|
|
|
|
25
|
|
|
protected Invoker $invoker; |
26
|
|
|
|
27
|
|
|
protected Translator $translator; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Seeder constructor. |
31
|
|
|
* |
32
|
|
|
* @param EventsService $events Events service |
33
|
|
|
* @param Progress $progress Progress helper |
34
|
|
|
* @param Invoker $invoker Invoker service |
35
|
|
|
* @param Translator $translator Translator |
36
|
|
|
*/ |
37
|
4 |
|
public function __construct( |
38
|
|
|
EventsService $events, |
39
|
|
|
Progress $progress, |
40
|
|
|
Invoker $invoker, |
41
|
|
|
Translator $translator |
42
|
|
|
) { |
43
|
4 |
|
$this->events = $events; |
44
|
4 |
|
$this->progress = $progress; |
45
|
4 |
|
$this->invoker = $invoker; |
46
|
4 |
|
$this->translator = $translator; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Load seed scripts |
51
|
|
|
* |
52
|
|
|
* @param array $options options for seeding |
53
|
|
|
* - limit: the max number of entities to seed |
54
|
|
|
* - image_folder: a global (local) image folder to use for image seeding (user/group profile icon, etc) |
55
|
|
|
* - type: only seed this content type |
56
|
|
|
* - create: create new entities (default: false) |
57
|
|
|
* - create_since: lower bound creation time (default: now) |
58
|
|
|
* - create_until: upper bound creation time (default: now) |
59
|
|
|
* |
60
|
|
|
* @return void |
61
|
|
|
*/ |
62
|
1 |
|
public function seed(array $options = []): void { |
63
|
1 |
|
$this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($options) { |
64
|
1 |
|
$defaults = [ |
65
|
1 |
|
'limit' => null, |
66
|
1 |
|
'image_folder' => elgg_get_config('seeder_local_image_folder'), |
67
|
1 |
|
'type' => '', |
68
|
1 |
|
'create' => false, |
69
|
1 |
|
'create_since' => 'now', |
70
|
1 |
|
'create_until' => 'now', |
71
|
1 |
|
'interactive' => true, |
72
|
1 |
|
'cli_command' => null, |
73
|
1 |
|
]; |
74
|
1 |
|
$options = array_merge($defaults, $options); |
75
|
|
|
|
76
|
|
|
// set global configuration |
77
|
1 |
|
if ($options['image_folder'] !== $defaults['image_folder']) { |
78
|
1 |
|
elgg_set_config('seeder_local_image_folder', $options['image_folder']); |
79
|
|
|
} |
80
|
|
|
|
81
|
1 |
|
unset($options['image_folder']); |
82
|
|
|
|
83
|
|
|
// fetch CLI command |
84
|
1 |
|
$cli_command = $options['cli_command']; |
85
|
1 |
|
unset($options['cli_command']); |
86
|
|
|
|
87
|
|
|
// interactive mode |
88
|
1 |
|
$interactive = $options['interactive'] && empty($options['type']); |
89
|
1 |
|
unset($options['interactive']); |
90
|
|
|
|
91
|
1 |
|
$seeds = $this->getSeederClasses(); |
92
|
1 |
|
foreach ($seeds as $seed) { |
93
|
1 |
|
$seed_options = $options; |
94
|
|
|
|
95
|
|
|
// check for type limitation |
96
|
1 |
|
if (!empty($seed_options['type']) && $seed_options['type'] !== $seed::getType()) { |
97
|
|
|
continue; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
// check the seed limit |
101
|
1 |
|
$seed_options['limit'] = $seed_options['limit'] ?? $seed::getDefaultLimit(); |
102
|
1 |
|
if ($interactive && $cli_command instanceof Command) { |
103
|
1 |
|
$seed_options['limit'] = (int) $cli_command->ask($this->translator->translate('cli:database:seed:ask:limit', [$seed::getType()]), $seed_options['limit'], false, false); |
104
|
|
|
} |
105
|
|
|
|
106
|
1 |
|
if ($seed_options['limit'] < 1) { |
107
|
|
|
// skip seeding |
108
|
|
|
continue; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/* @var $seeder Seed */ |
112
|
1 |
|
$seeder = new $seed($seed_options); |
113
|
|
|
|
114
|
1 |
|
$progress_bar = $this->progress->start($seed, $seed_options['limit']); |
115
|
|
|
|
116
|
1 |
|
$seeder->setProgressBar($progress_bar); |
117
|
|
|
|
118
|
1 |
|
$seeder->seed(); |
119
|
|
|
|
120
|
1 |
|
$this->progress->finish($progress_bar); |
121
|
|
|
} |
122
|
1 |
|
}); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Remove all seeded entities |
127
|
|
|
* |
128
|
|
|
* @param array $options unseeding options |
129
|
|
|
* - type: only unseed this content type |
130
|
|
|
* |
131
|
|
|
* @return void |
132
|
|
|
*/ |
133
|
1 |
|
public function unseed(array $options = []): void { |
134
|
1 |
|
$this->invoker->call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES | ELGG_DISABLE_SYSTEM_LOG, function() use ($options) { |
135
|
1 |
|
$defaults = [ |
136
|
1 |
|
'type' => '', |
137
|
1 |
|
]; |
138
|
1 |
|
$options = array_merge($defaults, $options); |
139
|
|
|
|
140
|
1 |
|
$seeds = $this->getSeederClasses(); |
141
|
|
|
|
142
|
1 |
|
foreach ($seeds as $seed) { |
143
|
|
|
// check for type limitation |
144
|
1 |
|
if (!empty($options['type']) && $options['type'] !== $seed::getType()) { |
145
|
|
|
continue; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/* @var $seeder Seed */ |
149
|
1 |
|
$seeder = new $seed(); |
150
|
|
|
|
151
|
1 |
|
$progress_bar = $this->progress->start($seed, $seeder->getCount()); |
152
|
|
|
|
153
|
1 |
|
$seeder->setProgressBar($progress_bar); |
154
|
|
|
|
155
|
1 |
|
$seeder->unseed(); |
156
|
|
|
|
157
|
1 |
|
$this->progress->finish($progress_bar); |
158
|
|
|
} |
159
|
1 |
|
}); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Get the class names of all registered seeders (verified to work for seeding) |
164
|
|
|
* |
165
|
|
|
* @return string[] |
166
|
|
|
*/ |
167
|
3 |
|
public function getSeederClasses(): array { |
168
|
3 |
|
$result = []; |
169
|
|
|
|
170
|
3 |
|
$seeds = $this->events->triggerResults('seeds', 'database', [], []); |
171
|
3 |
|
foreach ($seeds as $seed) { |
172
|
3 |
|
if (!class_exists($seed)) { |
173
|
|
|
elgg_log("Seeding class {$seed} not found", 'ERROR'); |
174
|
|
|
continue; |
175
|
|
|
} |
176
|
|
|
|
177
|
3 |
|
if (!is_subclass_of($seed, Seed::class)) { |
178
|
|
|
elgg_log("Seeding class {$seed} does not extend " . Seed::class, 'ERROR'); |
179
|
|
|
continue; |
180
|
|
|
} |
181
|
|
|
|
182
|
3 |
|
$result[] = $seed; |
183
|
|
|
} |
184
|
|
|
|
185
|
3 |
|
return $result; |
186
|
|
|
} |
187
|
|
|
} |
188
|
|
|
|