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 \Framework \App \ObjectManager ;
1115use Magento \Framework \EntityManager \Operation \ExtensionInterface ;
16+ use Magento \Catalog \Model \ResourceModel \Product \Relation ;
17+ use Magento \Framework \Exception \CouldNotSaveException ;
1218
1319/**
14- * Class SaveHandler
20+ * SaveHandler for product option
21+ *
22+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1523 */
1624class SaveHandler implements ExtensionInterface
1725{
26+ /**
27+ * @var string[]
28+ */
29+ private $ compositeProductTypes = ['grouped ' , 'configurable ' , 'bundle ' ];
30+
1831 /**
1932 * @var OptionRepository
2033 */
2134 protected $ optionRepository ;
2235
36+ /**
37+ * @var Relation
38+ */
39+ private $ relation ;
40+
2341 /**
2442 * @param OptionRepository $optionRepository
43+ * @param Relation|null $relation
2544 */
2645 public function __construct (
27- OptionRepository $ optionRepository
46+ OptionRepository $ optionRepository ,
47+ ?Relation $ relation = null
2848 ) {
2949 $ this ->optionRepository = $ optionRepository ;
50+ $ this ->relation = $ relation ?: ObjectManager::getInstance ()->get (Relation::class);
3051 }
3152
3253 /**
3354 * Perform action on relation/extension attribute
3455 *
3556 * @param object $entity
3657 * @param array $arguments
37- * @return \Magento\Catalog\Api\Data\ ProductInterface|object
58+ * @return ProductInterface|object
3859 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
3960 */
4061 public function execute ($ entity , $ arguments = [])
@@ -47,20 +68,19 @@ public function execute($entity, $arguments = [])
4768 $ optionIds = [];
4869
4970 if ($ options ) {
50- $ optionIds = array_map (function ($ option ) {
51- /** @var \Magento\Catalog\Model\Product\Option $option */
71+ $ optionIds = array_map (function (Option $ option ) {
5272 return $ option ->getOptionId ();
5373 }, $ options );
5474 }
5575
56- /** @var \Magento\Catalog\Api\Data\ ProductInterface $entity */
76+ /** @var ProductInterface $entity */
5777 foreach ($ this ->optionRepository ->getProductOptions ($ entity ) as $ option ) {
5878 if (!in_array ($ option ->getOptionId (), $ optionIds )) {
5979 $ this ->optionRepository ->delete ($ option );
6080 }
6181 }
6282 if ($ options ) {
63- $ this ->processOptionsSaving ($ options , (bool )$ entity ->dataHasChangedFor ('sku ' ), ( string ) $ entity-> getSku () );
83+ $ this ->processOptionsSaving ($ options , (bool )$ entity ->dataHasChangedFor ('sku ' ), $ entity );
6484 }
6585
6686 return $ entity ;
@@ -71,15 +91,43 @@ public function execute($entity, $arguments = [])
7191 *
7292 * @param array $options
7393 * @param bool $hasChangedSku
74- * @param string $newSku
94+ * @param ProductInterface $product
95+ * @return void
96+ * @throws CouldNotSaveException
7597 */
76- private function processOptionsSaving (array $ options , bool $ hasChangedSku , string $ newSku )
98+ private function processOptionsSaving (array $ options , bool $ hasChangedSku , ProductInterface $ product ): void
7799 {
100+ $ isProductHasRelations = $ this ->isProductHasRelations ($ product );
101+ /** @var ProductCustomOptionInterface $option */
78102 foreach ($ options as $ option ) {
103+ if (!$ isProductHasRelations && $ option ->getIsRequire ()) {
104+ $ message = 'Required custom options cannot be added to a simple product '
105+ . ' that is a part of a composite product. ' ;
106+ throw new CouldNotSaveException (__ ($ message ));
107+ }
108+
79109 if ($ hasChangedSku && $ option ->hasData ('product_sku ' )) {
80- $ option ->setProductSku ($ newSku );
110+ $ option ->setProductSku ($ product -> getSku () );
81111 }
82112 $ this ->optionRepository ->save ($ option );
83113 }
84114 }
115+
116+ /**
117+ * Check if product doesn't belong to composite product
118+ *
119+ * @param ProductInterface $product
120+ * @return bool
121+ */
122+ private function isProductHasRelations (ProductInterface $ product ): bool
123+ {
124+ $ result = true ;
125+ if (!in_array ($ product ->getId (), $ this ->compositeProductTypes )
126+ && $ this ->relation ->getRelationsByChildren ([$ product ->getId ()])
127+ ) {
128+ $ result = false ;
129+ }
130+
131+ return $ result ;
132+ }
85133}
0 commit comments