PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / trunk
Pods – Custom Content Types and Fields vtrunk
trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / src / Pods / Integrations / WPGraphQL / Field.php
pods / src / Pods / Integrations / WPGraphQL Last commit date
Connection_Resolver 4 months ago Connection.php 4 months ago Field.php 4 months ago Integration.php 4 months ago Service_Provider.php 4 months ago Settings.php 4 months ago
Field.php
318 lines
1 <?php
2
3 namespace Pods\Integrations\WPGraphQL;
4
5 // Don't load directly.
6 if ( ! defined( 'ABSPATH' ) ) {
7 die( '-1' );
8 }
9
10 use Exception;
11 use GraphQL\Type\Definition\ResolveInfo;
12 use Pods\Pod_Manager;
13 use Pods\Whatsit\Field as Pod_Field;
14 use Pods\Whatsit\Pod;
15 use WPGraphQL\AppContext;
16 use WPGraphQL\Data\Loader\PostObjectLoader;
17 use WPGraphQL\Model\Comment;
18 use WPGraphQL\Model\Menu;
19 use WPGraphQL\Model\MenuItem;
20 use WPGraphQL\Model\Model;
21 use WPGraphQL\Model\Post;
22 use WPGraphQL\Model\Term;
23 use WPGraphQL\Model\User;
24
25 /**
26 * Field interfacing functionality for GraphQL.
27 *
28 * @since 2.9.0
29 */
30 class Field {
31
32 /**
33 * The field data.
34 *
35 * @since 2.9.0
36 *
37 * @var Pod_Field
38 */
39 private $field;
40
41 /**
42 * The pod data.
43 *
44 * @since 2.9.0
45 *
46 * @var Pod
47 */
48 private $pod;
49
50 /**
51 * List of arguments.
52 *
53 * @since 2.9.0
54 *
55 * @var array
56 */
57 private $args;
58
59 /**
60 * List of connections that need to be registered later.
61 *
62 * @since 2.9.0
63 *
64 * @var array
65 */
66 private static $connections = [];
67
68 /**
69 * Field constructor.
70 *
71 * @since 2.9.0
72 *
73 * @param Pod_Field $field The field data.
74 * @param Pod $pod The pod data.
75 * @param array $args List of arguments to setup.
76 */
77 public function __construct( $field, $pod, $args ) {
78 $this->field = $field;
79 $this->pod = $pod;
80 $this->args = $args;
81
82 $required = [
83 'type_name',
84 'field_name',
85 'graphql_type',
86 ];
87
88 // If we are missing required arguments, don't register the field.
89 foreach ( $required as $arg ) {
90 if ( empty( $this->args[ $arg ] ) ) {
91 return;
92 }
93 }
94
95 // Register the field.
96 $this->register_field();
97 }
98
99 /**
100 * Register the field.
101 *
102 * @since 2.9.0
103 */
104 public function register_field() {
105 $is_connection = 'connection' === $this->args['graphql_format'] && ! empty( $this->args['related_type_name'] );
106 $is_multi = is_array( $this->args['graphql_type'] ) && isset( $this->args['graphql_type']['list_of'] );
107 $connection_name = null;
108
109 if ( $is_connection ) {
110 $connection_name = $this->args['type_name'] . '_' . $this->args['field_name'] . '_connection';
111
112 $this->args['graphql_type'] = $connection_name;
113
114 if ( $is_multi ) {
115 $this->args['graphql_type'] = [
116 'list_of' => $this->args['graphql_type'],
117 ];
118 }
119 }
120
121 $config = [
122 'type' => $this->args['graphql_type'],
123 'args' => [
124 'format' => [
125 'type' => 'PostObjectFieldFormatEnum',
126 'description' => __( 'Format of the field output', 'pods' ),
127 ],
128 ],
129 'resolve' => [ $this, 'get_field_value' ],
130 ];
131
132 // Remove the format arg if the type is not a string.
133 if ( 'String' !== $this->args['graphql_type'] && ( ! $is_multi || 'String' !== $this->args['graphql_type']['list_of'] ) ) {
134 unset( $config['args'] );
135 }
136
137 try {
138 // Save the config for reference later.
139 $this->args['config'] = $config;
140 $this->args['is_multi'] = $is_multi;
141
142 if ( ! $is_connection ) {
143 register_graphql_field( $this->args['type_name'], $this->args['field_name'], $config );
144 }
145
146 // Maybe add a connection to set up later.
147 if ( $is_connection ) {
148 self::$connections[] = [
149 'from' => $this->args['type_name'],
150 'from_field' => $this->args['field_name'],
151 'name' => $connection_name,
152 'to' => $this->args['related_type_name'],
153 'object_type' => $this->args['related_object_type'],
154 'object_name' => $this->args['related_object_name'],
155 'is_multi' => $is_multi,
156 'field' => $this,
157 ];
158 }
159 } catch ( Exception $exception ) {
160 // Connection was not registered.
161 throw $exception;
162 }
163 }
164
165 /**
166 * Get the ID from the model object.
167 *
168 * @since 2.9.0
169 *
170 * @param Model $source The model object.
171 *
172 * @return int|null The ID or null if not supported.
173 */
174 public function get_id_from_model( $source ) {
175 switch ( true ) {
176 case $source instanceof Term:
177 $id = $source->term_id;
178 break;
179 case $source instanceof Post:
180 $id = $source->ID;
181 break;
182 case $source instanceof MenuItem:
183 $id = $source->menuItemId;
184 break;
185 case $source instanceof Menu:
186 $id = $source->menuId;
187 break;
188 case $source instanceof User:
189 $id = $source->userId;
190 break;
191 case $source instanceof Comment:
192 $id = $source->comment_ID;
193 break;
194 default:
195 $id = null;
196 break;
197 }
198
199 return $id;
200 }
201
202 /**
203 * Get the ID from the root object.
204 *
205 * @since 2.9.0
206 *
207 * @param Model $source The source passed down from the resolve tree.
208 * @param array $args List of arguments input in the field as part of the GraphQL query.
209 * @param AppContext $context Object containing app context that gets passed down the resolve tree.
210 * @param ResolveInfo $info Info about fields passed down the resolve tree.
211 *
212 * @return mixed The field value.
213 */
214 public function get_field_value( $source, $args, $context, $info ) {
215 $id = $this->get_id_from_model( $source );
216
217 if ( null === $id ) {
218 return '';
219 }
220
221 $pod = pods_container( Pod_Manager::class )->get_pod( $this->pod->get_name(), $id );
222
223 $field_name = $this->field->get_name();
224
225 $format = pods_v( 'format', $args, 'rendered', true );
226
227 if ( in_array( $this->field['type'], [ 'pick', 'file' ], true ) ) {
228 $return_type = $this->args[ $this->field['type'] . '_format' ];
229
230 // Force different formats based on return type.
231 if ( 'connection' === $return_type ) {
232 $format = 'raw';
233 } elseif ( 'id' === $return_type ) {
234 $format = 'raw';
235 } elseif ( 'title' === $return_type ) {
236 $format = 'rendered';
237 } elseif ( in_array( $return_type, [ 'view-url', 'asset-url' ], true ) ) {
238 $format = 'raw';
239
240 $field_name .= '.permalink';
241 }
242 }
243
244 // Maybe return the raw field value.
245 if (
246 $this->args['is_multi']
247 || (
248 'String' !== $this->args['graphql_type']
249 && (
250 ! $this->args['is_multi']
251 || 'String' !== $this->args['graphql_type']['list_of']
252 )
253 )
254 ) {
255 $field_params = [
256 'name' => $field_name,
257 'output' => 'ids',
258 ];
259
260 // If this is a multi field and we need to get the rendered format, turn display on.
261 if ( $this->args['is_multi'] && 'rendered' === $format ) {
262 // Handle formatting.
263 $field_params['display'] = true;
264
265 // Format the values individually.
266 $field_params['display_process_individually'] = true;
267 }
268
269 $value = $pod->field( $field_params );
270
271 if ( ! $this->args['is_multi'] && is_array( $value ) ) {
272 // Maybe force a string.
273 $value = implode( ',', $value );
274 } elseif ( $this->args['is_multi'] && ! is_array( $value ) ) {
275 // Maybe force an array.
276 if ( '' === $value || null === $value ) {
277 $value = [];
278 } else {
279 $value = (array) $value;
280 }
281 }
282
283 return $value;
284 }
285
286 // Check if we are need the raw format.
287 if ( 'raw' === $format ) {
288 $field_params = [
289 'name' => $field_name,
290 'output' => 'ids',
291 ];
292
293 // Return the field in the raw context.
294 return $pod->field( $field_params );
295 }
296
297 // Return the field in the normal render context.
298 return $pod->display( $field_name );
299 }
300
301 /**
302 * Register the connections.
303 *
304 * @since 2.9.0
305 */
306 public static function register_connections() {
307 if ( empty( self::$connections ) ) {
308 return;
309 }
310
311 // Register the connections.
312 foreach ( self::$connections as $connection ) {
313 new Connection( $connection );
314 }
315 }
316
317 }
318