@@ -84,19 +84,29 @@ public function __construct(
84
84
* Bulk options save
85
85
*
86
86
* @param ProductInterface $bundleProduct
87
- * @param OptionInterface[] $options
87
+ * @param array $options
88
+ * @param array $existingBundleProductOptions
88
89
* @return void
89
90
* @throws CouldNotSaveException
90
- * @throws NoSuchEntityException
91
91
* @throws InputException
92
+ * @throws NoSuchEntityException
92
93
*/
93
- public function saveBulk (ProductInterface $ bundleProduct , array $ options ): void
94
- {
94
+ public function saveBulk (
95
+ ProductInterface $ bundleProduct ,
96
+ array $ options ,
97
+ array $ existingBundleProductOptions = []
98
+ ): void {
95
99
$ metadata = $ this ->metadataPool ->getMetadata (ProductInterface::class);
96
100
$ optionCollection = $ this ->type ->getOptionsCollection ($ bundleProduct );
97
101
98
102
foreach ($ options as $ option ) {
99
- $ this ->saveOptionItem ($ bundleProduct , $ option , $ optionCollection , $ metadata );
103
+ $ this ->saveOptionItem (
104
+ $ bundleProduct ,
105
+ $ option ,
106
+ $ optionCollection ,
107
+ $ metadata ,
108
+ $ existingBundleProductOptions
109
+ );
100
110
}
101
111
102
112
$ bundleProduct ->setIsRelationsChanged (true );
@@ -109,42 +119,42 @@ public function saveBulk(ProductInterface $bundleProduct, array $options): void
109
119
* @param OptionInterface $option
110
120
* @param Collection $optionCollection
111
121
* @param EntityMetadataInterface $metadata
122
+ * @param array $existingBundleProductOptions
112
123
* @return void
113
124
* @throws CouldNotSaveException
114
- * @throws NoSuchEntityException
115
125
* @throws InputException
126
+ * @throws NoSuchEntityException
116
127
*/
117
128
private function saveOptionItem (
118
129
ProductInterface $ bundleProduct ,
119
130
OptionInterface $ option ,
120
131
Collection $ optionCollection ,
121
- EntityMetadataInterface $ metadata
132
+ EntityMetadataInterface $ metadata ,
133
+ array $ existingBundleProductOptions = []
122
134
) : void {
123
135
$ linksToAdd = [];
124
136
125
137
$ option ->setStoreId ($ bundleProduct ->getStoreId ());
126
138
$ parentId = $ bundleProduct ->getData ($ metadata ->getLinkField ());
127
139
$ option ->setParentId ($ parentId );
128
140
$ optionId = $ option ->getOptionId ();
141
+ $ existingOption = $ this ->retrieveExistingOption ($ optionCollection , $ option , $ existingBundleProductOptions );
129
142
130
- /** @var \Magento\Bundle\Model\Option $existingOption */
131
- $ existingOption = $ optionCollection ->getItemById ($ option ->getOptionId ())
132
- ?? $ optionCollection ->getNewEmptyItem ();
133
143
if (!$ optionId || $ existingOption ->getParentId () != $ parentId ) {
134
144
$ option ->setOptionId (null );
135
145
$ option ->setDefaultTitle ($ option ->getTitle ());
136
146
if (is_array ($ option ->getProductLinks ())) {
137
147
$ linksToAdd = $ option ->getProductLinks ();
138
148
}
139
149
} else {
140
- if (!$ existingOption ->getOptionId ()) {
150
+ if (!$ existingOption || ! $ existingOption ->getOptionId ()) {
141
151
throw new NoSuchEntityException (
142
152
__ ("The option that was requested doesn't exist. Verify the entity and try again. " )
143
153
);
144
154
}
145
155
146
156
$ option ->setData (array_merge ($ existingOption ->getData (), $ option ->getData ()));
147
- $ this ->updateOptionSelection ($ bundleProduct , $ option );
157
+ $ this ->updateOptionSelection ($ bundleProduct , $ option, $ existingOption );
148
158
}
149
159
150
160
try {
@@ -183,15 +193,21 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option)
183
193
*
184
194
* @param ProductInterface $product
185
195
* @param OptionInterface $option
196
+ * @param OptionInterface|null $existingOption
186
197
* @return void
198
+ * @throws CouldNotSaveException
199
+ * @throws InputException
200
+ * @throws NoSuchEntityException
187
201
*/
188
- private function updateOptionSelection (ProductInterface $ product , OptionInterface $ option )
189
- {
190
- $ optionId = $ option ->getOptionId ();
191
- $ existingLinks = $ this ->linkManagement ->getChildren ($ product ->getSku (), $ optionId );
202
+ private function updateOptionSelection (
203
+ ProductInterface $ product ,
204
+ OptionInterface $ option ,
205
+ ?OptionInterface $ existingOption = null
206
+ ):void {
192
207
$ linksToAdd = [];
193
208
$ linksToUpdate = [];
194
209
$ linksToDelete = [];
210
+
195
211
if (is_array ($ option ->getProductLinks ())) {
196
212
$ productLinks = $ option ->getProductLinks ();
197
213
foreach ($ productLinks as $ productLink ) {
@@ -201,20 +217,24 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac
201
217
$ linksToUpdate [] = $ productLink ;
202
218
}
203
219
}
204
- /** @var LinkInterface[] $linksToDelete */
205
- $ linksToDelete = $ this ->compareLinks ($ existingLinks , $ linksToUpdate );
206
- $ linksToUpdate = $ this ->verifyLinksToUpdate ($ existingLinks , $ linksToUpdate );
220
+ if (!empty ($ existingOption ) && !empty ($ existingOption ->getProductLinks ())) {
221
+ $ linksToDelete = $ this ->compareLinks ($ existingOption ->getProductLinks (), $ linksToUpdate );
222
+ $ linksToUpdate = $ this ->verifyLinksToUpdate ($ existingOption ->getProductLinks (), $ linksToUpdate );
223
+ }
207
224
}
225
+
208
226
foreach ($ linksToUpdate as $ linkedProduct ) {
209
227
$ this ->linkManagement ->saveChild ($ product ->getSku (), $ linkedProduct );
210
228
}
229
+
211
230
foreach ($ linksToDelete as $ linkedProduct ) {
212
231
$ this ->linkManagement ->removeChild (
213
232
$ product ->getSku (),
214
233
$ option ->getOptionId (),
215
234
$ linkedProduct ->getSku ()
216
235
);
217
236
}
237
+
218
238
$ this ->addChildren ->addChildren ($ product , (int )$ option ->getOptionId (), $ linksToAdd );
219
239
}
220
240
@@ -300,4 +320,42 @@ private function compareLinks(array $firstArray, array $secondArray)
300
320
301
321
return $ result ;
302
322
}
323
+
324
+ /**
325
+ * Retrieve option from list.
326
+ *
327
+ * @param Collection $optionCollection
328
+ * @param OptionInterface $option
329
+ * @param array $existingBundleProductOptions
330
+ * @return OptionInterface
331
+ */
332
+ private function retrieveExistingOption (
333
+ Collection $ optionCollection ,
334
+ OptionInterface $ option ,
335
+ array $ existingBundleProductOptions
336
+ ): OptionInterface {
337
+ $ existingOption = $ optionCollection ->getItemById ($ option ->getOptionId ());
338
+
339
+ $ incomingOption = current (
340
+ array_filter ($ existingBundleProductOptions , function ($ obj ) use ($ option ) {
341
+ return $ obj ->getData ()['option_id ' ] == $ option ->getId ();
342
+ })
343
+ );
344
+
345
+ if (!empty ($ incomingOption )) {
346
+ $ existingOption ->setData (
347
+ array_merge (
348
+ $ existingOption ->getData (),
349
+ $ incomingOption ->getData ()
350
+ )
351
+ );
352
+ }
353
+
354
+ // @phpstan-ignore-next-line
355
+ if (empty ($ existingOption )) {
356
+ $ existingOption = $ optionCollection ->getNewEmptyItem ();
357
+ }
358
+
359
+ return $ existingOption ;
360
+ }
303
361
}
0 commit comments