PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.18.0
GiveWP – Donation Plugin and Fundraising Platform v4.18.0
4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 All 257 releases
give / src / Framework / Migrations / MigrationsRunner.php

MigrationsRunner.php in GiveWP – Donation Plugin and Fundraising Platform 4.18.0, at src/Framework/Migrations/MigrationsRunner.php

235 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Give\Framework\Migrations;
4
5 use Exception;
6 use Give\Framework\Database\DB;
7 use Give\Framework\Database\Exceptions\DatabaseQueryException;
8 use Give\Framework\Migrations\Contracts\BatchMigration;
9 use Give\Framework\Migrations\Contracts\Migration;
10 use Give\Framework\Migrations\Controllers\BatchMigrationRunner;
11 use Give\Log\Log;
12 use Give\MigrationLog\MigrationLogFactory;
13 use Give\MigrationLog\MigrationLogRepository;
14 use Give\MigrationLog\MigrationLogStatus;
15 use WP_Upgrader;
16
17 /**
18 * Class MigrationsRunner
19 *
20 * @since 2.9.0
21 */
22 class MigrationsRunner
23 {
24 /**
25 * @since 4.18.0
26 */
27 const LOCK_NAME = 'give_migrations';
28
29 /**
30 * List of completed migrations.
31 *
32 * @since 2.9.0
33 *
34 * @var array
35 */
36 private $completedMigrations;
37
38 /**
39 * @since 2.9.0
40 *
41 * @var MigrationsRegister
42 */
43 private $migrationRegister;
44
45 /**
46 * @since 2.10.0
47 *
48 * @var MigrationLogFactory
49 */
50 private $migrationLogFactory;
51
52 /**
53 * @since 2.10.0
54 * @var MigrationLogRepository
55 */
56 private $migrationLogRepository;
57
58 /**
59 * MigrationsRunner constructor.
60 *
61 * @param MigrationsRegister $migrationRegister
62 * @param MigrationLogFactory $migrationLogFactory
63 * @param MigrationLogRepository $migrationLogRepository
64 */
65 public function __construct(
66 MigrationsRegister $migrationRegister,
67 MigrationLogFactory $migrationLogFactory,
68 MigrationLogRepository $migrationLogRepository
69 ) {
70 $this->migrationRegister = $migrationRegister;
71 $this->migrationLogFactory = $migrationLogFactory;
72 $this->migrationLogRepository = $migrationLogRepository;
73 $this->completedMigrations = $this->migrationLogRepository->getCompletedMigrationsIDs();
74 }
75
76 /**
77 * Run database migrations.
78 *
79 * @since 4.18.0 hold a lock so concurrent requests do not run the same migration twice
80 * @since 4.0.0 add support for batch processing
81 * @since 2.9.0
82 */
83 public function run()
84 {
85 if ( ! $this->hasMigrationToRun()) {
86 return;
87 }
88
89 // Stop Migration Runner if there are failed migrations
90 if ($this->migrationLogRepository->getFailedMigrationsCountByIds(
91 $this->migrationRegister->getRegisteredIds()
92 )) {
93 return;
94 }
95
96 if ( ! class_exists('WP_Upgrader')) {
97 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
98 }
99
100 // Migrations run on every request, so without this a slow one (an ALTER TABLE over millions of
101 // rows) starts again in every request that arrives while it is still running.
102 if ( ! WP_Upgrader::create_lock(self::LOCK_NAME)) {
103 return;
104 }
105
106 try {
107 $migrations = $this->migrationRegister->getMigrations();
108
109 foreach ($migrations as $migrationClass) {
110 $migrationId = $migrationClass::id();
111
112 if (in_array($migrationId, $this->completedMigrations, true)) {
113 continue;
114 }
115
116 $migrationLog = $this->migrationLogFactory->make($migrationId);
117
118 try {
119 /**
120 * @var Migration|BatchMigration $migration
121 */
122 $migration = give($migrationClass);
123
124 if ($migration instanceof BatchMigration) {
125 $status = (new BatchMigrationRunner($migration))->run();
126
127 if ($status === MigrationLogStatus::RUNNING) {
128 give()->notices->register_notice(
129 [
130 'id' => $migrationId,
131 'description' => esc_html__('GiveWP is running database updates in the background. You will be notified as soon as it completes.',
132 'give'),
133 ]
134 );
135
136 // Update status to RUNNING
137 if (MigrationLogStatus::RUNNING !== $migrationLog->getStatus()) {
138 $migrationLog->setStatus(MigrationLogStatus::RUNNING);
139 $migrationLog->save();
140 }
141
142 break;
143 }
144
145 if ($status === MigrationLogStatus::INCOMPLETE) {
146 $listTableLink = sprintf(
147 '<a href="%s">%s</a>',
148 admin_url('edit.php?post_type=give_forms&page=give-tools&tab=data'),
149 esc_html__('Resume update', 'give')
150 );
151
152 give()->notices->register_notice(
153 [
154 'id' => $migrationId,
155 'type' => 'warning',
156 'description' => sprintf(
157 __('Incomplete database update: "%s". %s', 'give'),
158 $migration::title(),
159 $listTableLink
160 ),
161 ]
162 );
163 }
164
165 $migrationLog->setStatus($status);
166 } else {
167 $migration->run();
168 $migrationLog->setStatus(MigrationLogStatus::SUCCESS);
169 }
170 } catch (Exception $exception) {
171 DB::rollback();
172 $migrationLog
173 ->setStatus(MigrationLogStatus::FAILED)
174 ->setError([
175 'status' => __('Migration failed', 'give'),
176 'error' => [
177 'message' => $exception->getMessage(),
178 'code' => $exception->getCode(),
179 'file' => $exception->getFile(),
180 'line' => $exception->getLine(),
181 ],
182 ]);
183
184 give()->notices->register_notice(
185 [
186 'id' => 'migration-failure',
187 'description' => sprintf(
188 '%1$s <a href="https://givewp.com/support/">https://givewp.com/support</a>',
189 esc_html__(
190 'There was a problem running the migrations. Please reach out to GiveWP support for assistance:',
191 'give'
192 )
193 ),
194 ]
195 );
196 }
197
198 try {
199 $migrationLog->save();
200 } catch (DatabaseQueryException $e) {
201 Log::error(
202 'Failed to save migration log',
203 [
204 'Error Message' => $e->getMessage(),
205 'Query Errors' => $e->getQueryErrors(),
206 ]
207 );
208 }
209
210 // Stop Migration Runner if migration has failed
211 if ($migrationLog->getStatus() === MigrationLogStatus::FAILED) {
212 break;
213 }
214
215 // Commit transaction if successful
216 DB::commit();
217 }
218 } finally {
219 WP_Upgrader::release_lock(self::LOCK_NAME);
220 }
221 }
222
223 /**
224 * Return whether or not all migrations completed.
225 *
226 * @since 2.9.0
227 *
228 * @return bool
229 */
230 public function hasMigrationToRun()
231 {
232 return (bool)array_diff($this->migrationRegister->getRegisteredIds(), $this->completedMigrations);
233 }
234 }
235