@@ -31,18 +31,28 @@ class SaveHandler
3131 private $ linkResource ;
3232
3333 /**
34+ * @var linkTypeProvider
35+ */
36+ private $ linkTypeProvider ;
37+
38+ /**
39+ * SaveHandler constructor.
3440 * @param MetadataPool $metadataPool
3541 * @param Link $linkResource
3642 * @param ProductLinkRepositoryInterface $productLinkRepository
43+ * @param \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider
3744 */
3845 public function __construct (
3946 MetadataPool $ metadataPool ,
4047 Link $ linkResource ,
41- ProductLinkRepositoryInterface $ productLinkRepository
42- ) {
48+ ProductLinkRepositoryInterface $ productLinkRepository ,
49+ \Magento \Catalog \Model \Product \LinkTypeProvider $ linkTypeProvider
50+ )
51+ {
4352 $ this ->metadataPool = $ metadataPool ;
4453 $ this ->linkResource = $ linkResource ;
4554 $ this ->productLinkRepository = $ productLinkRepository ;
55+ $ this ->linkTypeProvider = $ linkTypeProvider ;
4656 }
4757
4858 /**
@@ -55,17 +65,74 @@ public function execute($entityType, $entity)
5565 {
5666 $ link = $ entity ->getData ($ this ->metadataPool ->getMetadata ($ entityType )->getLinkField ());
5767 if ($ this ->linkResource ->hasProductLinks ($ link )) {
58- /** @var \Magento\Catalog\Api\Data\ProductInterface $entity*/
68+ /** @var \Magento\Catalog\Api\Data\ProductInterface $entity */
5969 foreach ($ this ->productLinkRepository ->getList ($ entity ) as $ link ) {
6070 $ this ->productLinkRepository ->delete ($ link );
6171 }
6272 }
6373 $ productLinks = $ entity ->getProductLinks ();
74+
75+ // Build links per type
76+ $ linksByType = [];
77+ foreach ($ productLinks as $ link ) {
78+ $ linksByType [$ link ->getLinkType ()][] = $ link ;
79+ }
80+
81+ // Do check
82+ $ hasPositionLinkType = $ this ->isPositionsSet ($ linksByType );
83+
84+
85+ // Bug fix for API if the Position was not set to force set Position attribute in "catalog_product_link_attribute_int"
86+ // set Positions attribute values
87+ foreach ($ hasPositionLinkType as $ linkType => $ hasPosition ) {
88+ if (!$ hasPosition ) {
89+ array_walk ($ linksByType [$ linkType ], function ($ productLink , $ position ) {
90+ $ productLink ->setPosition (++$ position );
91+ });
92+ }
93+ }
94+
95+ // Flatten multi-dimensional linksByType in ProductLinks
96+ $ productLinks = array_reduce ($ linksByType , 'array_merge ' , []);
97+
6498 if (count ($ productLinks ) > 0 ) {
6599 foreach ($ entity ->getProductLinks () as $ link ) {
66100 $ this ->productLinkRepository ->save ($ link );
67101 }
68102 }
69103 return $ entity ;
70104 }
105+
106+ /**
107+ * Check if the position is set for all product links per link type.
108+ * array with boolean per type
109+ *
110+ * @param $linksByType
111+ * @return array
112+ */
113+ private function isPositionsSet ($ linksByType )
114+ {
115+ $ linkTypes = $ this ->linkTypeProvider ->getLinkTypes ();
116+
117+ // Initialize isPositionSet for existent link types
118+ $ isPositionSet = [];
119+ foreach (array_keys ($ linkTypes ) as $ typeName ) {
120+ if (array_key_exists ($ typeName , $ linksByType )) {
121+ $ isPositionSet [$ typeName ] = count ($ linksByType [$ typeName ]) > 0 ;
122+ }
123+ }
124+
125+
126+ // Check if at least on link without position exists per Link type
127+ foreach ($ linksByType as $ type => $ links ) {
128+ foreach ($ links as $ link ) {
129+ if (!array_key_exists ('position ' , $ link ->getData ())) {
130+ $ isPositionSet [$ type ] = false ;
131+ break ;
132+ }
133+ }
134+ }
135+
136+ return $ isPositionSet ;
137+ }
71138}
0 commit comments