Completed
Push — master ( 185c31...77478e )
by Glynn
03:11 queued 03:11
created

Migration_Log_Manager::clear_log()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Holds a log of the last table constructed
7
 *
8
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
9
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
10
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
12
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
13
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
14
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
15
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
16
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
18
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
 *
20
 * @author Glynn Quelch <[email protected]>
21
 * @license http://www.opensource.org/licenses/mit-license.html  MIT License
22
 * @package PinkCrab\DB_Migration
23
 */
24
25
namespace PinkCrab\DB_Migration\Log;
26
27
use InvalidArgumentException;
28
use PinkCrab\Table_Builder\Schema;
29
use PinkCrab\DB_Migration\Log\Migration_Log;
30
31
class Migration_Log_Manager {
32
33
	/**
34
	 * The key used to hold all migration dates
35
	 * Can be shared between multiple plugins.
36
	 *
37
	 * @var string
38
	 */
39
	protected $option_key;
40
41
	/**
42
	 * Current migration details
43
	 *
44
	 * @var array<Migration_Log>
45
	 */
46
	protected $migration_details = array();
47
48
	public function __construct( string $option_key = null ) {
49
		$this->option_key = $option_key ?? 'pinkcrab_migration_log';
50
		$this->set_migration_details();
51
	}
52
53
	/**
54
	 * Sets the migration details held in optiosn
55
	 *
56
	 * @return void
57
	 * @throws InvalidArgumentException If can not unserialize
58
	 */
59
	protected function set_migration_details(): void {
60
		$migrations = get_option( $this->option_key, null );
61
62
		if ( $migrations === null ) {
63
			return;
64
		}
65
66
		// Handle errors as exceptions.
67
		set_error_handler( // phpcs:ignore
68
			function ( int $errno, string $errstr ) { // phpcs:ignore
0 ignored issues
show
Unused Code introduced by
The parameter $errstr 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

68
			function ( int $errno, /** @scrutinizer ignore-unused */ string $errstr ) { // phpcs:ignore

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...
Unused Code introduced by
The parameter $errno 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

68
			function ( /** @scrutinizer ignore-unused */ int $errno, string $errstr ) { // phpcs:ignore

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...
69
				throw new InvalidArgumentException( 'Migration details as unserialize from options, failed to be decoded.' );
70
			}
71
		);
72
		$migrations = \unserialize( $migrations ); // phpcs:ignore
0 ignored issues
show
Bug introduced by
It seems like $migrations can also be of type false; however, parameter $data of unserialize() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

72
		$migrations = \unserialize( /** @scrutinizer ignore-type */ $migrations ); // phpcs:ignore
Loading history...
73
		restore_error_handler();
74
75
		$this->migration_details = $migrations;
76
	}
77
78
	/**
79
	 * Checks if a table has been migrated
80
	 *
81
	 * @param \PinkCrab\Table_Builder\Schema $schema
82
	 * @return boolean
83
	 */
84
	public function has_migration( Schema $schema ): bool {
85
		return array_key_exists( $schema->get_table_name(), $this->migration_details );
86
	}
87
88
	/**
89
	 * Gets a migration log based on its name
90
	 *
91
	 * @return \PinkCrab\DB_Migration\Log\Migration_Log|null
92
	 */
93
	public function get_migration( Schema $schema ): ?Migration_Log {
94
		return $this->has_migration( $schema )
95
			? $this->migration_details[ $schema->get_table_name() ]
96
			: null;
97
	}
98
99
	/**
100
	 * Check if a table can be migrated.
101
	 *
102
	 * @param \PinkCrab\Table_Builder\Schema $schema
103
	 * @return bool
104
	 */
105
	public function can_migrate( Schema $schema ): bool {
106
		return ! $this->check_hash( $schema );
107
	}
108
109
	/**
110
	 * Checks if the define table has been seeded.
111
	 *
112
	 * @param \PinkCrab\Table_Builder\Schema $schema
113
	 * @return bool
114
	 */
115
	public function is_seeded( Schema $schema ): bool {
116
		return $this->has_migration( $schema )
117
		&& $this->migration_details[ $schema->get_table_name() ]->is_seeded();
118
	}
119
120
	/**
121
	 * Checks if the passed schema's hash matches the existing schema hash.
122
	 *
123
	 * @param \PinkCrab\Table_Builder\Schema $schema
124
	 * @return bool
125
	 */
126
	private function check_hash( Schema $schema ): bool {
127
		// If table doesnt exist, return false;
128
		if ( ! $this->has_migration( $schema ) ) {
129
			return false;
130
		}
131
132
		$schema_hash = Migration_Log::compose_column_hash( $schema );
133
		$migration   = $this->migration_details[ $schema->get_table_name() ];
134
		return strcmp( $schema_hash, $migration->schema_hash() ) === 0;
135
	}
136
137
	/**
138
	 * Upserts a migration based on its schema.
139
	 *
140
	 * - Upates if Migration exists, but schema is different.
141
	 * - Creates if Migration doesnt exist.
142
	 *
143
	 * Only updates the schema is actually upserted.
144
	 *
145
	 * @param \PinkCrab\Table_Builder\Schema $schema
146
	 * @return self
147
	 */
148
	public function upsert_migration( Schema $schema ): self {
149
		// Update if table exists and we have a new schema defined.
150
		if ( $this->has_migration( $schema )
151
		&& ! $this->check_hash( $schema ) ) {
152
			$this->migration_details[ $schema->get_table_name() ] =
153
				$this->migration_details[ $schema->get_table_name() ]->as_updated( $schema );
154
155
			$this->save();
156
		}
157
158
		// If a new hash.
159
		if ( $this->has_migration( $schema ) === false ) {
160
			$this->migration_details[ $schema->get_table_name() ] =
161
				Migration_Log::new_from_schema( $schema );
162
163
			$this->save();
164
		}
165
166
		return $this;
167
	}
168
169
	/**
170
	 * Removes a migration from the log based on its schema.
171
	 *
172
	 * @param \PinkCrab\Table_Builder\Schema $schema
173
	 * @return self
174
	 */
175
	public function remove_migration( Schema $schema ): self {
176
		if ( $this->has_migration( $schema ) ) {
177
			unset( $this->migration_details[ $schema->get_table_name() ] );
178
179
			$this->save();
180
		}
181
		return $this;
182
	}
183
184
	/**
185
	 * If the table has not already been seeded, update the to denote it has.
186
	 *
187
	 * @param \PinkCrab\Table_Builder\Schema $schema
188
	 * @return self
189
	 */
190
	public function mark_table_seeded( Schema $schema ): self {
191
		if ( ! $this->is_seeded( $schema ) ) {
192
			$this->migration_details[ $schema->get_table_name() ] =
193
				$this->migration_details[ $schema->get_table_name() ]->as_seeded();
194
195
			$this->save();
196
		}
197
198
		return $this;
199
	}
200
201
	/**
202
	 * Saves the current migration details
203
	 *
204
	 * @return void
205
	 */
206
	protected function save(): void {
207
		\update_option( $this->option_key, serialize( $this->migration_details ), false ); // phpcs:ignore
208
	}
209
210
	/**
211
	 * Returns the migration log key
212
	 *
213
	 * @return string
214
	 */
215
	public function get_log_key(): string {
216
		return $this->option_key;
217
	}
218
219
	/**
220
	 * Clears the log from options table
221
	 *
222
	 * @return void
223
	 */
224
	public function clear_log(): void {
225
		\delete_option( $this->option_key );
226
	}
227
}
228