SyncFlatten::getCurrentRelease()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Distilleries\Contentful\Commands\Sync;
4
5
use stdClass;
6
use Exception;
7
use Illuminate\Console\Command;
8
use Illuminate\Support\Collection;
9
use Illuminate\Support\Facades\DB;
10
use Distilleries\Contentful\Models\Locale;
11
use Distilleries\Contentful\Models\Release;
12
use Symfony\Component\Console\Helper\ProgressBar;
13
use Distilleries\Contentful\Repositories\AssetsRepository;
14
use Distilleries\Contentful\Repositories\EntriesRepository;
15
16
class SyncFlatten extends Command
17
{
18
    use Traits\SyncTrait;
19
20
    /**
21
     * Number of entries to fetch per pagination.
22
     *
23
     * @var integer
24
     */
25
    const PER_BATCH = 50;
26
27
    /**
28
     * {@inheritdoc}
29
     */
30
    protected $signature = 'contentful:sync-flatten {--preview} {--no-switch} {--no-truncate} {--multi}';
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    protected $description = 'Map and persist previously synced Contentful data';
36
37
    /**
38
     * Assets repository instance.
39
     *
40
     * @var \Distilleries\Contentful\Repositories\AssetsRepository
41
     */
42
    protected $assets;
43
44
    /**
45
     * Entries repository instance.
46
     *
47
     * @var \Distilleries\Contentful\Repositories\EntriesRepository
48
     */
49
    protected $entries;
50
51
    /**
52
     * MapEntries command constructor.
53
     *
54
     * @return void
55
     */
56
    public function __construct()
57
    {
58
        parent::__construct();
59
60
        $this->assets = new AssetsRepository;
61
62
        $this->entries = new EntriesRepository;
63
    }
64
65
    /**
66
     * Check if switch.
67
     *
68
     * @return bool
69
     */
70
    protected function canSwitch(): bool
71
    {
72
        $bool = $this->option('no-switch');
73
74
        return ! empty($bool) ? false : true;
75
    }
76
77
    /**
78
     * Check if no truncate.
79
     *
80
     * @return bool
81
     */
82
    protected function withoutTruncate(): bool
83
    {
84
        $bool = $this->option('no-truncate');
85
86
        return ! empty($bool) ? true : false;
87
    }
88
89
    /**
90
     * Check if preview.
91
     *
92
     * @return bool
93
     */
94
    protected function isPreview(): bool
95
    {
96
        $bool = $this->option('preview');
97
98
        return ! empty($bool) ? true : false;
99
    }
100
101
    /**
102
     * Check if multi-thread.
103
     *
104
     * @return bool
105
     */
106
    protected function isMultiThread(): bool
107
    {
108
        $bool = $this->option('multi');
109
110
        return ! empty($bool) ? true : false;
111
    }
112
113
    /**
114
     * Execute the console command.
115
     *
116
     * @param  \Distilleries\Contentful\Models\Release  $release
117
     * @return void
118
     */
119
    public function handle(Release $release)
120
    {
121
        $isPreview = $this->isPreview();
122
123
        if ($this->canSwitch()) {
124
            $this->call('contentful:sync-switch', $isPreview ? ['--preview' => true] : []);
125
        }
126
127
        $this->switchToSyncDb();
128
129
        if (! $this->withoutTruncate()) {
130
            $this->line('Truncate Contentful related tables');
131
            $this->assets->truncateRelatedTables();
132
            $this->entries->truncateRelatedTables();
133
        }
134
135
        try {
136
            $this->line('Map and persist synced data');
137
            if ($this->isMultiThread()) {
138
                $release = $this->getCurrentRelease($release);
139
                $this->flattenSyncedDataMultiThread($release);
140
            } else {
141
                $this->flattenSyncedData();
142
            }
143
        } catch (Exception $e) {
144
            echo PHP_EOL;
145
            $this->error($e->getMessage());
146
            return;
147
        }
148
149
        if ($this->canSwitch()) {
150
            $this->call('contentful:sync-switch', $isPreview ? ['--preview' => true, '--live' => true] : ['--live' => true]);
151
        }
152
    }
153
154
    /**
155
     * Map and persist synced data.
156
     *
157
     * @return void
158
     * @throws \Exception
159
     */
160
    protected function flattenSyncedData()
161
    {
162
        $page = 1;
163
        $paginator = DB::table('sync_entries')->paginate(static::PER_BATCH, ['*'], 'page', $page);
164
        $locales = Locale::all();
165
        $locales = is_array($locales) ? collect($locales) : $locales;
0 ignored issues
show
introduced by
The condition is_array($locales) is always false.
Loading history...
166
167
        $bar = $this->createProgressBar($paginator->total());
168
        while ($paginator->isNotEmpty()) {
169
            foreach ($paginator->items() as $item) {
170
                $bar->setMessage('Map entry ID: ' . $item->contentful_id);
171
                $this->mapItemToContentfulModel($item, $locales);
172
                $bar->advance();
173
            }
174
175
            $page++;
176
            $paginator = DB::table('sync_entries')->paginate(static::PER_BATCH, ['*'], 'page', $page);
177
        }
178
        $bar->finish();
179
180
        echo PHP_EOL;
181
    }
182
183
    protected function flattenSyncedDataMultiThread(Release $release)
184
    {
185
        $locales = collect(Locale::all());
186
        $locales = is_array($locales) ? collect($locales) : $locales;
0 ignored issues
show
introduced by
The condition is_array($locales) is always false.
Loading history...
187
188
        $bar = $this->createProgressBar(DB::table('sync_entries')->count());
189
        do {
190
            try {
191
                $this->updateFromOtherThread($bar);
192
                $items = collect();
193
194
                DB::transaction(function () use ($release, & $items) {
195
                    $items = DB::table('sync_entries')
196
                        ->whereNull('release_id')
197
                        ->take(static::PER_BATCH)
198
                        ->lockForUpdate()
199
                        ->get();
200
201
                    DB::table('sync_entries')
202
                        ->whereIn('contentful_id', $items->pluck('contentful_id')->toArray())
203
                        ->lockForUpdate()
204
                        ->update(['release_id' => $release->getKey()]);
205
                });
206
            } catch (Exception $e) {
207
                $items = collect();
208
            }
209
210
            $items->each(function ($item, $key) use ($locales, $bar) {
0 ignored issues
show
Unused Code introduced by
The parameter $key 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

210
            $items->each(function ($item, /** @scrutinizer ignore-unused */ $key) use ($locales, $bar) {

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...
211
                $bar->setMessage('Map entry ID: ' . $item->contentful_id);
212
                $this->mapItemToContentfulModel($item, $locales);
213
                $bar->advance();
214
            });
215
216
        } while (DB::table('sync_entries')->whereNull('release_id')->count() > 0);
217
218
        $bar->finish();
219
    }
220
221
    /**
222
     * Update progress from other threads.
223
     *
224
     * @return void
225
     */
226
    protected function updateFromOtherThread($bar)
227
    {
228
        $bar->setProgress((DB::table('sync_entries'))->whereNotNull('release_id')->count());
229
    }
230
231
    /**
232
     * Get current release.
233
     *
234
     * @param  \Distilleries\Contentful\Models\Release  $release
235
     * @return \Distilleries\Contentful\Models\Release|null
236
     */
237
    protected function getCurrentRelease(Release $release)
238
    {
239
        return $release->where('current', true)->get()->first();
240
    }
241
242
    /**
243
     * Create custom progress bar.
244
     *
245
     * @param  integer  $total
246
     * @return \Symfony\Component\Console\Helper\ProgressBar
247
     */
248
    protected function createProgressBar(int $total): ProgressBar
249
    {
250
        $bar = $this->output->createProgressBar($total);
251
252
        $bar->setFormat("%message%" . PHP_EOL . " %current%/%max% [%bar%] %percent:3s%%");
253
254
        return $bar;
255
    }
256
257
    /**
258
     * Map and persist given sync_entries item.
259
     *
260
     * @param  \stdClass  $item
261
     * @param  \Illuminate\Support\Collection $locales
262
     * @return void
263
     * @throws \Exception
264
     */
265
    protected function mapItemToContentfulModel(stdClass $item, Collection $locales)
266
    {
267
        $entry = json_decode($item->payload, true);
268
269
        if ($item->contentful_type === 'asset') {
270
            $this->assets->toContentfulModel($entry, $locales);
271
        } else {
272
            $this->entries->toContentfulModel($entry, $locales);
273
        }
274
    }
275
}
276