55 */
66namespace Magento \Bundle \Model \Product ;
77
8- use Magento \Catalog \Api \Data \ProductInterface ;
98use Magento \Bundle \Api \ProductOptionRepositoryInterface as OptionRepository ;
109use Magento \Bundle \Api \ProductLinkManagementInterface ;
1110use Magento \Framework \App \ObjectManager ;
@@ -53,50 +52,50 @@ public function __construct(
5352 * @param object $entity
5453 * @param array $arguments
5554 * @return \Magento\Catalog\Api\Data\ProductInterface|object
55+ * @throws \Magento\Framework\Exception\NoSuchEntityException
56+ * @throws \Magento\Framework\Exception\InputException
57+ * @throws \Magento\Framework\Exception\CouldNotSaveException
5658 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
5759 */
5860 public function execute ($ entity , $ arguments = [])
5961 {
6062 /** @var \Magento\Bundle\Api\Data\OptionInterface[] $options */
61- $ options = $ entity ->getExtensionAttributes ()->getBundleProductOptions () ?: [];
63+ $ bundleProductOptions = $ entity ->getExtensionAttributes ()->getBundleProductOptions () ?: [];
6264
63- if ($ entity ->getTypeId () !== ' bundle ' || empty ($ options )) {
65+ if ($ entity ->getTypeId () !== Type:: TYPE_CODE || empty ($ bundleProductOptions )) {
6466 return $ entity ;
6567 }
6668
67- if (!$ entity ->getCopyFromView ()) {
68- $ updatedOptions = [];
69- $ oldOptions = $ this ->optionRepository ->getList ($ entity ->getSku ());
70-
71- $ metadata = $ this ->metadataPool ->getMetadata (ProductInterface::class);
69+ $ existingBundleProductOptions = $ this ->optionRepository ->getList ($ entity ->getSku ());
7270
73- $ productId = $ entity ->getData ($ metadata ->getLinkField ());
71+ $ existingOptionsIds = !empty ($ existingBundleProductOptions )
72+ ? $ this ->getOptionIds ($ existingBundleProductOptions )
73+ : [];
74+ $ optionIds = !empty ($ bundleProductOptions )
75+ ? $ this ->getOptionIds ($ bundleProductOptions )
76+ : [];
7477
75- foreach ($ options as $ option ) {
76- $ updatedOptions [$ option ->getOptionId ()][$ productId ] = (bool )$ option ->getOptionId ();
77- }
78-
79- foreach ($ oldOptions as $ option ) {
80- if (!isset ($ updatedOptions [$ option ->getOptionId ()][$ productId ])) {
81- $ option ->setParentId ($ productId );
82- $ this ->removeOptionLinks ($ entity ->getSku (), $ option );
83- $ this ->optionRepository ->delete ($ option );
84- }
85- }
86- }
78+ $ options = $ bundleProductOptions ?: [];
8779
88- foreach ($ options as $ option ) {
89- $ this ->optionRepository ->save ($ entity , $ option );
80+ if (!$ entity ->getCopyFromView ()) {
81+ $ this ->processRemovedOptions ($ entity ->getSku (), $ existingOptionsIds , $ optionIds );
82+
83+ $ newOptionsIds = array_diff ($ optionIds , $ existingOptionsIds );
84+ $ this ->saveOptions ($ entity , $ options , $ newOptionsIds );
85+ } else {
86+ //save only labels and not selections + product links
87+ $ this ->saveOptions ($ entity , $ options );
88+ $ entity ->setCopyFromView (false );
9089 }
9190
92- $ entity ->setCopyFromView (false );
93-
9491 return $ entity ;
9592 }
9693
9794 /**
9895 * @param string $entitySku
9996 * @param \Magento\Bundle\Api\Data\OptionInterface $option
97+ * @throws \Magento\Framework\Exception\NoSuchEntityException
98+ * @throws \Magento\Framework\Exception\InputException
10099 * @return void
101100 */
102101 protected function removeOptionLinks ($ entitySku , $ option )
@@ -108,4 +107,67 @@ protected function removeOptionLinks($entitySku, $option)
108107 }
109108 }
110109 }
110+
111+ /**
112+ * Perform save for all options entities
113+ *
114+ * @param object $entity
115+ * @param array $options
116+ * @param array $newOptionsIds
117+ * @throws \Magento\Framework\Exception\CouldNotSaveException
118+ * @throws \Magento\Framework\Exception\InputException
119+ * @return void
120+ */
121+ private function saveOptions ($ entity , array $ options , array $ newOptionsIds = [])
122+ {
123+ foreach ($ options as $ option ) {
124+ if (in_array ($ option ->getOptionId (), $ newOptionsIds , true )) {
125+ $ option ->setOptionId (null );
126+ }
127+ $ this ->optionRepository ->save ($ entity , $ option );
128+ }
129+ }
130+
131+ /**
132+ * Get options ids from array of the options entities
133+ *
134+ * @param array $options
135+ * @return array
136+ */
137+ private function getOptionIds (array $ options )
138+ {
139+ $ optionIds = [];
140+
141+ if (empty ($ options )) {
142+ return $ optionIds ;
143+ }
144+
145+ /** @var \Magento\Bundle\Api\Data\OptionInterface $option */
146+ foreach ($ options as $ option ) {
147+ if ($ option ->getOptionId ()) {
148+ $ optionIds [] = $ option ->getOptionId ();
149+ }
150+ }
151+ return $ optionIds ;
152+ }
153+
154+ /**
155+ * Removes old options that no longer exists
156+ *
157+ * @param string $entitySku
158+ * @param array $existingOptionsIds
159+ * @param array $optionIds
160+ * @throws \Magento\Framework\Exception\NoSuchEntityException
161+ * @throws \Magento\Framework\Exception\InputException
162+ * @throws \Magento\Framework\Exception\CouldNotSaveException
163+ * @return void
164+ */
165+ private function processRemovedOptions ($ entitySku , array $ existingOptionsIds , array $ optionIds )
166+ {
167+ foreach (array_diff ($ existingOptionsIds , $ optionIds ) as $ optionId ) {
168+ $ option = $ this ->optionRepository ->get ($ entitySku , $ optionId );
169+ $ this ->removeOptionLinks ($ entitySku , $ option );
170+ $ this ->optionRepository ->delete ($ option );
171+ }
172+ }
111173}
0 commit comments