Passed
Push — master ( 7af0e6...874476 )
by Glynn
05:51 queued 01:56
created

Meta_Data_Registrar::create_rest_get_method()   A

Complexity

Conditions 5
Paths 1

Size

Total Lines 25
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 18
c 0
b 0
f 0
dl 0
loc 25
rs 9.3554
cc 5
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Used for registering Meta Data.
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\Registerables
23
 * @since 0.7.1
24
 */
25
26
namespace PinkCrab\Registerables\Registrar;
27
28
use PinkCrab\Registerables\Meta_Data;
29
30
class Meta_Data_Registrar {
31
32
	/**
33
	 * Registers meta data for post types.
34
	 *
35
	 * @param \PinkCrab\Registerables\Meta_Data $meta
36
	 * @param string $post_type
37
	 * @return bool
38
	 * @throws \Exception if fails to register meta data.
39
	 */
40
	public function register_for_post_type( Meta_Data $meta, string $post_type ):bool {
41
		return $this->register_meta( $meta, 'post', $post_type );
42
	}
43
44
	/**
45
	 * Registers meta data for terms.
46
	 *
47
	 * @param \PinkCrab\Registerables\Meta_Data $meta
48
	 * @param string $taxonomy
49
	 * @return bool
50
	 * @throws \Exception if fails to register meta data.
51
	 */
52
	public function register_for_term( Meta_Data $meta, string $taxonomy ):bool {
53
		return $this->register_meta( $meta, 'term', $taxonomy );
54
	}
55
56
	/**
57
	 * Registers meta data for a defined type.
58
	 *
59
	 * Will cast WP Rest Schema model to array
60
	 *
61
	 * @param \PinkCrab\Registerables\Meta_Data $meta
62
	 * @param  string $meta_type The object type ('post', 'user', 'comment', 'term')
63
	 * @param  string $sub_type The object sub-type ('post_type', 'taxonomy')
64
	 * @return bool
65
	 * @throws \Exception if fails to register meta data.
66
	 */
67
	protected function register_meta( Meta_Data $meta, string $meta_type, string $sub_type ): bool {
68
		// Clone and set the post type, while enforcing it as a post meta.
69
		$meta = clone $meta;
70
		$meta->object_subtype( $sub_type );
71
		$meta->meta_type( $meta_type );
72
73
		// Normalise rest schema model to array.
74
		$meta = $this->normalise_rest_schema( $meta );
75
76
		$result = register_meta( $meta->get_meta_type(), $meta->get_meta_key(), $meta->parse_args() );
77
		if ( ! $result ) {
78
			throw new \Exception(
79
				"Failed to register {$meta->get_meta_key()} (meta) for {$sub_type} of {$meta_type} type"
80
			);
81
		}
82
83
		// Maybe register rest fields.
84
		if ( false !== $meta->get_rest_schema() ) {
85
			$this->register_meta_rest_field( $meta );
86
		}
87
88
		return $result;
89
	}
90
91
92
	/**
93
	 * Potentially casts a Rest Schema to an array.
94
	 *
95
	 * Only if the module active and the schema is Argument type.
96
	 *
97
	 * @param \PinkCrab\Registerables\Meta_Data $meta
98
	 * @return \PinkCrab\Registerables\Meta_Data
99
	 */
100
	protected function normalise_rest_schema( Meta_Data $meta ): Meta_Data {
101
		if ( \class_exists( 'PinkCrab\WP_Rest_Schema\Argument\Argument' )
102
		&& $meta->get_rest_schema() instanceof \PinkCrab\WP_Rest_Schema\Argument\Argument
103
		) {
104
			$meta->rest_schema( \PinkCrab\WP_Rest_Schema\Parser\Argument_Parser::for_meta_data( $meta->get_rest_schema() ) );
105
		}
106
		return $meta;
107
	}
108
109
	/**
110
	* Registers a Meta Data object as defined REST field.
111
	*
112
	* @param \PinkCrab\Registerables\Meta_Data $meta
113
	* @return void
114
	*/
115
	public function register_meta_rest_field( Meta_Data $meta ) {
116
		// Skip if not sub type defined for post or term.
117
		if ( null === $meta->get_subtype() ) {
118
			return;
119
		}
120
121
		add_action(
122
			'rest_api_init',
123
			function () use ( $meta ) {
124
				register_rest_field(
125
					$meta->get_subtype(),
126
					$meta->get_meta_key(),
127
					array( // @phpstan-ignore-line WP Docblock doesn't give enough details of callable param types, so throws false positive
128
						'get_callback'    => $meta->get_rest_view() ?? $this->create_rest_get_method( $meta ),
129
						'schema'          => $meta->get_rest_schema(),
130
						'update_callback' => $meta->get_rest_update() ?? $this->create_rest_update_method( $meta ),
131
					)
132
				);
133
			}
134
		);
135
	}
136
137
	/**
138
	 * Creates a fallback rest get callback.
139
	 *
140
	 * @param \PinkCrab\Registerables\Meta_Data $meta
141
	 * @return callable(array<mixed>):void
142
	 */
143
	protected function create_rest_get_method( Meta_Data $meta ): callable {
144
		return function( $model ) use ( $meta ) {
145
			switch ( $meta->get_meta_type() ) {
146
				case 'post':
147
					$value = get_post_meta( $model['id'], $meta->get_meta_key(), true );
148
					break;
149
150
				case 'term':
151
					$value = get_term_meta( $model['id'], $meta->get_meta_key(), true );
152
					break;
153
154
				case 'user':
155
					$value = get_user_meta( $model['id'], $meta->get_meta_key(), true );
156
					break;
157
158
				case 'comment':
159
					$value = get_comment_meta( $model['id'], $meta->get_meta_key(), true );
160
					break;
161
162
				default:
163
					$value = null;
164
					break;
165
			}
166
167
			return $value;
168
		};
169
	}
170
171
	/**
172
	 * Creates a fallback rest update callback.
173
	 *
174
	 * @param Meta_Data $meta
175
	 * @return callable(mixed $value, \WP_Post|\WP_Term|\WP_User|\WP_Comment $object)
176
	 */
177
	protected function create_rest_update_method( Meta_Data $meta ): callable {
178
		/**
179
		 * @param mixed $value
180
		 * @param \WP_Post|\WP_Term|\WP_User|\WP_Comment $object
181
		 */
182
		return function( $value, $object ) use ( $meta ) {
183
			switch ( $meta->get_meta_type() ) {
184
				case 'post':
185
					/** @var \WP_Post $object */
186
					update_post_meta( $object->ID, $meta->get_meta_key(), $value );
187
					break;
188
189
				case 'term':
190
					/** @var \WP_Term $object */
191
					update_term_meta( $object->term_id, $meta->get_meta_key(), $value );
192
					break;
193
194
				case 'user':
195
					/** @var \WP_User $object */
196
					update_user_meta( $object->ID, $meta->get_meta_key(), $value );
197
					break;
198
199
				case 'comment':
200
					/** @var \WP_Comment $object */
201
					update_comment_meta( (int) $object->comment_ID, $meta->get_meta_key(), $value );
202
					break;
203
204
				default:
205
					// @codeCoverageIgnoreStart
206
					break;
207
					// @codeCoverageIgnoreEnd
208
			}
209
210
			return $value;
211
		};
212
	}
213
}
214