1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: jgulledge |
5
|
|
|
* Date: 9/29/2017 |
6
|
|
|
* Time: 3:33 PM |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace LCI\Blend; |
10
|
|
|
|
11
|
|
|
use LCI\Blend\Console\Blend; |
12
|
|
|
use LCI\Blend\Exception\MigratorException; |
13
|
|
|
use LCI\Blend\Helpers\Format; |
14
|
|
|
use LCI\Blend\Helpers\BlendableLoader; |
15
|
|
|
use LCI\Blend\Migrations\MigrationsCreator; |
16
|
|
|
use LCI\Blend\Migrations\Migrator; |
17
|
|
|
use LCI\MODX\Console\Helpers\UserInteractionHandler; |
18
|
|
|
use modX; |
|
|
|
|
19
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
20
|
|
|
|
21
|
|
|
class Blender |
22
|
|
|
{ |
23
|
|
|
/** @var string ~ version number of the project */ |
24
|
|
|
const VERSION = '1.3.1'; |
25
|
|
|
|
26
|
|
|
/** @var \modx */ |
|
|
|
|
27
|
|
|
protected $modx; |
28
|
|
|
|
29
|
|
|
/** @var array */ |
30
|
|
|
protected $modx_version_info = []; |
31
|
|
|
|
32
|
|
|
/** @var \LCI\MODX\Console\Helpers\UserInteractionHandler */ |
33
|
|
|
protected $userInteractionHandler; |
34
|
|
|
|
35
|
|
|
/** @var array */ |
36
|
|
|
protected $config = []; |
37
|
|
|
|
38
|
|
|
/** @var boolean|array */ |
39
|
|
|
protected $blendMigrations = false; |
40
|
|
|
|
41
|
|
|
/** @var BlendableLoader */ |
42
|
|
|
protected $blendableLoader; |
43
|
|
|
|
44
|
|
|
/** @var string */ |
45
|
|
|
protected $project = 'local'; |
46
|
|
|
|
47
|
|
|
/** @var \Tagger */ |
|
|
|
|
48
|
|
|
protected $tagger; |
49
|
|
|
|
50
|
|
|
protected $resource_id_map = []; |
51
|
|
|
|
52
|
|
|
protected $resource_seek_key_map = []; |
53
|
|
|
|
54
|
|
|
protected $category_map = []; |
55
|
|
|
|
56
|
|
|
/** @var string date('Y_m_d_His') */ |
57
|
|
|
protected $seeds_dir = ''; |
58
|
|
|
|
59
|
|
|
/** @var int */ |
60
|
|
|
protected $xpdo_version = 3; |
61
|
|
|
|
62
|
|
|
protected $blend_class_object = 'BlendMigrations'; |
63
|
|
|
|
64
|
|
|
protected $blend_package = 'blend'; |
65
|
|
|
|
66
|
|
|
const VERBOSITY_QUIET = OutputInterface::VERBOSITY_QUIET; |
67
|
|
|
const VERBOSITY_NORMAL = OutputInterface::VERBOSITY_NORMAL; |
68
|
|
|
const VERBOSITY_VERBOSE = OutputInterface::VERBOSITY_VERBOSE; |
69
|
|
|
const VERBOSITY_VERY_VERBOSE = OutputInterface::VERBOSITY_VERY_VERBOSE; |
70
|
|
|
const VERBOSITY_DEBUG = OutputInterface::VERBOSITY_DEBUG; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Blender constructor. |
74
|
|
|
* |
75
|
|
|
* @param \modX $modx |
76
|
|
|
* @param UserInteractionHandler $userInteractionHandler |
77
|
|
|
* @param array $config |
78
|
|
|
*/ |
79
|
|
|
public function __construct(modX $modx, UserInteractionHandler $userInteractionHandler, $config = []) |
80
|
|
|
{ |
81
|
|
|
$this->modx = $modx; |
82
|
|
|
|
83
|
|
|
$this->modx_version_info = $this->modx->getVersionData(); |
84
|
|
|
|
85
|
|
|
$this->userInteractionHandler = $userInteractionHandler; |
86
|
|
|
|
87
|
|
|
if (version_compare($this->modx_version_info['full_version'], '3.0') >= 0) { |
88
|
|
|
$this->xpdo_version = 3; |
89
|
|
|
$this->blend_class_object = 'LCI\\Blend\\Model\\xPDO\\BlendMigrations'; |
90
|
|
|
$this->blend_package = 'LCI\\Blend\\Model\\xPDO'; |
91
|
|
|
|
92
|
|
|
} else { |
93
|
|
|
$this->xpdo_version = 2; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$blend_modx_migration_dir = dirname(__DIR__); |
97
|
|
|
if (isset($config['blend_modx_migration_dir'])) { |
98
|
|
|
$blend_modx_migration_dir = $config['blend_modx_migration_dir']; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
$this->config = [ |
102
|
|
|
'migration_templates_path' => __DIR__.'/Migrations/templates/', |
103
|
|
|
'migrations_path' => $blend_modx_migration_dir.'database/migrations/', |
104
|
|
|
'seeds_path' => $blend_modx_migration_dir.'database/seeds/', |
105
|
|
|
'history_path' => $blend_modx_migration_dir.'database/history/', |
106
|
|
|
'model_dir' => __DIR__.($this->xpdo_version >= 3 ? '/' : '/xpdo2/'), |
107
|
|
|
'extras' => [ |
108
|
|
|
'tagger' => false |
109
|
|
|
] |
110
|
|
|
]; |
111
|
|
|
|
112
|
|
|
$this->setVerbose(); |
113
|
|
|
|
114
|
|
|
$this->config = array_merge($this->config, $config); |
115
|
|
|
|
116
|
|
|
$this->seeds_dir = date('Y_m_d_His'); |
117
|
|
|
|
118
|
|
|
$tagger_path = $this->modx->getOption('tagger.core_path', null, $this->modx->getOption('core_path').'components/tagger/').'model/tagger/'; |
119
|
|
|
if (is_dir($tagger_path)) { |
120
|
|
|
$this->config['extras']['tagger'] = true; |
121
|
|
|
/** @var \Tagger $tagger */ |
122
|
|
|
$this->tagger = $this->modx->getService('tagger', 'Tagger', $tagger_path, []); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
if ($this->xpdo_version >= 3) { |
126
|
|
|
$this->modx->setPackage($this->blend_package, $this->config['model_dir']); |
127
|
|
|
|
128
|
|
|
} else { |
129
|
|
|
$this->modx->addPackage($this->blend_package, $this->config['model_dir']); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
$this->blendableLoader = new BlendableLoader($this, $this->modx, $this->userInteractionHandler); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @deprecated |
137
|
|
|
* @param $name |
138
|
|
|
* @param $arguments |
139
|
|
|
* @return mixed |
140
|
|
|
* @throws MigratorException |
141
|
|
|
*/ |
142
|
|
|
public function __call($name, $arguments) |
143
|
|
|
{ |
144
|
|
|
// How to mark as deprecated? |
145
|
|
|
if (method_exists($this->blendableLoader, $name)) { |
146
|
|
|
|
147
|
|
|
$message = get_class($this) . '->'.$name.'() has been deprecated, please use ' . get_class($this) . '->getBlendableLoader()->' . $name; |
148
|
|
|
trigger_error($message, E_USER_WARNING); |
149
|
|
|
$this->modx->log(\modX::LOG_LEVEL_ERROR, $message); |
150
|
|
|
|
151
|
|
|
return call_user_func_array(array($this->blendableLoader, $name), $arguments); |
152
|
|
|
|
153
|
|
|
} else { |
154
|
|
|
throw new MigratorException('Call to undefined Method ' . get_class($this) . '->' . $name); |
155
|
|
|
} |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* @return BlendableLoader |
160
|
|
|
*/ |
161
|
|
|
public function getBlendableLoader(): BlendableLoader |
162
|
|
|
{ |
163
|
|
|
return $this->blendableLoader; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* @return string |
168
|
|
|
*/ |
169
|
|
|
public function getBlendClassObject() |
170
|
|
|
{ |
171
|
|
|
return $this->blend_class_object; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* @return array |
176
|
|
|
*/ |
177
|
|
|
public function getConfig(): array |
178
|
|
|
{ |
179
|
|
|
return $this->config; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* @return int |
184
|
|
|
*/ |
185
|
|
|
public function getVerbose(): int |
186
|
|
|
{ |
187
|
|
|
return $this->config['verbose']; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
/** |
191
|
|
|
* @param int $verbose |
192
|
|
|
* @see https://symfony.com/doc/current/console/verbosity.html |
193
|
|
|
* @return $this |
194
|
|
|
*/ |
195
|
|
|
public function setVerbose(int $verbose=self::VERBOSITY_NORMAL) |
196
|
|
|
{ |
197
|
|
|
$this->config['verbose'] = $verbose; |
198
|
|
|
return $this; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* @return UserInteractionHandler |
203
|
|
|
*/ |
204
|
|
|
public function getUserInteractionHandler() |
205
|
|
|
{ |
206
|
|
|
return $this->userInteractionHandler; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* @return string |
211
|
|
|
*/ |
212
|
|
|
public function getVersion() |
213
|
|
|
{ |
214
|
|
|
return static::VERSION; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* @return string |
219
|
|
|
*/ |
220
|
|
|
public function getSeedsDir() |
221
|
|
|
{ |
222
|
|
|
return $this->seeds_dir; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* @param string $seeds_dir ~ local folder |
227
|
|
|
* |
228
|
|
|
* @return Blender |
229
|
|
|
*/ |
230
|
|
|
public function setSeedsDir($seeds_dir) |
231
|
|
|
{ |
232
|
|
|
$this->seeds_dir = $seeds_dir; |
233
|
|
|
return $this; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* @param string|null $directory_key |
238
|
|
|
* @return string |
239
|
|
|
*/ |
240
|
|
|
public function getSeedsPath($directory_key = null) |
241
|
|
|
{ |
242
|
|
|
$seed_path = $this->config['seeds_path']; |
243
|
|
|
if (!empty($directory_key)) { |
244
|
|
|
$seed_path .= trim($directory_key, '/').DIRECTORY_SEPARATOR; |
245
|
|
|
} |
246
|
|
|
return $seed_path; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* @param string|null $directory_key |
251
|
|
|
* @return string |
252
|
|
|
*/ |
253
|
|
|
public function getHistoryPath($directory_key = null) |
254
|
|
|
{ |
255
|
|
|
$seed_path = $this->config['history_path']; |
256
|
|
|
if (!empty($directory_key)) { |
257
|
|
|
$seed_path .= trim($directory_key, '/').DIRECTORY_SEPARATOR; |
258
|
|
|
} |
259
|
|
|
return $seed_path; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* @return string |
264
|
|
|
*/ |
265
|
|
|
public function getMigrationPath() |
266
|
|
|
{ |
267
|
|
|
return $this->config['migrations_path']; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
/** |
271
|
|
|
* @return \Tagger |
272
|
|
|
*/ |
273
|
|
|
public function getTagger() |
274
|
|
|
{ |
275
|
|
|
return $this->tagger; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* @param bool $refresh |
280
|
|
|
* @return array |
281
|
|
|
*/ |
282
|
|
|
public function getCategoryMap($refresh = false) |
283
|
|
|
{ |
284
|
|
|
if (count($this->category_map) == 0 || $refresh) { |
285
|
|
|
$this->category_map = [ |
286
|
|
|
'ids' => [], |
287
|
|
|
'names' => [], |
288
|
|
|
'lineage' => [] |
289
|
|
|
]; |
290
|
|
|
$query = $this->modx->newQuery('modCategory'); |
291
|
|
|
$query->sortBy('parent'); |
292
|
|
|
$query->sortBy('rank'); |
293
|
|
|
$categories = $this->modx->getCollection('modCategory', $query); |
294
|
|
|
foreach ($categories as $category) { |
295
|
|
|
$category_data = $category->toArray(); |
296
|
|
|
|
297
|
|
|
$this->category_map['ids'][$category->get('id')] = $category_data; |
298
|
|
|
|
299
|
|
|
$key = trim($category->get('category')); |
300
|
|
|
// This is not unique! |
301
|
|
|
$this->category_map['names'][$key] = $category_data; |
302
|
|
|
|
303
|
|
|
// Get the lineage: Parent=>Child=>Grand Child as key |
304
|
|
|
$lineage = $key; |
305
|
|
|
if ($category_data['parent'] > 0 && isset($this->category_map['ids'][$category_data['parent']]) && isset($this->category_map['ids'][$category_data['parent']]['lineage'])) { |
306
|
|
|
$lineage = $this->category_map['ids'][$category_data['parent']]['lineage'].'=>'.$key; |
307
|
|
|
} elseif ($category_data['parent'] > 0) { |
308
|
|
|
//$this->out('DID NOT FIND PARENT?? '. print_r($category_data, true), true); |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
$this->category_map['ids'][$category->get('id')]['lineage'] = $lineage; |
312
|
|
|
|
313
|
|
|
$this->category_map['lineage'][$lineage] = $category->toArray(); |
314
|
|
|
} |
315
|
|
|
} |
316
|
|
|
return $this->category_map; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* @param string $message |
321
|
|
|
* @param int $verbose |
322
|
|
|
* @param bool $error |
323
|
|
|
*/ |
324
|
|
|
public function out($message, $verbose=Blender::VERBOSITY_NORMAL, $error = false) |
325
|
|
|
{ |
326
|
|
|
if ($this->getVerbose() >= $verbose) { |
327
|
|
|
if ($error) { |
328
|
|
|
$this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_ERROR); |
329
|
|
|
|
330
|
|
|
} else { |
331
|
|
|
$this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_STRING); |
332
|
|
|
} |
333
|
|
|
} |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* @param string $message |
338
|
|
|
* @param int $verbose |
339
|
|
|
*/ |
340
|
|
|
public function outError($message, $verbose=Blender::VERBOSITY_NORMAL) |
341
|
|
|
{ |
342
|
|
|
if ($this->getVerbose() >= $verbose) { |
343
|
|
|
$this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_ERROR); |
344
|
|
|
} |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
/** |
348
|
|
|
* @param string $message |
349
|
|
|
* @param int $verbose |
350
|
|
|
*/ |
351
|
|
|
public function outSuccess($message, $verbose=Blender::VERBOSITY_NORMAL) |
352
|
|
|
{ |
353
|
|
|
if ($this->getVerbose() >= $verbose) { |
354
|
|
|
$this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_SUCCESS); |
355
|
|
|
} |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
/** |
359
|
|
|
* @param string $name |
360
|
|
|
* @param string $server_type |
361
|
|
|
* @param string|null $migration_path |
362
|
|
|
* |
363
|
|
|
* @return bool |
364
|
|
|
*/ |
365
|
|
|
public function createBlankMigrationClassFile($name, $server_type = 'master', $migration_path = null) |
366
|
|
|
{ |
367
|
|
|
$migrationCreator = new MigrationsCreator($this->userInteractionHandler); |
368
|
|
|
|
369
|
|
|
if (empty($migration_path)) { |
370
|
|
|
$migration_path = $this->getMigrationPath(); |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
$success = $migrationCreator |
374
|
|
|
->setPathTimeStamp($this->getSeedsDir()) |
375
|
|
|
->setVerbose($this->getVerbose()) |
376
|
|
|
->setName($name) |
377
|
|
|
->setDescription('') |
378
|
|
|
->setServerType($server_type) |
379
|
|
|
->setMigrationsPath($migration_path) |
380
|
|
|
->createBlankMigrationClassFile(); |
381
|
|
|
|
382
|
|
|
$this->logCreatedMigration($migrationCreator->getLogData()); |
383
|
|
|
return $success; |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
/** |
387
|
|
|
* @return SeedMaker |
388
|
|
|
*/ |
389
|
|
|
public function getSeedMaker() |
390
|
|
|
{ |
391
|
|
|
return new SeedMaker($this->modx, $this); |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
/** |
395
|
|
|
* @param string $method |
396
|
|
|
* @param bool $prompt |
397
|
|
|
* @throws MigratorException |
398
|
|
|
*/ |
399
|
|
|
/** |
400
|
|
|
* @param string $method |
401
|
|
|
* @param bool $prompt |
402
|
|
|
* @throws MigratorException |
403
|
|
|
*/ |
404
|
|
|
public function install($method = 'up', $prompt = false) |
405
|
|
|
{ |
406
|
|
|
$config = $this->config; |
407
|
|
|
|
408
|
|
|
$config['migrations_path'] = __DIR__.'/database/migrations/'; |
409
|
|
|
|
410
|
|
|
$blender = new Blender($this->modx, $this->getUserInteractionHandler(), $config); |
411
|
|
|
$blender->setProject('lci/blend'); |
412
|
|
|
|
413
|
|
|
$migrator = new Migrator($blender, $this->modx, 'lci/blend'); |
414
|
|
|
$migrator |
415
|
|
|
->setDelayLogging(true) |
416
|
|
|
->setCheckInstallLog($method == 'up' ? false : true) |
417
|
|
|
->runMigration($method); |
418
|
|
|
|
419
|
|
|
// does the migration directory exist? |
420
|
|
|
if (!file_exists($this->getMigrationPath())) { |
421
|
|
|
$create = true; |
422
|
|
|
if ($this->getVerbose() >= Blender::VERBOSITY_NORMAL || $prompt) { |
423
|
|
|
$create = $this->getUserInteractionHandler()->promptConfirm('Create the following directory for migration files?'.PHP_EOL |
424
|
|
|
.$this->getMigrationPath(), true); |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
if ($create) { |
428
|
|
|
mkdir($this->getMigrationPath(), 0700, true); |
429
|
|
|
$this->outSuccess('Created migration directory: '.$this->getMigrationPath()); |
430
|
|
|
} |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** @var \LCI\Blend\Blendable\SystemSetting $systemSetting */ |
434
|
|
|
$systemSetting = $this->getBlendableLoader()->getBlendableSystemSetting('blend.version'); |
435
|
|
|
$systemSetting |
436
|
|
|
->setSeedsDir($this->getSeedsDir()) |
437
|
|
|
->setFieldValue($this->getVersion()) |
438
|
|
|
->setFieldArea('Blend') |
439
|
|
|
->blend(true); |
440
|
|
|
|
441
|
|
|
$this->modx->cacheManager->refresh(); |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
/** |
445
|
|
|
* @throws MigratorException |
446
|
|
|
*/ |
447
|
|
|
public function uninstall() |
448
|
|
|
{ |
449
|
|
|
$this->install('down'); |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
/** |
453
|
|
|
* @param string $method |
454
|
|
|
* @throws MigratorException |
455
|
|
|
*/ |
456
|
|
|
public function update($method = 'up') |
457
|
|
|
{ |
458
|
|
|
$current_version = $this->modx->getOption('blend.version'); |
|
|
|
|
459
|
|
|
$this->install($method); |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* @return bool |
464
|
|
|
*/ |
465
|
|
|
public function requireUpdate() |
466
|
|
|
{ |
467
|
|
|
$upgrade = false; |
468
|
|
|
|
469
|
|
|
$current_version = $this->modx->getOption('blend.version'); |
470
|
|
|
// FILE version, DB Version |
471
|
|
|
if ($this->isBlendInstalledInModx() && (!$current_version || version_compare($this->getVersion(), $current_version) === 1)) { |
472
|
|
|
$this->outError('MODX System Setting Version: '. $current_version.' Code version: '.$this->getVersion(), Blender::VERBOSITY_DEBUG); |
473
|
|
|
$upgrade = true; |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
return $upgrade; |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
/** |
480
|
|
|
* @param bool $check_install_log |
481
|
|
|
* @return bool |
482
|
|
|
*/ |
483
|
|
|
public function isBlendInstalledInModx($check_install_log=true) |
484
|
|
|
{ |
485
|
|
|
$installed = false; |
|
|
|
|
486
|
|
|
try { |
487
|
|
|
$table = $this->modx->getTableName($this->blend_class_object); |
488
|
|
|
if ($rs = $this->modx->query("SELECT 1 FROM {$table} LIMIT 0") === false) { |
|
|
|
|
489
|
|
|
$this->out(__METHOD__.' table not found ', Blender::VERBOSITY_DEBUG); |
490
|
|
|
return false; |
491
|
|
|
} |
492
|
|
|
$installed = true; |
493
|
|
|
|
494
|
|
|
} catch (\Exception $exception) { |
495
|
|
|
$this->out(__METHOD__ . ' Exception: '. $exception->getMessage(), Blender::VERBOSITY_DEBUG); |
496
|
|
|
// We got an exception == table not found |
497
|
|
|
return false; |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
if ($check_install_log) { |
501
|
|
|
$installed = false; |
502
|
|
|
/** @var \xPDOQuery $query */ |
503
|
|
|
$query = $this->modx->newQuery($this->blend_class_object); |
504
|
|
|
$query->select('id'); |
505
|
|
|
$query->where([ |
506
|
|
|
'name:IN' => ['InstallBlender', 'install_blender'], |
507
|
|
|
'status' => 'up_complete' |
508
|
|
|
]); |
509
|
|
|
$query->sortBy('name'); |
510
|
|
|
|
511
|
|
|
$installMigration = $this->modx->getObject($this->blend_class_object, $query); |
512
|
|
|
if ($installMigration instanceof \BlendMigrations || $installMigration instanceof \LCI\Blend\Model\xPDO\BlendMigrations) { |
513
|
|
|
$this->out(print_r($installMigration->toArray(), true), Blender::VERBOSITY_DEBUG); |
514
|
|
|
$installed = true; |
515
|
|
|
} |
516
|
|
|
$this->out(__METHOD__ . ' Blend install log not found', Blender::VERBOSITY_DEBUG); |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
return $installed; |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
/** |
523
|
|
|
* @param string $method |
524
|
|
|
* @param string $type |
525
|
|
|
* @param int $count |
526
|
|
|
* @param int $id |
527
|
|
|
* @param null|string $name |
528
|
|
|
* @throws MigratorException |
529
|
|
|
*/ |
530
|
|
|
public function runMigration($method = 'up', $type = 'master', $count = 0, $id = 0, $name = null) |
531
|
|
|
{ |
532
|
|
|
/** @var Migrator $migrator */ |
533
|
|
|
$migrator = new Migrator($this, $this->modx, $this->project); |
534
|
|
|
$migrator->runMigration($method, $type, $count, $id, $name); |
535
|
|
|
} |
536
|
|
|
|
537
|
|
|
/** |
538
|
|
|
* @param $type |
539
|
|
|
* @param null $name |
|
|
|
|
540
|
|
|
* @return string |
541
|
|
|
*/ |
542
|
|
|
public function getMigrationName($type, $name = null) |
543
|
|
|
{ |
544
|
|
|
$format = new Format($this->seeds_dir); |
545
|
|
|
return $format->getMigrationName($type, $name); |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
/** |
549
|
|
|
* @param string $name |
550
|
|
|
* @param string $type ~ chunk, plugin, resource, snippet, systemSettings, template, site |
551
|
|
|
* |
552
|
|
|
* @return bool |
553
|
|
|
*/ |
554
|
|
|
public function removeMigrationFile($name, $type) |
555
|
|
|
{ |
556
|
|
|
$class_name = $this->getMigrationName($type, $name); |
557
|
|
|
|
558
|
|
|
$removed = false; |
559
|
|
|
$migration_file = $this->getMigrationPath().$class_name.'.php'; |
560
|
|
|
if (file_exists($migration_file)) { |
561
|
|
|
if (unlink($migration_file)) { |
562
|
|
|
$removed = true; |
563
|
|
|
$migration = $this->modx->getObject($this->blend_class_object, ['name' => $class_name]); |
564
|
|
|
if (is_object($migration) && $migration->remove()) { |
565
|
|
|
$this->out($class_name.' migration has been removed from the blend_migrations table', Blender::VERBOSITY_VERY_VERBOSE); |
566
|
|
|
|
567
|
|
|
} |
568
|
|
|
} else { |
569
|
|
|
$this->outError($class_name.' migration has not been removed from the blend_migrations table'); |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
} else { |
573
|
|
|
$this->outError($this->getMigrationPath().$class_name.'.php migration could not be found to remove'); |
574
|
|
|
} |
575
|
|
|
|
576
|
|
|
return $removed; |
577
|
|
|
} |
578
|
|
|
/** |
579
|
|
|
* @param int $id |
580
|
|
|
* |
581
|
|
|
* @return bool|array |
582
|
|
|
*/ |
583
|
|
|
public function getResourceSeedKeyFromID($id) |
584
|
|
|
{ |
585
|
|
|
if (!isset($this->resource_id_map[$id])) { |
586
|
|
|
$seed_key = $context = false; |
587
|
|
|
$resource = $this->modx->getObject('modResource', $id); |
588
|
|
|
if ($resource) { |
589
|
|
|
$context = $resource->get('context_key'); |
590
|
|
|
if (!isset($this->resource_seek_key_map[$context])) { |
591
|
|
|
$this->resource_seek_key_map[$context] = []; |
592
|
|
|
} |
593
|
|
|
$seed_key = $this->getSeedKeyFromAlias($resource->get('alias')); |
594
|
|
|
$this->resource_seek_key_map[$context][$seed_key] = $id; |
595
|
|
|
} |
596
|
|
|
$this->resource_id_map[$id] = [ |
597
|
|
|
'context' => $context, |
598
|
|
|
'seed_key' => $seed_key |
599
|
|
|
]; |
600
|
|
|
} |
601
|
|
|
|
602
|
|
|
return $this->resource_id_map[$id]; |
603
|
|
|
} |
604
|
|
|
|
605
|
|
|
/** |
606
|
|
|
* @param string $alias |
607
|
|
|
* @param string $context |
608
|
|
|
* @return bool|int |
609
|
|
|
*/ |
610
|
|
|
public function getResourceIDFromLocalAlias($alias, $context='web') |
611
|
|
|
{ |
612
|
|
|
$seed_key = $this->getSeedKeyFromAlias($alias); |
613
|
|
|
return $this->getResourceIDFromSeedKey($seed_key, $context); |
614
|
|
|
} |
615
|
|
|
|
616
|
|
|
/** |
617
|
|
|
* @param string $seed_key |
618
|
|
|
* @param string $context |
619
|
|
|
* |
620
|
|
|
* @return bool|int |
621
|
|
|
*/ |
622
|
|
|
public function getResourceIDFromSeedKey($seed_key, $context = 'web') |
623
|
|
|
{ |
624
|
|
|
if (!isset($this->resource_seek_key_map[$context])) { |
625
|
|
|
$this->resource_seek_key_map[$context] = []; |
626
|
|
|
} |
627
|
|
|
if (!isset($this->resource_seek_key_map[$context][$seed_key])) { |
628
|
|
|
$id = false; |
629
|
|
|
$alias = $this->getAliasFromSeedKey($seed_key); |
630
|
|
|
$resource = $this->modx->getObject('modResource', ['alias' => $alias, 'context_key' => $context]); |
631
|
|
|
if ($resource) { |
632
|
|
|
$id = $resource->get('id'); |
633
|
|
|
$this->resource_seek_key_map[$context][$seed_key] = $id; |
634
|
|
|
$this->resource_id_map[$id] = [ |
635
|
|
|
'context' => $context, |
636
|
|
|
'seed_key' => $seed_key |
637
|
|
|
]; |
638
|
|
|
} |
639
|
|
|
$this->resource_seek_key_map[$context][$seed_key] = $id; |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
return $this->resource_seek_key_map[$context][$seed_key]; |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* @param string $alias |
647
|
|
|
* |
648
|
|
|
* @return string |
649
|
|
|
*/ |
650
|
|
|
public function getSeedKeyFromAlias($alias) |
651
|
|
|
{ |
652
|
|
|
return str_replace('/', '#', $alias); |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* @param string $seed_key |
657
|
|
|
* |
658
|
|
|
* @return string |
659
|
|
|
*/ |
660
|
|
|
public function getAliasFromSeedKey($seed_key) |
661
|
|
|
{ |
662
|
|
|
return str_replace('#', '/', $seed_key); |
663
|
|
|
} |
664
|
|
|
|
665
|
|
|
/** |
666
|
|
|
* @deprecated |
667
|
|
|
* @param string $name |
668
|
|
|
* @param string $type ~ template, template-variable, chunk, snippet or plugin |
669
|
|
|
* @return string |
670
|
|
|
*/ |
671
|
|
|
public function getElementSeedKeyFromName($name, $type) |
672
|
|
|
{ |
673
|
|
|
return $type.'_'.$this->getSeedKeyFromName($name); |
674
|
|
|
} |
675
|
|
|
|
676
|
|
|
/** |
677
|
|
|
* @param string $name |
678
|
|
|
* @return string |
679
|
|
|
*/ |
680
|
|
|
public function getSeedKeyFromName($name) |
681
|
|
|
{ |
682
|
|
|
return str_replace('/', '#', $name); |
683
|
|
|
} |
684
|
|
|
|
685
|
|
|
/** |
686
|
|
|
* @param string $seed_key |
687
|
|
|
* @return string |
688
|
|
|
*/ |
689
|
|
|
public function getNameFromSeedKey($seed_key) |
690
|
|
|
{ |
691
|
|
|
return str_replace('#', '/', $seed_key); |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
/** |
695
|
|
|
* @param string $project |
696
|
|
|
* @return Blender |
697
|
|
|
*/ |
698
|
|
|
public function setProject(string $project): Blender |
699
|
|
|
{ |
700
|
|
|
$this->project = $project; |
701
|
|
|
return $this; |
702
|
|
|
} |
703
|
|
|
|
704
|
|
|
/** |
705
|
|
|
* @param array $data |
706
|
|
|
*/ |
707
|
|
|
protected function logCreatedMigration(array $data) |
708
|
|
|
{ |
709
|
|
|
$migrator = new Migrator($this, $this->modx, 'local'); |
710
|
|
|
$migrator->logMigration($data); |
711
|
|
|
} |
712
|
|
|
} |
713
|
|
|
|
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths