7
7
8
8
namespace Magento \Bundle \Model \Option ;
9
9
10
+ use Exception ;
10
11
use Magento \Bundle \Api \Data \LinkInterface ;
11
12
use Magento \Bundle \Api \Data \OptionInterface ;
13
+ use Magento \Bundle \Api \ProductLinkManagementInterface ;
14
+ use Magento \Bundle \Model \Product \Type ;
12
15
use Magento \Bundle \Model \ResourceModel \Option ;
16
+ use Magento \Bundle \Model \ResourceModel \Option \Collection ;
13
17
use Magento \Catalog \Api \Data \ProductInterface ;
14
- use Magento \Framework \App \ ObjectManager ;
18
+ use Magento \Framework \EntityManager \ EntityMetadataInterface ;
15
19
use Magento \Framework \EntityManager \MetadataPool ;
16
20
use Magento \Framework \Exception \CouldNotSaveException ;
17
- use Magento \Bundle \Model \Product \Type ;
18
- use Magento \Bundle \Api \ProductLinkManagementInterface ;
21
+ use Magento \Framework \Exception \InputException ;
19
22
use Magento \Framework \Exception \NoSuchEntityException ;
20
23
use Magento \Store \Model \StoreManagerInterface ;
21
24
22
25
/**
23
26
* Encapsulates logic for saving a bundle option, including coalescing the parent product's data.
27
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
24
28
*/
25
29
class SaveAction
26
30
{
@@ -66,32 +70,56 @@ public function __construct(
66
70
}
67
71
68
72
/**
69
- * Manage the logic of saving a bundle option, including the coalescence of its parent product data.
73
+ * Bulk options save
70
74
*
71
75
* @param ProductInterface $bundleProduct
72
- * @param OptionInterface $option
73
- * @return OptionInterface
76
+ * @param OptionInterface[] $options
77
+ * @return void
74
78
* @throws CouldNotSaveException
75
- * @throws \Exception
79
+ * @throws NoSuchEntityException
80
+ * @throws InputException
76
81
*/
77
- public function save (ProductInterface $ bundleProduct , OptionInterface $ option )
82
+ public function saveBulk (ProductInterface $ bundleProduct , array $ options ): void
78
83
{
79
84
$ metadata = $ this ->metadataPool ->getMetadata (ProductInterface::class);
85
+ $ optionCollection = $ this ->type ->getOptionsCollection ($ bundleProduct );
86
+
87
+ foreach ($ options as $ option ) {
88
+ $ this ->saveOptionItem ($ bundleProduct , $ option , $ optionCollection , $ metadata );
89
+ }
90
+
91
+ $ bundleProduct ->setIsRelationsChanged (true );
92
+ }
93
+
94
+ /**
95
+ * Process option save
96
+ *
97
+ * @param ProductInterface $bundleProduct
98
+ * @param OptionInterface $option
99
+ * @param Collection $optionCollection
100
+ * @param EntityMetadataInterface $metadata
101
+ * @return void
102
+ * @throws CouldNotSaveException
103
+ * @throws NoSuchEntityException
104
+ * @throws InputException
105
+ */
106
+ private function saveOptionItem (
107
+ ProductInterface $ bundleProduct ,
108
+ OptionInterface $ option ,
109
+ Collection $ optionCollection ,
110
+ EntityMetadataInterface $ metadata
111
+ ) : void {
112
+ $ linksToAdd = [];
80
113
81
114
$ option ->setStoreId ($ bundleProduct ->getStoreId ());
82
115
$ parentId = $ bundleProduct ->getData ($ metadata ->getLinkField ());
83
116
$ option ->setParentId ($ parentId );
84
-
85
117
$ optionId = $ option ->getOptionId ();
86
- $ linksToAdd = [];
87
- $ optionCollection = $ this ->type ->getOptionsCollection ($ bundleProduct );
88
118
89
119
/** @var \Magento\Bundle\Model\Option $existingOption */
90
120
$ existingOption = $ optionCollection ->getItemById ($ option ->getOptionId ())
91
121
?? $ optionCollection ->getNewEmptyItem ();
92
122
if (!$ optionId || $ existingOption ->getParentId () != $ parentId ) {
93
- //If option ID is empty or existing option's parent ID is different
94
- //we'd need a new ID for the option.
95
123
$ option ->setOptionId (null );
96
124
$ option ->setDefaultTitle ($ option ->getTitle ());
97
125
if (is_array ($ option ->getProductLinks ())) {
@@ -110,7 +138,7 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option)
110
138
111
139
try {
112
140
$ this ->optionResource ->save ($ option );
113
- } catch (\ Exception $ e ) {
141
+ } catch (Exception $ e ) {
114
142
throw new CouldNotSaveException (__ ("The option couldn't be saved. " ), $ e );
115
143
}
116
144
@@ -120,7 +148,21 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option)
120
148
}
121
149
}
122
150
123
- $ bundleProduct ->setIsRelationsChanged(true );
151
+ /**
152
+ * Manage the logic of saving a bundle option, including the coalescence of its parent product data.
153
+ *
154
+ * @param ProductInterface $bundleProduct
155
+ * @param OptionInterface $option
156
+ * @return OptionInterface
157
+ * @throws CouldNotSaveException
158
+ * @throws Exception
159
+ */
160
+ public function save (ProductInterface $ bundleProduct , OptionInterface $ option )
161
+ {
162
+ $ metadata = $ this ->metadataPool ->getMetadata (ProductInterface::class);
163
+ $ optionCollection = $ this ->type ->getOptionsCollection ($ bundleProduct );
164
+
165
+ $ this ->saveOptionItem ($ bundleProduct , $ option , $ optionCollection , $ metadata );
124
166
125
167
return $ option ;
126
168
}
@@ -167,6 +209,55 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac
167
209
}
168
210
}
169
211
212
+ /**
213
+ * Verify that updated data actually changed
214
+ *
215
+ * @param LinkInterface[] $existing
216
+ * @param LinkInterface[] $updates
217
+ * @return array
218
+ */
219
+ private function verifyLinksToUpdate (array $ existing , array $ updates ) : array
220
+ {
221
+ $ linksToUpdate = [];
222
+ $ beforeLinksMap = [];
223
+
224
+ foreach ($ existing as $ beforeLink ) {
225
+ $ beforeLinksMap [$ beforeLink ->getId ()] = $ beforeLink ;
226
+ }
227
+
228
+ foreach ($ updates as $ updatedLink ) {
229
+ if (array_key_exists ($ updatedLink ->getId (), $ beforeLinksMap )) {
230
+ $ beforeLink = $ beforeLinksMap [$ updatedLink ->getId ()];
231
+ if ($ this ->isLinkChanged ($ beforeLink , $ updatedLink )) {
232
+ $ linksToUpdate [] = $ updatedLink ;
233
+ }
234
+ } else {
235
+ $ linksToUpdate [] = $ updatedLink ;
236
+ }
237
+ }
238
+ return $ linksToUpdate ;
239
+ }
240
+
241
+ /**
242
+ * Check is updated link actually updated
243
+ *
244
+ * @param LinkInterface $beforeLink
245
+ * @param LinkInterface $updatedLink
246
+ * @return bool
247
+ */
248
+ private function isLinkChanged (LinkInterface $ beforeLink , LinkInterface $ updatedLink ) : bool
249
+ {
250
+ return (int )$ beforeLink ->getOptionId () !== (int )$ updatedLink ->getOptionId ()
251
+ || $ beforeLink ->getIsDefault () !== $ updatedLink ->getIsDefault ()
252
+ || (float )$ beforeLink ->getQty () !== (float )$ updatedLink ->getQty ()
253
+ || $ beforeLink ->getPrice () !== $ updatedLink ->getPrice ()
254
+ || $ beforeLink ->getCanChangeQuantity () !== $ updatedLink ->getCanChangeQuantity ()
255
+ || (array )$ beforeLink ->getExtensionAttributes () !== (array )$ updatedLink ->getExtensionAttributes ()
256
+ || (int )$ beforeLink ->getPosition () !== (int )$ updatedLink ->getPosition ()
257
+ || $ beforeLink ->getSku () !== $ updatedLink ->getSku ()
258
+ || $ beforeLink ->getPriceType () !== $ updatedLink ->getPriceType ();
259
+ }
260
+
170
261
/**
171
262
* Compute the difference between given arrays.
172
263
*
0 commit comments