@@ -84,19 +84,29 @@ public function __construct(
8484 * Bulk options save
8585 *
8686 * @param ProductInterface $bundleProduct
87- * @param OptionInterface[] $options
87+ * @param array $options
88+ * @param array $existingBundleProductOptions
8889 * @return void
8990 * @throws CouldNotSaveException
90- * @throws NoSuchEntityException
9191 * @throws InputException
92+ * @throws NoSuchEntityException
9293 */
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 {
9599 $ metadata = $ this ->metadataPool ->getMetadata (ProductInterface::class);
96100 $ optionCollection = $ this ->type ->getOptionsCollection ($ bundleProduct );
97101
98102 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+ );
100110 }
101111
102112 $ bundleProduct ->setIsRelationsChanged (true );
@@ -109,42 +119,42 @@ public function saveBulk(ProductInterface $bundleProduct, array $options): void
109119 * @param OptionInterface $option
110120 * @param Collection $optionCollection
111121 * @param EntityMetadataInterface $metadata
122+ * @param array $existingBundleProductOptions
112123 * @return void
113124 * @throws CouldNotSaveException
114- * @throws NoSuchEntityException
115125 * @throws InputException
126+ * @throws NoSuchEntityException
116127 */
117128 private function saveOptionItem (
118129 ProductInterface $ bundleProduct ,
119130 OptionInterface $ option ,
120131 Collection $ optionCollection ,
121- EntityMetadataInterface $ metadata
132+ EntityMetadataInterface $ metadata ,
133+ array $ existingBundleProductOptions = []
122134 ) : void {
123135 $ linksToAdd = [];
124136
125137 $ option ->setStoreId ($ bundleProduct ->getStoreId ());
126138 $ parentId = $ bundleProduct ->getData ($ metadata ->getLinkField ());
127139 $ option ->setParentId ($ parentId );
128140 $ optionId = $ option ->getOptionId ();
141+ $ existingOption = $ this ->retrieveExistingOption ($ optionCollection , $ option , $ existingBundleProductOptions );
129142
130- /** @var \Magento\Bundle\Model\Option $existingOption */
131- $ existingOption = $ optionCollection ->getItemById ($ option ->getOptionId ())
132- ?? $ optionCollection ->getNewEmptyItem ();
133143 if (!$ optionId || $ existingOption ->getParentId () != $ parentId ) {
134144 $ option ->setOptionId (null );
135145 $ option ->setDefaultTitle ($ option ->getTitle ());
136146 if (is_array ($ option ->getProductLinks ())) {
137147 $ linksToAdd = $ option ->getProductLinks ();
138148 }
139149 } else {
140- if (!$ existingOption ->getOptionId ()) {
150+ if (!$ existingOption || ! $ existingOption ->getOptionId ()) {
141151 throw new NoSuchEntityException (
142152 __ ("The option that was requested doesn't exist. Verify the entity and try again. " )
143153 );
144154 }
145155
146156 $ option ->setData (array_merge ($ existingOption ->getData (), $ option ->getData ()));
147- $ this ->updateOptionSelection ($ bundleProduct , $ option );
157+ $ this ->updateOptionSelection ($ bundleProduct , $ option, $ existingOption );
148158 }
149159
150160 try {
@@ -183,15 +193,21 @@ public function save(ProductInterface $bundleProduct, OptionInterface $option)
183193 *
184194 * @param ProductInterface $product
185195 * @param OptionInterface $option
196+ * @param OptionInterface|null $existingOption
186197 * @return void
198+ * @throws CouldNotSaveException
199+ * @throws InputException
200+ * @throws NoSuchEntityException
187201 */
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 {
192207 $ linksToAdd = [];
193208 $ linksToUpdate = [];
194209 $ linksToDelete = [];
210+
195211 if (is_array ($ option ->getProductLinks ())) {
196212 $ productLinks = $ option ->getProductLinks ();
197213 foreach ($ productLinks as $ productLink ) {
@@ -201,20 +217,24 @@ private function updateOptionSelection(ProductInterface $product, OptionInterfac
201217 $ linksToUpdate [] = $ productLink ;
202218 }
203219 }
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+ }
207224 }
225+
208226 foreach ($ linksToUpdate as $ linkedProduct ) {
209227 $ this ->linkManagement ->saveChild ($ product ->getSku (), $ linkedProduct );
210228 }
229+
211230 foreach ($ linksToDelete as $ linkedProduct ) {
212231 $ this ->linkManagement ->removeChild (
213232 $ product ->getSku (),
214233 $ option ->getOptionId (),
215234 $ linkedProduct ->getSku ()
216235 );
217236 }
237+
218238 $ this ->addChildren ->addChildren ($ product , (int )$ option ->getOptionId (), $ linksToAdd );
219239 }
220240
@@ -300,4 +320,42 @@ private function compareLinks(array $firstArray, array $secondArray)
300320
301321 return $ result ;
302322 }
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+ }
303361}
0 commit comments