Test Setup Failed
Push — master ( 32c7c7...b19ce7 )
by Josh
03:11
created

Blender::makeMediaSourceSeeds()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 30
rs 9.6
c 0
b 0
f 0
nc 4
nop 4
cc 3
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\Helpers\Format;
12
use LCI\Blend\Migrations\MigrationsCreator;
13
use LCI\Blend\Model\xPDO\BlendMigrations;
14
use modX;
0 ignored issues
show
Bug introduced by
The type modX was not found. Maybe you did not declare it correctly or list all dependencies?

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:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use LCI\Blend\Blendable\Chunk;
16
use LCI\Blend\Blendable\Context;
17
use LCI\Blend\Blendable\MediaSource;
18
use LCI\Blend\Blendable\Plugin;
19
use LCI\Blend\Blendable\Resource;
20
use LCI\Blend\Blendable\Snippet;
21
use LCI\Blend\Blendable\SystemSetting;
22
use LCI\Blend\Blendable\Template;
23
use LCI\Blend\Blendable\TemplateVariable;
24
use LCI\Blend\Helpers\SimpleCache;
25
use LCI\MODX\Console\Helpers\UserInteractionHandler;
26
use Exception;
27
28
class Blender
29
{
30
    /** @var string ~ version number of the project */
31
    private $version = '1.0.0 beta';
32
33
    /** @var array a list of valid upgrade migrations */
34
    protected $update_migrations = [
35
        '0.9.7' => 'v0_9_7_update',
36
        '0.9.8' => 'v0_9_8_update',
37
        '0.9.9' => 'v0_9_9_update',
38
        '0.9.10' => 'v0_9_10_update',
39
        '0.9.11' => 'v0_9_11_update',
40
        '1.0.0 beta' => 'v1_0_0_beta_update'
41
    ];
42
43
    /** @var  \modx */
0 ignored issues
show
Bug introduced by
The type modx was not found. Maybe you did not declare it correctly or list all dependencies?

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:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
44
    protected $modx;
45
46
    /** @var array  */
47
    protected $modx_version_info = [];
48
49
    /** @var \LCI\MODX\Console\Helpers\UserInteractionHandler */
50
    protected $userInteractionHandler;
51
52
    /** @var array  */
53
    protected $config = [];
54
55
    /** @var boolean|array  */
56
    protected $blendMigrations = false;
57
58
    /** @var  \Tagger */
0 ignored issues
show
Bug introduced by
The type Tagger was not found. Maybe you did not declare it correctly or list all dependencies?

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:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
59
    protected $tagger;
60
61
    protected $resource_id_map = [];
62
63
    protected $resource_seek_key_map = [];
64
65
    protected $category_map = [];
66
67
    /** @var string date('Y_m_d_His') */
68
    protected $seeds_dir = '';
69
70
    /** @var int  */
71
    protected $xpdo_version = 3;
72
73
    protected $blend_class_object = 'BlendMigrations';
74
75
    protected $blend_package = 'blend';
76
77
    /**
78
     * Stockpile constructor.
79
     *
80
     * @param \modX $modx
81
     * @param UserInteractionHandler $userInteractionHandler
82
     * @param array $config
83
     */
84
    public function __construct(modX $modx, UserInteractionHandler $userInteractionHandler, $config=[])
85
    {
86
        $this->modx = $modx;
87
88
        $this->modx_version_info = $this->modx->getVersionData();
89
90
        $this->userInteractionHandler = $userInteractionHandler;
91
92
        if (version_compare($this->modx_version_info['full_version'], '3.0') >= 0 ) {
93
            $this->xpdo_version = 3;
94
            $this->blend_class_object = 'LCI\\Blend\\Model\\xPDO\\BlendMigrations';
95
            $this->blend_package = 'LCI\\Blend\\Model\\xPDO';
96
97
        } else {
98
            $this->xpdo_version = 2;
99
        }
100
101
        $blend_modx_migration_dir = dirname(__DIR__);
102
        if (isset($config['blend_modx_migration_dir'])) {
103
            $blend_modx_migration_dir = $config['blend_modx_migration_dir'];
104
        }
105
106
        $this->config = [
107
            'migration_templates_path' => __DIR__. '/Migrations/templates/',
108
            'migrations_path' => $blend_modx_migration_dir.'database/migrations/',
109
            'seeds_path' => $blend_modx_migration_dir.'database/seeds/',
110
            'model_dir' => __DIR__ . ($this->xpdo_version >= 3 ? '/' : '/xpdo2/'),
111
            'extras' => [
112
                'tagger' => false
113
            ]
114
        ];
115
        $this->config = array_merge($this->config, $config);
116
117
        $this->seeds_dir = date('Y_m_d_His');
118
119
        $tagger_path = $this->modx->getOption('tagger.core_path', null, $this->modx->getOption('core_path') . 'components/tagger/') . 'model/tagger/';
120
        if (is_dir($tagger_path)) {
121
            $this->config['extras']['tagger'] = true;
122
            /** @var \Tagger $tagger */
123
            $this->tagger = $this->modx->getService('tagger', 'Tagger', $tagger_path, []);
124
        }
125
126
        if ($this->xpdo_version >= 3) {
127
            $this->modx->setPackage($this->blend_package, $this->config['model_dir']);
128
129
        } else {
130
            $this->modx->addPackage($this->blend_package, $this->config['model_dir']);
131
        }
132
    }
133
134
    /**
135
     * @return string
136
     */
137
    public function getBlendClassObject()
138
    {
139
        return $this->blend_class_object;
140
    }
141
142
    /**
143
     * @return UserInteractionHandler
144
     */
145
    public function getUserInteractionHandler()
146
    {
147
        return $this->userInteractionHandler;
148
    }
149
150
    /**
151
     * @return string
152
     */
153
    public function getVersion()
154
    {
155
        return $this->version;
156
    }
157
158
    /**
159
     * @return string
160
     */
161
    public function getSeedsDir()
162
    {
163
        return $this->seeds_dir;
164
    }
165
166
    /**
167
     * @param string $seeds_dir ~ local folder
168
     *
169
     * @return Blender
170
     */
171
    public function setSeedsDir($seeds_dir)
172
    {
173
        $this->seeds_dir = $seeds_dir;
174
        return $this;
175
    }
176
177
    /**
178
     * @param null $directory_key
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $directory_key is correct as it would always require null to be passed?
Loading history...
179
     * @return string
180
     */
181
    public function getSeedsPath($directory_key=null)
182
    {
183
        $seed_path = $this->config['seeds_path'];
184
        if (!empty($directory_key)) {
185
            $seed_path .= trim($directory_key, '/') . DIRECTORY_SEPARATOR;
186
        }
187
        return $seed_path;
188
    }
189
190
    /**
191
     * @return string
192
     */
193
    public function getMigrationPath()
194
    {
195
        return $this->config['migrations_path'];
196
    }
197
198
    /**
199
     * @param bool $reload
200
     * @param string $dir
201
     * @param int $count
202
     * @param int $id
203
     * @param string $name
204
     *
205
     * @return array ~ array of \BlendMigrations
206
     */
207
    public function getBlendMigrationCollection($reload=false, $dir='ASC', $count=0, $id=0, $name=null)
208
    {
209
        if (!$this->blendMigrations || $reload) {
210
            $blendMigrations = [];
211
212
            /** @var \xPDOQuery $query */
213
            $query = $this->modx->newQuery($this->blend_class_object);
214
            if ($id > 0 ) {
215
                $query->where(['id' => $id]);
216
            } elseif (!empty($name)) {
217
                $query->where(['name' => $name]);
218
            }
219
            // @TODO need a ran sequence column to better order of down
220
            $query->sortBy('name', $dir);
221
            if ($count > 0 ) {
222
                $query->limit($count);
223
            }
224
            $query->prepare();
225
            //echo 'SQL: '.$query->toSQL();
226
            $migrationCollection = $this->modx->getCollection($this->blend_class_object, $query);
227
228
            /** @var \BlendMigrations $migration */
229
            foreach ($migrationCollection as $migration) {
230
                $blendMigrations[$migration->get('name')] = $migration;
231
            }
232
            $this->blendMigrations = $blendMigrations;
233
        }
234
        return $this->blendMigrations;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->blendMigrations also could return the type true which is incompatible with the documented return type array.
Loading history...
235
    }
236
237
    /**
238
     * @return \Tagger
239
     */
240
    public function getTagger()
241
    {
242
        return $this->tagger;
243
    }
244
245
    /**
246
     * @param bool $refresh
247
     * @return array
248
     */
249
    public function getCategoryMap($refresh=false)
250
    {
251
        if (count($this->category_map) == 0 || $refresh) {
252
            $this->category_map = [
253
                'ids' => [],
254
                'names' => [],
255
                'lineage' => []
256
            ];
257
            $query = $this->modx->newQuery('modCategory');
258
            $query->sortBy('parent');
259
            $query->sortBy('rank');
260
            $categories = $this->modx->getCollection('modCategory', $query);
261
            foreach ($categories as $category) {
262
                $category_data = $category->toArray();
263
264
                $this->category_map['ids'][$category->get('id')] = $category_data;
265
266
                $key = trim($category->get('category'));
267
                // This is not unique!
268
                $this->category_map['names'][$key] = $category_data;
269
270
                // Get the lineage: Parent=>Child=>Grand Child as key
271
                $lineage = $key;
272
                if ($category_data['parent'] > 0 && isset($this->category_map['ids'][$category_data['parent']]) && isset($this->category_map['ids'][$category_data['parent']]['lineage'])) {
273
                    $lineage = $this->category_map['ids'][$category_data['parent']]['lineage'].'=>'.$key;
274
                } elseif ($category_data['parent'] > 0) {
275
                    //$this->out('DID NOT FIND PARENT?? '. print_r($category_data, true), true);
276
                }
277
278
                $this->category_map['ids'][$category->get('id')]['lineage'] = $lineage;
279
280
                $this->category_map['lineage'][$lineage] = $category->toArray();
281
            }
282
        }
283
        return $this->category_map;
284
    }
285
286
    /**
287
     * Use this method with your IDE to help manually build a Chunk with PHP
288
     * @param string $name
289
     * @return Chunk
290
     */
291
    public function getBlendableChunk($name)
292
    {
293
        /** @var \LCI\Blend\Blendable\Chunk $chunk */
294
        $chunk =  new Chunk($this->modx, $this, $name);
295
        return $chunk->setSeedsDir($this->getSeedsDir());
296
    }
297
    /**
298
     * @param array $chunks
299
     * @param string $seeds_dir
300
     */
301
    public function blendManyChunks($chunks=[], $seeds_dir='')
302
    {
303
        // will update if element does exist or create new
304
        foreach ($chunks as $seed_key) {
305
            /** @var \LCI\Blend\Blendable\Chunk $blendChunk */
306
            $blendChunk = new Chunk($this->modx, $this, $this->getNameFromSeedKey($seed_key));
307
            if (!empty($seeds_dir)) {
308
                $blendChunk->setSeedsDir($seeds_dir);
309
            }
310
            if ($blendChunk->blendFromSeed($seed_key)) {
311
                $this->out($seed_key.' has been blended into ID: ');
312
313
            } elseif($blendChunk->isExists()) {
314
                // @TODO prompt Do you want to blend Y/N/Compare
315
                $this->out($seed_key.' chunk already exists', true);
316
                if ($this->prompt('Would you like to update?', 'Y') === 'Y') {
317
                    if ($blendChunk->blendFromSeed($seed_key, true)) {
318
                        $this->out($seed_key.' has been blended');
319
                    }
320
                }
321
            } else {
322
                $this->out('There was an error saving '.$seed_key, true);
323
            }
324
        }
325
    }
326
327
    /**
328
     * @param array $chunks
329
     * @param string $seeds_dir
330
     */
331
    public function revertBlendManyChunks($chunks=[], $seeds_dir='')
332
    {
333
        // will update if system setting does exist or create new
334
        foreach ($chunks as $seed_key) {
335
            /** @var \LCI\Blend\Blendable\Chunk $blendChunk */
336
            $blendChunk = new Chunk($this->modx, $this, $this->getNameFromSeedKey($seed_key));
337
            if (!empty($seeds_dir)) {
338
                $blendChunk->setSeedsDir($seeds_dir);
339
            }
340
341
            if ( $blendChunk->revertBlend() ) {
342
                $this->out($blendChunk->getFieldName().' chunk has been reverted to '.$seeds_dir);
343
344
            } else {
345
                $this->out($blendChunk->getFieldName().' chunk was not reverted', true);
346
            }
347
        }
348
    }
349
350
    /**
351
     * Use this method with your IDE to help manually build a Chunk with PHP
352
     * @param string $key
353
     * @return Context
354
     */
355
    public function getBlendableContext($key)
356
    {
357
        /** @var \LCI\Blend\Blendable\Context $chunk */
358
        $context =  new Context($this->modx, $this, $key);
359
        return $context->setSeedsDir($this->getSeedsDir());
360
    }
361
362
    /**
363
     * @param array $contexts
364
     * @param string $seeds_dir
365
     */
366
    public function blendManyContexts($contexts=[], $seeds_dir='')
367
    {
368
        // will update if element does exist or create new
369
        foreach ($contexts as $seed_key) {
370
            /** @var \LCI\Blend\Blendable\Context $blendContext */
371
            $blendContext = new Context($this->modx, $this, $this->getNameFromSeedKey($seed_key));
372
            if (!empty($seeds_dir)) {
373
                $blendContext->setSeedsDir($seeds_dir);
374
            }
375
            if ($blendContext->blendFromSeed($seed_key)) {
376
                $this->out($seed_key.' has been blended ');
377
378
            } elseif($blendContext->isExists()) {
379
                // @TODO prompt Do you want to blend Y/N/Compare
380
                $this->out($seed_key.' chunk already exists', true);
381
                if ($this->prompt('Would you like to update?', 'Y') === 'Y') {
382
                    if ($blendContext->blendFromSeed($seed_key, true)) {
383
                        $this->out($seed_key.' has been blended');
384
                    }
385
                }
386
            } else {
387
                $this->out('There was an error saving '.$seed_key, true);
388
            }
389
        }
390
    }
391
392
    /**
393
     * @param array $contexts
394
     * @param string $seeds_dir
395
     */
396
    public function revertBlendManyContexts($contexts=[], $seeds_dir='')
397
    {
398
        // will update if system setting does exist or create new
399
        foreach ($contexts as $seed_key) {
400
            /** @var \LCI\Blend\Blendable\Context $blendContext */
401
            $blendContext = new Context($this->modx, $this, $this->getNameFromSeedKey($seed_key));
402
            if (!empty($seeds_dir)) {
403
                $blendContext->setSeedsDir($seeds_dir);
404
            }
405
406
            if ( $blendContext->revertBlend() ) {
407
                $this->out($blendContext->getFieldKey().' context has been reverted to '.$seeds_dir);
408
409
            } else {
410
                $this->out($blendContext->getFieldKey().' context was not reverted', true);
411
            }
412
        }
413
    }
414
415
416
    /**
417
     * @param string $name
418
     * @return \LCI\Blend\Blendable\MediaSource
419
     */
420
    public function getBlendableMediaSource($name)
421
    {
422
        /** @var \LCI\Blend\Blendable\MediaSource $mediaSource */
423
        $mediaSource =  new MediaSource($this->modx, $this, $name);
424
        return $mediaSource
425
            ->setFieldName($name)
426
            ->setSeedsDir($this->getSeedsDir());
427
    }
428
429
    /**
430
     * @param array $media_sources
431
     * @param string $seeds_dir
432
     */
433
    public function blendManyMediaSources($media_sources=[], $seeds_dir='')
434
    {
435
        // will update if element does exist or create new
436
        foreach ($media_sources as $seed_key) {
437
            /** @var \LCI\Blend\Blendable\MediaSource $blendMediaSource */
438
            $blendMediaSource = new MediaSource($this->modx, $this);
439
            if (!empty($seeds_dir)) {
440
                $blendMediaSource->setSeedsDir($seeds_dir);
441
            }
442
            if ($blendMediaSource->blendFromSeed($seed_key)) {
443
                $this->out($seed_key.' has been blended into ID: ');
444
445
            } elseif($blendMediaSource->isExists()) {
446
                // @TODO add Compare as option
447
                $this->out($seed_key.' media source already exists', true);
448
                if ($this->prompt('Would you like to update?', 'Y') === 'Y') {
449
                    if ($blendMediaSource->blendFromSeed($seed_key, true)) {
450
                        $this->out($seed_key.' has been blended');
451
                    }
452
                }
453
            } else {
454
                $this->out('There was an error saving '.$seed_key, true);
455
            }
456
        }
457
    }
458
459
    /**
460
     * @param array $media_sources
461
     * @param string $seeds_dir
462
     */
463
    public function revertBlendManyMediaSources($media_sources=[], $seeds_dir='')
464
    {
465
        // will update if system setting does exist or create new
466
        foreach ($media_sources as $seed_key) {
467
            /** @var \LCI\Blend\Blendable\MediaSource $blendMediaSource */
468
            $blendMediaSource = new MediaSource($this->modx, $this, $this->getNameFromSeedKey($seed_key));
469
            if (!empty($seeds_dir)) {
470
                $blendMediaSource->setSeedsDir($seeds_dir);
471
            }
472
473
            if ( $blendMediaSource->revertBlend() ) {
474
                $this->out($blendMediaSource->getFieldName().' media source has been reverted to '.$seeds_dir);
475
476
            } else {
477
                $this->out($blendMediaSource->getFieldName().' media source was not reverted', true);
478
            }
479
        }
480
    }
481
482
    /**
483
     * Use this method with your IDE to help manually build a Plugin with PHP
484
     * @param string $name
485
     * @return \LCI\Blend\Blendable\Plugin
486
     */
487
    public function getBlendablePlugin($name)
488
    {
489
        /** @var \LCI\Blend\Blendable\Plugin $plugin */
490
        $plugin =  new Plugin($this->modx, $this, $name);
491
        return $plugin->setSeedsDir($this->getSeedsDir());
492
    }
493
494
    /**
495
     * @param array $plugins
496
     * @param string $seeds_dir
497
     */
498
    public function blendManyPlugins($plugins=[], $seeds_dir='')
499
    {
500
        // will update if element does exist or create new
501
        foreach ($plugins as $seed_key) {
502
            /** @var \LCI\Blend\Blendable\Plugin $blendPlugin */
503
            $blendPlugin = new Plugin($this->modx, $this, $this->getNameFromSeedKey($seed_key));
504
            if (!empty($seeds_dir)) {
505
                $blendPlugin->setSeedsDir($seeds_dir);
506
            }
507
            if ($blendPlugin->blendFromSeed($seed_key)) {
508
                $this->out($seed_key.' has been blended into ID: ');
509
510
            } elseif($blendPlugin->isExists()) {
511
                // @TODO prompt Do you want to blend Y/N/Compare
512
                $this->out($seed_key.' plugin already exists', true);
513
                if ($this->prompt('Would you like to update?', 'Y') === 'Y') {
514
                    if ($blendPlugin->blendFromSeed($seed_key, true)) {
515
                        $this->out($seed_key.' has been blended');
516
                    }
517
                }
518
            } else {
519
                $this->out('There was an error saving '.$seed_key, true);
520
            }
521
        }
522
    }
523
524
    /**
525
     * @param array $plugins
526
     * @param string $seeds_dir
527
     */
528
    public function revertBlendManyPlugins($plugins=[], $seeds_dir='')
529
    {
530
        // will update if system setting does exist or create new
531
        foreach ($plugins as $seed_key) {
532
            /** @var \LCI\Blend\Blendable\Plugin $blendPlugin */
533
            $blendPlugin = new Plugin($this->modx, $this);
534
            if (!empty($seeds_dir)) {
535
                $blendPlugin->setSeedsDir($seeds_dir);
536
            }
537
538
            if ( $blendPlugin->revertBlend() ) {
539
                $this->out($blendPlugin->getFieldName().' plugin has been reverted to '.$seeds_dir);
540
541
            } else {
542
                $this->out($blendPlugin->getFieldName().' plugin was not reverted', true);
543
            }
544
        }
545
    }
546
547
    /**
548
     * Use this method with your IDE to help manually build a Snippet with PHP
549
     * @param string $name
550
     * @return \LCI\Blend\Blendable\Snippet
551
     */
552
    public function getBlendableSnippet($name)
553
    {
554
        /** @var Snippet $snippet */
555
        $snippet =  new Snippet($this->modx, $this, $name);
556
        return $snippet->setSeedsDir($this->getSeedsDir());
557
    }
558
559
    /**
560
     * @param array $snippets
561
     * @param string $seeds_dir
562
     */
563
    public function blendManySnippets($snippets=[], $seeds_dir='')
564
    {
565
        // will update if element does exist or create new
566
        foreach ($snippets as $seed_key) {
567
            /** @var \LCI\Blend\Blendable\Snippet $blendSnippet */
568
            $blendSnippet = new Snippet($this->modx, $this, $this->getNameFromSeedKey($seed_key));
569
            if (!empty($seeds_dir)) {
570
                $blendSnippet->setSeedsDir($seeds_dir);
571
            }
572
            if ($blendSnippet->blendFromSeed($seed_key)) {
573
                $this->out($seed_key.' has been blended');
574
575
            } elseif($blendSnippet->isExists()) {
576
                // @TODO prompt Do you want to blend Y/N/Compare
577
                $this->out($seed_key.' snippet already exists', true);
578
                if ($this->prompt('Would you like to update?', 'Y') === 'Y') {
579
                    if ($blendSnippet->blendFromSeed($seed_key, true)) {
580
                        $this->out($seed_key.' has been blended');
581
                    }
582
                }
583
            } else {
584
                $this->out('There was an error saving '.$seed_key, true);
585
            }
586
        }
587
    }
588
    /**
589
     * @param array $snippets
590
     * @param string $seeds_dir
591
     */
592
    public function revertBlendManySnippets($snippets=[], $seeds_dir='')
593
    {
594
        // will update if system setting does exist or create new
595
        foreach ($snippets as $seed_key) {
596
            /** @var Snippet $blendSnippet */
597
            $blendSnippet = new Snippet($this->modx, $this, $this->getNameFromSeedKey($seed_key));
598
            if (!empty($seeds_dir)) {
599
                $blendSnippet->setSeedsDir($seeds_dir);
600
            }
601
602
            if ( $blendSnippet->revertBlend() ) {
603
                $this->out($blendSnippet->getFieldName().' snippet has been reverted to '.$seeds_dir);
604
605
            } else {
606
                $this->out($blendSnippet->getFieldName().' snippet was not reverted', true);
607
            }
608
        }
609
    }
610
611
    /**
612
     * Use this method with your IDE to manually build a template
613
     * @param string $name
614
     * @return \LCI\Blend\Blendable\Template
615
     */
616
    public function getBlendableTemplate($name)
617
    {
618
        /** @var \LCI\Blend\Blendable\Template $template */
619
        $template =  new Template($this->modx, $this, $name);
620
        return $template->setSeedsDir($this->seeds_dir);
621
    }
622
623
    /**
624
     * @param array $templates
625
     * @param string $seeds_dir
626
     * @param bool $overwrite
627
     */
628
    public function blendManyTemplates($templates=[], $seeds_dir='', $overwrite=false)
629
    {
630
        // will update if template does exist or create new
631
        foreach ($templates as $seed_key) {
632
633
            /** @var \LCI\Blend\Blendable\Template $blendTemplate */
634
            $blendTemplate = new Template($this->modx, $this, $this->getNameFromSeedKey($seed_key));
635
            if (!empty($seeds_dir)) {
636
                $blendTemplate->setSeedsDir($seeds_dir);
637
            }
638
            if ($blendTemplate->blendFromSeed($seed_key, $overwrite)) {
639
                $this->out($seed_key.' has been blended');
640
641
            } elseif($blendTemplate->isExists()) {
642
                $this->out($seed_key.' template already exists', true);
643
                if ($this->prompt('Would you like to update?', 'Y') === 'Y') {
644
                    if ($blendTemplate->blendFromSeed($seed_key, true)) {
645
                        $this->out($seed_key.' has been blended');
646
                    }
647
                }
648
            } else {
649
                $this->out('There was an error saving '.$seed_key, true);
650
            }
651
        }
652
    }
653
654
    /**
655
     * @param array $templates
656
     * @param string $seeds_dir
657
     */
658
    public function revertBlendManyTemplates($templates=[], $seeds_dir='')
659
    {
660
        // will update if system setting does exist or create new
661
        foreach ($templates as $seed_key) {
662
            /** @var \LCI\Blend\Blendable\Template $blendTemplate */
663
            $blendTemplate = new Template($this->modx, $this, $this->getNameFromSeedKey($seed_key));
664
            if (!empty($seeds_dir)) {
665
                $blendTemplate->setSeedsDir($seeds_dir);
666
            }
667
668
            if ( $blendTemplate->revertBlend() ) {
669
                $this->out($blendTemplate->getFieldName().' template has been reverted to '.$seeds_dir);
670
671
            } else {
672
                $this->out($blendTemplate->getFieldName().' template was not reverted', true);
673
            }
674
        }
675
    }
676
677
    /**
678
     * Use this method with your IDE to manually build a template variable
679
     * @param string $name
680
     * @return TemplateVariable
681
     */
682
    public function getBlendableTemplateVariable($name)
683
    {
684
        /** @var \LCI\Blend\Blendable\TemplateVariable $tv */
685
        $tv =  new TemplateVariable($this->modx, $this, $name);
686
        return $tv->setSeedsDir($this->seeds_dir);
687
    }
688
689
    /**
690
     * @param string $alias
691
     * @param  string $context
692
     * @return \LCI\Blend\Blendable\Resource
693
     */
694
    public function getBlendableResource($alias, $context='web')
695
    {
696
        /** @var \LCI\Blend\Blendable\Resource $resource */
697
        $resource =  new Resource($this->modx, $this, $alias, $context);
698
        return $resource
699
            ->setSeedsDir($this->getSeedsDir());
700
    }
701
    /**
702
     * @param array $resources
703
     * @param string $seeds_dir
704
     * @param bool $overwrite
705
     *
706
     * @return bool
707
     */
708
    public function blendManyResources($resources=[], $seeds_dir='', $overwrite=false)
709
    {
710
        $saved = true;
711
        // will update if resource does exist or create new
712
        foreach ($resources as $context => $seeds) {
713
            foreach ($seeds as $seed_key) {
714
                /** @var \LCI\Blend\Blendable\Resource $blendResource */
715
                $blendResource = new Resource($this->modx, $this, $this->getAliasFromSeedKey($seed_key), $context);
716
717
                if (!empty($seeds_dir)) {
718
                    $blendResource->setSeedsDir($seeds_dir);
719
                }
720
721
                if ($blendResource->blendFromSeed($seed_key, $overwrite)) {
722
                    $this->out($seed_key . ' has been blended into ID: ');
723
724
                } elseif ($blendResource->isExists()) {
725
                    // @TODO prompt Do you want to blend Y/N/Compare
726
                    $this->out($seed_key . ' already exists', true);
727
                    if ($this->prompt('Would you like to update?', 'Y') === 'Y') {
728
                        if ($blendResource->blendFromSeed($seed_key, true)) {
729
                            $this->out($seed_key . ' has been blended into ID: ');
730
                        }
731
                    }
732
                } else {
733
                    $this->out('There was an error saving ' . $seed_key, true);
734
                    echo 'There was an error saving ' . $seed_key; exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
735
                    $saved = false;
0 ignored issues
show
Unused Code introduced by
$saved = false is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
736
                }
737
            }
738
        }
739
740
        return $saved;
741
    }
742
743
    /**
744
     * @param array $resources
745
     * @param string $seeds_dir
746
     * @param bool $overwrite
747
     *
748
     * @return bool
749
     */
750
    public function revertBlendManyResources($resources=[], $seeds_dir='', $overwrite=false)
0 ignored issues
show
Unused Code introduced by
The parameter $overwrite is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

750
    public function revertBlendManyResources($resources=[], $seeds_dir='', /** @scrutinizer ignore-unused */ $overwrite=false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
751
    {
752
        $saved = true;
753
        // will update if resource does exist or create new
754
        foreach ($resources as $context => $seeds) {
755
            foreach ($seeds as $seed_key) {
756
                /** @var \LCI\Blend\Blendable\Resource $blendResource */
757
                $blendResource = new Resource($this->modx, $this, $this->getAliasFromSeedKey($seed_key), $context);
758
759
                if (!empty($seeds_dir)) {
760
                    $blendResource->setSeedsDir($seeds_dir);
761
                }
762
                if ($blendResource->revertBlend()) {
763
                    $this->out($seed_key . ' has been reverted ');
764
765
                } else {
766
                    $this->out('There was an error reverting resource ' . $seed_key, true);
767
                    $saved = false;
768
                }
769
            }
770
        }
771
772
        return $saved;
773
    }
774
775
    /**
776
     * @param string $key
777
     * @return \LCI\Blend\Blendable\SystemSetting
778
     */
779
    public function getBlendableSystemSetting($key='')
780
    {
781
        /** @var \LCI\Blend\Blendable\SystemSetting $systemSetting */
782
        $systemSetting =  new SystemSetting($this->modx, $this, $key);
783
        return $systemSetting->setSeedsDir($this->getSeedsDir());
784
    }
785
786
    /**
787
     * @param array $settings ~ [ ['name' => 'mySystemSetting', 'value' => 'myValue'], ..]
788
     * @param string $seeds_dir
789
     *
790
     * @return bool
791
     */
792
    public function blendManySystemSettings($settings=[], $seeds_dir='')
793
    {
794
        $success = true;
795
        // will update if system setting does exist or create new
796
        foreach ($settings as $data) {
797
            if (isset($data['columns'])) {
798
                $setting = $data['columns'];
799
            } else {
800
                $setting = $data;
801
                $data['columns'] = $data;
802
            }
803
804
            if (isset($setting['key'])) {
805
                $key = $setting['key'];
806
807
            } elseif (isset($setting['name'])) {
808
                $key = $setting['name'];
809
810
            } else {
811
                // Error: no name/key
812
                $success = false;
813
                continue;
814
            }
815
816
            $systemSetting = $this->getBlendableSystemSetting($key);
817
            if (!empty($seeds_dir)) {
818
                $systemSetting->setSeedsDir($seeds_dir);
819
            }
820
821
            if ($systemSetting->blendFromArray($data, true)) {
822
                $this->out($systemSetting->getFieldName().' setting has been blended');
823
            } else {
824
                $success = false;
825
            }
826
        }
827
828
        return $success;
829
    }
830
831
    /**
832
     * @param array $settings ~ [ ['name' => 'mySystemSetting', 'value' => 'myValue'], ..]
833
     * @param string $seeds_dir
834
     *
835
     * @return bool
836
     */
837
    public function revertBlendManySystemSettings($settings=[], $seeds_dir='')
838
    {
839
        $success = true;
840
        // will update if system setting does exist or create new
841
        foreach ($settings as $data) {
842
            if (isset($data['columns'])) {
843
                $setting = $data['columns'];
844
            } else {
845
                $setting = $data;
846
                $data['columns'] = $data;
847
            }
848
849
            if (isset($setting['key'])) {
850
                $key = $setting['key'];
851
852
            } elseif (isset($setting['name'])) {
853
                $key = $setting['name'];
854
855
            } else {
856
                // Error: no name/key
857
                $success = false;
858
                continue;
859
            }
860
861
            $systemSetting = $this->getBlendableSystemSetting($key);
862
863
            if (!empty($seeds_dir)) {
864
                $systemSetting->setSeedsDir($seeds_dir);
865
            }
866
867
            if ( $systemSetting->revertBlend() ) {
868
                $this->out($systemSetting->getFieldName().' setting has been reverted to '.$seeds_dir);
869
870
            } else {
871
                $this->out($systemSetting->getFieldName().' setting was not reverted', true);
872
                $success = false;
873
            }
874
        }
875
876
        return $success;
877
    }
878
879
    /**
880
     * @param string $question
881
     * @param string $default
882
     *
883
     * @return mixed
884
     */
885
    protected function prompt($question, $default='')
886
    {
887
        return $this->userInteractionHandler->promptInput($question, $default);
888
    }
889
890
    /**
891
     * @param string $question
892
     * @param bool $default
893
     * @return bool
894
     */
895
    protected function promptConfirm($question, $default=true)
896
    {
897
        return $this->userInteractionHandler->promptConfirm($question, $default);
898
    }
899
900
    /**
901
     * @param string $question
902
     * @param string|mixed $default
903
     * @param array $options ~ ex: ['Option1' => 'value', 'Option2' => 'value2', ...]
904
     * @return mixed ~ selected value
905
     */
906
    protected function promptSelectOneOption($question, $default, $options=[])
907
    {
908
        return $this->userInteractionHandler->promptSelectOneOption($question, $default, $options);
909
    }
910
911
    /**
912
     * @param string $question
913
     * @param string|mixed $default
914
     * @param array $options ~ ex: ['Option1' => 'value', 'Option2' => 'value2', ...]
915
     * @return array ~ array of selected values
916
     */
917
    protected function promptSelectMultipleOptions($question, $default, $options=[])
918
    {
919
        return $this->userInteractionHandler->promptSelectMultipleOptions($question, $default, $options);
920
    }
921
922
    /**
923
     * @param string $message
924
     * @param bool $error
925
     */
926
    public function out($message, $error=false)
927
    {
928
        if ($error) {
929
            $this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_ERROR);
930
931
        } else {
932
            $this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_STRING);
933
        }
934
    }
935
936
    /**
937
     * @param string $message
938
     */
939
    public function outSuccess($message)
940
    {
941
        $this->userInteractionHandler->tellUser($message, userInteractionHandler::MASSAGE_SUCCESS);
942
    }
943
944
    /**
945
     * @param string $name
946
     * @param string $server_type
947
     * @param string|null $migration_path
948
     *
949
     * @return bool
950
     */
951
    public function createBlankMigrationClassFile($name, $server_type='master', $migration_path=null)
952
    {
953
        $migrationCreator = new MigrationsCreator($this->userInteractionHandler);
954
955
        if (empty($migration_path)) {
956
            $migration_path = $this->getMigrationPath();
957
        }
958
959
        $success = $migrationCreator
960
            ->setPathTimeStamp($this->getSeedsDir())
961
            ->setName($name)
962
            ->setDescription('')
963
            ->setServerType($server_type)
964
            ->setMigrationsPath($migration_path)
965
            ->createBlankMigrationClassFile();
966
967
        $this->logCreatedMigration($migrationCreator->getLogData());
968
        return $success;
969
    }
970
971
    /**
972
     * @return SeedMaker
973
     */
974
    public function getSeedMaker()
975
    {
976
        return new SeedMaker($this->modx, $this);
977
    }
978
979
    /**
980
     * @param string $method
981
     * @param bool $prompt
982
     */
983
    public function install($method='up', $prompt=false)
984
    {
985
        $migration_name = 'install_blender';
986
        $custom_migration_dir = __DIR__.'/Migrations/Blend/';
987
988
        $this->runInstallMigration($migration_name, $custom_migration_dir, null, $method, $prompt);
989
    }
990
991
    /**
992
     * @param string $migration_name
993
     * @param string|null $custom_migration_path
994
     * @param string|null $seed_root_path
995
     * @param string $method
996
     * @param bool $prompt
997
     */
998
    protected function runInstallMigration($migration_name, $custom_migration_path=null, $seed_root_path=null, $method='up', $prompt=false)
999
    {
1000
        // new blender for each instance
1001
        $config = $this->config;
1002
1003
        if (!empty($custom_migration_path)) {
1004
            $config['migrations_path'] = $custom_migration_path;
1005
        }
1006
        if (!empty($seed_root_path)) {
1007
            $config['seeds_path'] = $seed_root_path;
1008
        }
1009
1010
        $blender = new Blender($this->modx, $this->getUserInteractionHandler(), $config);
1011
1012
        /** @var Migrations $migrationProcessClass */
1013
        $migrationProcessClass = $blender->loadMigrationClass($migration_name, $blender);
1014
1015
        if (!$migrationProcessClass instanceof Migrations) {
0 ignored issues
show
introduced by
$migrationProcessClass is always a sub-type of LCI\Blend\Migrations. If $migrationProcessClass can have other possible types, add them to src/Blender.php:1012.
Loading history...
1016
            $this->out('File is not an instance of LCI\Blend\Migrations: '.$migration_name, true);
1017
            $this->out('Did not process, verify it is in the proper directory', true);
1018
1019
        } elseif ($method == 'up' && !$this->isBlendInstalledInModx()) {
1020
1021
            $migrationProcessClass->up();
1022
1023
            /** @var \BlendMigrations $migration */
1024
            $migration = $this->modx->newObject($this->blend_class_object);
1025
            if ($migration) {
0 ignored issues
show
introduced by
$migration is of type BlendMigrations, thus it always evaluated to true. If $migration can have other possible types, add them to src/Blender.php:1023
Loading history...
1026
                $migration->set('name', $migration_name);
1027
                $migration->set('type', 'master');
1028
                $migration->set('description', $migrationProcessClass->getDescription());
1029
                $migration->set('version', $migrationProcessClass->getVersion());
1030
                $migration->set('status', 'up_complete');
1031
                $migration->set('created_at', date('Y-m-d H:i:s'));
1032
                $migration->set('processed_at', date('Y-m-d H:i:s'));
1033
                if ($migration->save() ) {
1034
                    $this->outSuccess($migration_name.' ran and logged');
1035
                } else {
1036
                    $this->out($migration_name . ' did not log correctly', true);
1037
                }
1038
1039
                // does the migration directory exist?
1040
                if (!file_exists($this->getMigrationPath())) {
1041
                    $create = true;
1042
                    if ($prompt) {
1043
                        $response = $this->prompt('Create the following directory for migration files? (y/n) '.PHP_EOL
1044
                            .$this->getMigrationPath(), 'y');
1045
                        if (strtolower(trim($response)) != 'y') {
1046
                            $create = false;
1047
                        }
1048
                    }
1049
                    if ($create) {
1050
                        mkdir($this->getMigrationPath(), 0700, true);
1051
                        $this->outSuccess('Created migration directory: '. $this->getMigrationPath());
1052
                    }
1053
                }
1054
1055
            } else {
1056
                $this->out($migration_name . ' did not log correctly', true);
1057
            }
1058
1059
        } elseif ($method == 'down') {
1060
            $migrationProcessClass->down();
1061
1062
            /** @var \BlendMigrations $migration */
1063
            $migration = $this->modx->getObject($this->blend_class_object, ['name' => $migration_name]);
1064
            if ($migration) {
0 ignored issues
show
introduced by
$migration is of type BlendMigrations, thus it always evaluated to true. If $migration can have other possible types, add them to src/Blender.php:1062
Loading history...
1065
                $migration->set('name', $migration_name);
1066
                $migration->set('description', $migrationProcessClass->getDescription());
1067
                $migration->set('version', $migrationProcessClass->getVersion());
1068
                $migration->set('status', 'down_complete');
1069
                $migration->set('processed_at', date('Y-m-d H:i:s'));
1070
                $migration->save();
1071
            }
1072
1073
        }
1074
    }
1075
1076
    /**
1077
     * @param string $method
1078
     */
1079
    public function update($method='up')
1080
    {
1081
        $current_vesion = $this->modx->getOption('blend.version');
1082
1083
        // new blender for each instance
1084
        $config = $this->config;
1085
        $config['migrations_path'] = __DIR__.'/Migrations/Blend/';
1086
1087
        $blender = new Blender($this->modx, $this->getUserInteractionHandler(), $config);
1088
1089
        foreach ($this->update_migrations as $v => $migration_name) {
1090
            if (version_compare($v, $current_vesion) === 1 ) {
1091
                // can not use as xPDO get queries fill the SELECT with the DB fields and since we are adding one this is a SQL error
1092
                //$blender->runMigration($method, 'master', 0, 0, $migration_name);
1093
1094
                /** @var Migrations $migrationProcessClass */
1095
                $migrationProcessClass = $this->loadMigrationClass($migration_name, $blender);
1096
1097
                if (!$migrationProcessClass instanceof Migrations) {
1098
                    $this->out('File is not an instance of LCI\Blend\Migrations: '.$migration_name, true);
1099
                    $this->out('Did not process, verify it is in the proper directory', true);
1100
1101
                } elseif ($method == 'up' && $this->isBlendInstalledInModx()) {
1102
1103
                    $migrationProcessClass->up();
1104
1105
                    /** @var \BlendMigrations $migration */
1106
                    $migration = $this->modx->newObject($this->blend_class_object);
1107
                    if ($migration) {
1108
                        $migration->set('name', $migration_name);
1109
                        $migration->set('type', 'master');
1110
                        $migration->set('description', $migrationProcessClass->getDescription());
1111
                        $migration->set('version', $migrationProcessClass->getVersion());
1112
                        $migration->set('status', 'up_complete');
1113
                        $migration->set('created_at', date('Y-m-d H:i:s'));
1114
                        $migration->set('processed_at', date('Y-m-d H:i:s'));
1115
                        if ($migration->save() ) {
1116
                            $this->outSuccess('Blend updated to '.$v);
1117
                        } else {
1118
                            $this->out('Blend did not update to '.$v, true);
1119
                        }
1120
1121
                    } else {
1122
                        $this->out('Blender could not save the update to '.$v, true);
1123
                    }
1124
1125
                } elseif ($method == 'down') {
1126
                    $migrationProcessClass->down();
1127
1128
                    /** @var \BlendMigrations $migration */
1129
                    $migration = $this->modx->getObject($this->blend_class_object, ['name' => $migration_name]);
1130
                    if ($migration) {
1131
                        $migration->set('name', $migration_name);
1132
                        $migration->set('description', $migrationProcessClass->getDescription());
1133
                        $migration->set('version', $migrationProcessClass->getVersion());
1134
                        $migration->set('status', 'down_complete');
1135
                        $migration->set('processed_at', date('Y-m-d H:i:s'));
1136
                        $migration->save();
1137
                    }
1138
1139
                }
1140
1141
            }
1142
        }
1143
1144
    }
1145
1146
    /**
1147
     * @return bool
1148
     */
1149
    public function requireUpdate()
1150
    {
1151
        $upgrade = false;
1152
1153
        $current_vesion = $this->modx->getOption('blend.version');
1154
        //                                      FILE version,        DB Version
1155
        if ( $this->isBlendInstalledInModx() && ( !$current_vesion || version_compare($this->getVersion(), $current_vesion)) ) {
1156
            $upgrade = true;
1157
        }
1158
1159
        return $upgrade;
1160
    }
1161
1162
    /**
1163
     * @return bool
1164
     */
1165
    public function isBlendInstalledInModx()
1166
    {
1167
        try {
1168
            $table = $this->modx->getTableName($this->blend_class_object);
1169
            if ($this->modx->query("SELECT 1 FROM {$table} LIMIT 1") === false) {
1170
                return false;
1171
            }
1172
        } catch (Exception $exception) {
1173
            // We got an exception == table not found
1174
            return false;
1175
        }
1176
1177
        /** @var \xPDOQuery $query */
1178
        $query = $this->modx->newQuery($this->blend_class_object);
1179
        $query->select('id');
1180
        $query->where([
1181
            'name' => 'install_blender',
1182
            'status' => 'up_complete'
1183
        ]);
1184
        $query->sortBy('name');
1185
1186
        $installMigration = $this->modx->getObject($this->blend_class_object, $query);
1187
        if ($installMigration instanceof \BlendMigrations || $installMigration instanceof \LCI\Blend\Model\xPDO\BlendMigrations) {
1188
            return true;
1189
        }
1190
1191
        return false;
1192
    }
1193
    /**
1194
     * @param string $method
1195
     * @param string $type
1196
     * @param int $count
1197
     * @param int $id
1198
     * @param string $name
1199
     */
1200
    public function runMigration($method='up', $type='master', $count=0, $id=0, $name=null)
1201
    {
1202
        $dir = 'ASC';
1203
        if ($method == 'down') {
1204
            $dir = 'DESC';
1205
        } else {
1206
            $count = 0;
1207
        }
1208
        // 1. Get all migrations currently in DB:
1209
        $blendMigrations = $this->getBlendMigrationCollection(false, $dir, $count, $id, $name);
1210
1211
        // 2. Load migration files:
1212
        if ($method == 'up') {
1213
            if ($this->retrieveMigrationFiles()) {
1214
                // this is needed just to insure that the order is correct and any new files
1215
                $blendMigrations = $this->getBlendMigrationCollection(true, $dir, $count, $id, $name);
1216
            }
1217
        }
1218
1219
        // 3. now run migration if proper
1220
        /** @var \BlendMigrations $migration */
1221
        foreach ($blendMigrations as $name => $migration) {
1222
            if ($id > 0 && $migration->get('id') != $id) {
1223
                continue;
1224
            }
1225
            /** @var string $name */
1226
            $name = $migration->get('name');
1227
1228
            /** @var string $status ~ ready|up_complete|down_complete*/
1229
            $status = $migration->get('status');
1230
1231
            /** @var string $server_type */
1232
            $server_type = $migration->get('type');
1233
1234
            if ( ($server_type != $type) || ($method == 'up' && $status == 'up_complete') || ($method == 'down' && $status != 'up_complete') ) {
1235
                continue;
1236
            }
1237
1238
            // new blender for each instance
1239
            $blender = new Blender($this->modx, $this->getUserInteractionHandler(), $this->config);
1240
1241
            /** @var Migrations $migrationProcessClass */
1242
            $migrationProcessClass = $this->loadMigrationClass($name, $blender);
1243
1244
            if ($migrationProcessClass instanceof Migrations) {
1245
                $this->out('Load Class: '.$name.' M: '.$method);
1246
                if ($method == 'up') {
1247
                    $migrationProcessClass->up();
1248
                    $this->out('Run up: '.$name);
1249
                    $migration->set('status', 'up_complete');
1250
                    $migration->set('processed_at', date('Y-m-d H:i:s'));
1251
                    $migration->save();
1252
1253
                } elseif ($method == 'down') {
1254
                    $migrationProcessClass->down();
1255
                    $migration->set('status', 'down_complete');
1256
                    $migration->set('processed_at', date('Y-m-d H:i:s'));
1257
                    $migration->save();
1258
1259
                } else {
1260
                    // error
1261
                }
1262
            } else {
1263
                // error
1264
            }
1265
        }
1266
    }
1267
1268
    /**
1269
     * @return bool ~ true if new migrations were found
1270
     */
1271
    public function retrieveMigrationFiles()
1272
    {
1273
        // 1. Get all migrations currently in DB:
1274
        $migrationCollection = $this->modx->getCollection($this->blend_class_object);
1275
1276
        $blendMigrations = [];
1277
1278
        /** @var \BlendMigrations $migration */
1279
        foreach ($migrationCollection as $migration) {
1280
            $blendMigrations[$migration->get('name')] = $migration;
1281
        }
1282
1283
        $migration_dir = $this->getMigrationPath();
1284
        $this->out('Searching '.$migration_dir);
1285
1286
        $reload = false;
1287
        /** @var \DirectoryIterator $file */
1288
        foreach (new \DirectoryIterator($this->getMigrationPath()) as $file) {
1289
            if ($file->isFile() && $file->getExtension() == 'php') {
1290
1291
                $name = $file->getBasename('.php');
1292
                // @TODO query DB! and test this method
1293
                if (!isset($blendMigrations[$name])) {
1294
                    $this->out('Create new '.$name);
1295
                    /** @var Migrations $migrationProcessClass */
1296
                    $migrationProcessClass = $this->loadMigrationClass($name, $this);
1297
1298
                    /** @var \BlendMigrations $migration */
1299
                    $migration = $this->modx->newObject($this->blend_class_object);
1300
                    $migration->set('name', $name);
1301
                    $migration->set('status', 'ready');
1302
                    if ($migrationProcessClass instanceof Migrations) {
1303
                        $migration->set('description', $migrationProcessClass->getDescription());
1304
                        $migration->set('version', $migrationProcessClass->getVersion());
1305
                        $migration->set('author', $migrationProcessClass->getAuthor());
1306
                    }
1307
                    if (!$migration->save()) {
1308
                        exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1309
                    };
1310
1311
                    $reload = true;
1312
                }
1313
            }
1314
        }
1315
        return $reload;
1316
    }
1317
1318
    /**
1319
     * @param string $name
1320
     * @param Blender $blender
1321
     *
1322
     * @return bool|Migrations
1323
     */
1324
    protected function loadMigrationClass($name, Blender $blender)
1325
    {
1326
        $migrationProcessClass = false;
1327
1328
        $file = $blender->getMigrationPath().$name.'.php';
1329
        if (file_exists($file)) {
1330
            require_once $file;
1331
1332
            if(class_exists($name)) {
1333
                /** @var Migrations $migrationProcessClass */
1334
                $migrationProcessClass = new $name($this->modx, $blender);
1335
            }
1336
        }
1337
1338
        return $migrationProcessClass;
1339
    }
1340
1341
    /**
1342
     * @param $type
1343
     * @param null $name
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $name is correct as it would always require null to be passed?
Loading history...
1344
     * @return string
1345
     */
1346
    public function getMigrationName($type, $name=null)
1347
    {
1348
        $format = new Format($this->seeds_dir);
1349
        return $format->getMigrationName($type, $name);
1350
    }
1351
1352
    /**
1353
     * @param string $name
1354
     * @param string $type ~ chunk, plugin, resource, snippet, systemSettings, template, site
1355
     *
1356
     * @return bool
1357
     */
1358
    public function removeMigrationFile($name, $type)
1359
    {
1360
        // @TODO refactor for setting $name
1361
        $class_name = $this->getMigrationName($type, $name);
1362
1363
        $removed = false;
1364
        $migration_file = $this->getMigrationPath() . $class_name . '.php';
1365
        if (file_exists($migration_file)) {
1366
            if (unlink($migration_file)) {
1367
                $removed = true;
1368
                $migration = $this->modx->getObject($this->blend_class_object, ['name' => $class_name]);
1369
                if (is_object($migration) && $migration->remove()) {
1370
                    $this->out($class_name . ' migration has been removed from the blend_migrations table');
1371
1372
                }
1373
            } else {
1374
                $this->out($class_name . ' migration has not been removed from the blend_migrations table', true);
1375
            }
1376
1377
        } else {
1378
            $this->out($this->getMigrationPath() . $class_name . '.php migration could not be found to remove', true);
1379
        }
1380
1381
        return $removed;
1382
    }
1383
    /**
1384
     * @param int $id
1385
     *
1386
     * @return bool|array
1387
     */
1388
    public function getResourceSeedKeyFromID($id)
1389
    {
1390
        if (!isset($this->resource_id_map[$id])) {
1391
            $seed_key = $context = false;
1392
            $resource = $this->modx->getObject('modResource', $id);
1393
            if ($resource) {
1394
                $context = $resource->get('context_key');
1395
                if (!isset($this->resource_seek_key_map[$context])) {
1396
                    $this->resource_seek_key_map[$context] = [];
1397
                }
1398
                $seed_key = $this->getSeedKeyFromAlias($resource->get('alias'));
1399
                $this->resource_seek_key_map[$context][$seed_key] = $id;
1400
            }
1401
            $this->resource_id_map[$id] = [
1402
                'context' => $context,
1403
                'seed_key' => $seed_key
1404
            ];
1405
        }
1406
1407
        return $this->resource_id_map[$id];
1408
    }
1409
1410
    /**
1411
     * @param string $seed_key
1412
     * @param string $context
1413
     *
1414
     * @return bool|int
1415
     */
1416
    public function getResourceIDFromSeedKey($seed_key, $context='web')
1417
    {
1418
        if (!isset($this->resource_seek_key_map[$context])) {
1419
            $this->resource_seek_key_map[$context] = [];
1420
        }
1421
        if (!isset($this->resource_seek_key_map[$context][$seed_key])) {
1422
            $id = false;
1423
            $alias = $this->getAliasFromSeedKey($seed_key);
1424
            $resource = $this->modx->getObject('modResource', ['alias' => $alias, 'context_key' => $context]);
1425
            if ($resource) {
1426
                $id = $resource->get('id');
1427
                $this->resource_seek_key_map[$context][$seed_key] = $id;
1428
                $this->resource_id_map[$id] = [
1429
                    'context' => $context,
1430
                    'seed_key' => $seed_key
1431
                ];
1432
            }
1433
            $this->resource_seek_key_map[$context][$seed_key] = $id;
1434
        }
1435
1436
        return $this->resource_seek_key_map[$context][$seed_key];
1437
    }
1438
1439
    /**
1440
     * @param string $alias
1441
     *
1442
     * @return string
1443
     */
1444
    public function getSeedKeyFromAlias($alias)
1445
    {
1446
        return str_replace('/', '#', $alias);
1447
    }
1448
1449
    /**
1450
     * @param string $seed_key
1451
     *
1452
     * @return string
1453
     */
1454
    public function getAliasFromSeedKey($seed_key)
1455
    {
1456
        return str_replace('#', '/', $seed_key);
1457
    }
1458
1459
    /**
1460
     * @deprecated
1461
     * @param string $name
1462
     * @param string $type ~ template, template-variable, chunk, snippet or plugin
1463
     * @return string
1464
     */
1465
    public function getElementSeedKeyFromName($name, $type)
1466
    {
1467
        return $type.'_'.$this->getSeedKeyFromName($name);
1468
    }
1469
1470
    /**
1471
     * @param string $name
1472
     * @return string
1473
     */
1474
    public function getSeedKeyFromName($name)
1475
    {
1476
        // @TODO review
1477
        return str_replace('/', '#', $name);
1478
    }
1479
1480
    /**
1481
     * @param string $seed_key
1482
     * @return string
1483
     */
1484
    public function getNameFromSeedKey($seed_key)
1485
    {
1486
        return str_replace('#', '/', $seed_key);
1487
    }
1488
1489
    /**
1490
     * @param $data
1491
     */
1492
    protected function logCreatedMigration($data)
1493
    {
1494
        try {
1495
            /** @var BlendMigrations $migration */
1496
            $migration = $this->modx->newObject($this->blend_class_object);
1497
            if ($migration) {
0 ignored issues
show
introduced by
$migration is of type LCI\Blend\Model\xPDO\BlendMigrations, thus it always evaluated to true. If $migration can have other possible types, add them to src/Blender.php:1495
Loading history...
1498
                $migration->fromArray($data);
1499
                $migration->save();
1500
            }
1501
        } catch (Exception $exception) {
1502
            $this->out($exception->getMessage(), true);
1503
        }
1504
    }
1505
}
1506
/**
1507
 * id | element_class | name | data | action ??
1508
 */
1509