Passed
Push — master ( aa41b1...2b3c87 )
by Mike
04:52
created

ProductVariationRequest   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 103
dl 0
loc 189
rs 9.84
c 0
b 0
f 0
wmc 32

4 Methods

Rating   Name   Duplication   Size   Complexity  
B parse_image_field() 0 40 10
A prepare_object() 0 18 3
C parse_attributes_field() 0 43 12
B set_common_props() 0 54 7
1
<?php
2
/**
3
 * Convert data in the product schema format to a product object.
4
 *
5
 * @package WooCommerce/RestApi
6
 */
7
8
namespace WooCommerce\RestApi\Controllers\Version4\Schema;
9
10
defined( 'ABSPATH' ) || exit;
11
12
/**
13
 * ProductVariationRequest class.
14
 */
15
class ProductVariationRequest extends ProductRequest {
16
17
	/**
18
	 * Convert request to object.
19
	 *
20
	 * @throws \WC_REST_Exception Will throw an exception if the resulting product object is invalid.
21
	 * @return \WC_Product_Variation
22
	 */
23
	public function prepare_object() {
24
		$id     = (int) $this->get_param( 'id', 0 );
25
		$object = new \WC_Product_Variation( $id );
26
		$object->set_parent_id( (int) $this->get_param( 'product_id', 0 ) );
27
		$parent = wc_get_product( $object->get_parent_id() );
28
29
		if ( ! $parent ) {
0 ignored issues
show
introduced by
$parent is of type WC_Product, thus it always evaluated to true.
Loading history...
30
			throw new \WC_REST_Exception( 'woocommerce_rest_product_variation_invalid_parent', __( 'Invalid parent product.', 'woocommerce' ), 404 );
31
		}
32
33
		$this->set_common_props( $object );
34
		$this->set_meta_data( $object );
35
36
		if ( $object->get_downloadable() ) {
37
			$this->set_downloadable_props( $object );
38
		}
39
40
		return $object;
41
	}
42
43
	/**
44
	 * Set common product props.
45
	 *
46
	 * @param \WC_Product_Variation $object Product object reference.
47
	 */
48
	protected function set_common_props( &$object ) {
49
		$props = [
50
			'status',
51
			'sku',
52
			'virtual',
53
			'downloadable',
54
			'download_limit',
55
			'download_expiry',
56
			'manage_stock',
57
			'stock_status',
58
			'backorders',
59
			'regular_price',
60
			'sale_price',
61
			'date_on_sale_from',
62
			'date_on_sale_from_gmt',
63
			'date_on_sale_to',
64
			'date_on_sale_to_gmt',
65
			'tax_class',
66
			'description',
67
			'menu_order',
68
			'stock_quantity',
69
			'image',
70
			'downloads',
71
			'attributes',
72
			'weight',
73
			'dimensions',
74
			'shipping_class',
75
		];
76
77
		$request_props = array_intersect_key( $this->request, array_flip( $props ) );
78
		$prop_values   = [];
79
80
		foreach ( $request_props as $prop => $value ) {
81
			switch ( $prop ) {
82
				case 'image':
83
					$prop_values['image_id'] = $this->parse_image_field( $value, $object );
84
					break;
85
				case 'attributes':
86
					$prop_values['attributes'] = $this->parse_attributes_field( $value, $object );
87
					break;
88
				case 'dimensions':
89
					$dimensions  = $this->parse_dimensions_fields( $value );
90
					$prop_values = array_merge( $prop_values, $dimensions );
91
					break;
92
				case 'shipping_class':
93
					$prop_values['shipping_class_id'] = $this->parse_shipping_class( $value, $object );
94
					break;
95
				default:
96
					$prop_values[ $prop ] = $value;
97
			}
98
		}
99
100
		foreach ( $prop_values as $prop => $value ) {
101
			$object->{"set_$prop"}( $value );
102
		}
103
	}
104
105
	/**
106
	 * Set product object's attributes.
107
	 *
108
	 * @param array                 $raw_attributes Attribute data from request.
109
	 * @param \WC_Product_Variation $object Product object.
110
	 */
111
	protected function parse_attributes_field( $raw_attributes, $object = null ) {
112
		$attributes        = array();
113
		$parent            = wc_get_product( $object->get_parent_id() );
0 ignored issues
show
Bug introduced by
The method get_parent_id() does not exist on null. ( Ignorable by Annotation )

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

113
		$parent            = wc_get_product( $object->/** @scrutinizer ignore-call */ get_parent_id() );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
114
		$parent_attributes = $parent->get_attributes();
115
116
		foreach ( $raw_attributes as $attribute ) {
117
			$attribute_id   = 0;
118
			$attribute_name = '';
119
120
			// Check ID for global attributes or name for product attributes.
121
			if ( ! empty( $attribute['id'] ) ) {
122
				$attribute_id   = absint( $attribute['id'] );
123
				$attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
124
			} elseif ( ! empty( $attribute['name'] ) ) {
125
				$attribute_name = sanitize_title( $attribute['name'] );
126
			}
127
128
			if ( ! $attribute_id && ! $attribute_name ) {
129
				continue;
130
			}
131
132
			if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) {
133
				continue;
134
			}
135
136
			$attribute_key   = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() );
137
			$attribute_value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : '';
138
139
			if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) {
140
				// If dealing with a taxonomy, we need to get the slug from the name posted to the API.
141
				$term = get_term_by( 'name', $attribute_value, $attribute_name );
142
143
				if ( $term && ! is_wp_error( $term ) ) {
144
					$attribute_value = $term->slug;
145
				} else {
146
					$attribute_value = sanitize_title( $attribute_value );
147
				}
148
			}
149
150
			$attributes[ $attribute_key ] = $attribute_value;
151
		}
152
153
		return $attributes;
154
	}
155
156
	/**
157
	 * Set product images.
158
	 *
159
	 * @throws \WC_REST_Exception REST API exceptions.
160
	 * @param array                 $image  Image data.
161
	 * @param \WC_Product_Variation $object Product object.
162
	 * @return array
163
	 */
164
	protected function parse_image_field( $image, $object ) {
165
		if ( empty( $image ) ) {
166
			return '';
167
		}
168
169
		$attachment_id = isset( $image['id'] ) ? absint( $image['id'] ) : 0;
170
171
		if ( 0 === $attachment_id && isset( $image['src'] ) ) {
172
			$upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) );
173
174
			if ( is_wp_error( $upload ) ) {
175
				if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $object->get_id(), array( $image ) ) ) {
176
					throw new \WC_REST_Exception( 'woocommerce_variation_image_upload_error', $upload->get_error_message(), 400 );
177
				}
178
			}
179
180
			$attachment_id = wc_rest_set_uploaded_image_as_attachment( $upload, $object->get_id() );
0 ignored issues
show
Bug introduced by
It seems like $upload can also be of type WP_Error; however, parameter $upload of wc_rest_set_uploaded_image_as_attachment() does only seem to accept array, 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

180
			$attachment_id = wc_rest_set_uploaded_image_as_attachment( /** @scrutinizer ignore-type */ $upload, $object->get_id() );
Loading history...
181
		}
182
183
		if ( ! wp_attachment_is_image( $attachment_id ) ) {
184
			/* translators: %s: attachment ID */
185
			throw new \WC_REST_Exception( 'woocommerce_variation_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce' ), $attachment_id ), 400 );
186
		}
187
188
		// Set the image alt if present.
189
		if ( ! empty( $image['alt'] ) ) {
190
			update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) );
191
		}
192
193
		// Set the image name if present.
194
		if ( ! empty( $image['name'] ) ) {
195
			wp_update_post(
196
				array(
197
					'ID'         => $attachment_id,
198
					'post_title' => $image['name'],
199
				)
200
			);
201
		}
202
203
		return $attachment_id;
204
	}
205
}
206