77
88namespace Magento \Catalog \Model \Product \Option ;
99
10+ use Magento \Catalog \Api \Data \ProductCustomOptionInterface ;
11+ use Magento \Catalog \Api \Data \ProductInterface ;
1012use Magento \Catalog \Api \ProductCustomOptionRepositoryInterface as OptionRepository ;
13+ use Magento \Catalog \Model \Product \Option ;
14+ use Magento \ConfigurableProduct \Model \Product \Type \Configurable ;
15+ use Magento \Framework \App \ObjectManager ;
16+ use Magento \Catalog \Model \Product \Type ;
1117use Magento \Framework \EntityManager \Operation \ExtensionInterface ;
18+ use Magento \Catalog \Model \ResourceModel \Product \Relation ;
19+ use Magento \Framework \Exception \CouldNotSaveException ;
20+ use Magento \GroupedProduct \Model \Product \Type \Grouped ;
1221
1322/**
14- * Class SaveHandler
23+ * SaveHandler for product option
24+ *
25+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1526 */
1627class SaveHandler implements ExtensionInterface
1728{
@@ -20,21 +31,29 @@ class SaveHandler implements ExtensionInterface
2031 */
2132 protected $ optionRepository ;
2233
34+ /**
35+ * @var Relation
36+ */
37+ private $ relation ;
38+
2339 /**
2440 * @param OptionRepository $optionRepository
41+ * @param Relation|null $relation
2542 */
2643 public function __construct (
27- OptionRepository $ optionRepository
44+ OptionRepository $ optionRepository ,
45+ ?Relation $ relation = null
2846 ) {
2947 $ this ->optionRepository = $ optionRepository ;
48+ $ this ->relation = $ relation ?: ObjectManager::getInstance ()->get (Relation::class);
3049 }
3150
3251 /**
3352 * Perform action on relation/extension attribute
3453 *
3554 * @param object $entity
3655 * @param array $arguments
37- * @return \Magento\Catalog\Api\Data\ ProductInterface|object
56+ * @return ProductInterface|object
3857 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
3958 */
4059 public function execute ($ entity , $ arguments = [])
@@ -47,37 +66,66 @@ public function execute($entity, $arguments = [])
4766 $ optionIds = [];
4867
4968 if ($ options ) {
50- $ optionIds = array_map (function ($ option ) {
51- /** @var \Magento\Catalog\Model\Product\Option $option */
69+ $ optionIds = array_map (function (Option $ option ) {
5270 return $ option ->getOptionId ();
5371 }, $ options );
5472 }
5573
56- /** @var \Magento\Catalog\Api\Data\ ProductInterface $entity */
74+ /** @var ProductInterface $entity */
5775 foreach ($ this ->optionRepository ->getProductOptions ($ entity ) as $ option ) {
5876 if (!in_array ($ option ->getOptionId (), $ optionIds )) {
5977 $ this ->optionRepository ->delete ($ option );
6078 }
6179 }
6280 if ($ options ) {
63- $ this ->processOptionsSaving ($ options , (bool )$ entity ->dataHasChangedFor ('sku ' ), ( string ) $ entity-> getSku () );
81+ $ this ->processOptionsSaving ($ options , (bool )$ entity ->dataHasChangedFor ('sku ' ), $ entity );
6482 }
6583
6684 return $ entity ;
6785 }
6886
87+ /**
88+ * Check if product doesn't belong to composite product
89+ *
90+ * @param ProductInterface $product
91+ * @return bool
92+ */
93+ private function isProductValid (ProductInterface $ product ): bool
94+ {
95+ $ result = true ;
96+ if ($ product ->getTypeId () !== Type::TYPE_BUNDLE
97+ && $ product ->getTypeId () !== Configurable::TYPE_CODE
98+ && $ product ->getTypeId () !== Grouped::TYPE_CODE
99+ && $ this ->relation ->getRelationsByChildren ([$ product ->getId ()])
100+ ) {
101+ $ result = false ;
102+ }
103+
104+ return $ result ;
105+ }
106+
69107 /**
70108 * Save custom options
71109 *
72110 * @param array $options
73111 * @param bool $hasChangedSku
74- * @param string $newSku
112+ * @param ProductInterface $product
113+ * @return void
114+ * @throws CouldNotSaveException
75115 */
76- private function processOptionsSaving (array $ options , bool $ hasChangedSku , string $ newSku )
116+ private function processOptionsSaving (array $ options , bool $ hasChangedSku , ProductInterface $ product ): void
77117 {
118+ $ isProductValid = $ this ->isProductValid ($ product );
119+ /** @var ProductCustomOptionInterface $option */
78120 foreach ($ options as $ option ) {
121+ if (!$ isProductValid && $ option ->getIsRequire ()) {
122+ $ message = 'Required custom options cannot be added to a simple product '
123+ . ' that is a part of a composite product. ' ;
124+ throw new CouldNotSaveException (__ ($ message ));
125+ }
126+
79127 if ($ hasChangedSku && $ option ->hasData ('product_sku ' )) {
80- $ option ->setProductSku ($ newSku );
128+ $ option ->setProductSku ($ product -> getSku () );
81129 }
82130 $ this ->optionRepository ->save ($ option );
83131 }
0 commit comments