Prestashop Update product via webservice with reference connection
<p>I have two shops that should have the same product informations, i’m creating a module that synchronize products in one direction via webservice ; when i update a product in a shop, that should update the same product (with the same reference) in the other shop. 
In the 2 shops, products haven't always the same IDs.
My problem is when i’m making connection by reference i get error ‘id is required when modifying a resource’, and the update finish successfully when i’m making connection by product id</p>

<p>This is my method code:</p>

<pre><code>public function hookActionObjectProductUpdateAfter($params){

define('DEBUG', true);
define('PS_SHOP_PATH', Configuration::get('PS_SHOP_PATH'));
define('PS_WS_AUTH_KEY', Configuration::get('PS_WS_AUTH_KEY'));

// First : We always get the products's list or a specific one
try
{
        $webService = new PrestaShopWebservice(PS_SHOP_PATH, PS_WS_AUTH_KEY, DEBUG);
        $opt = array('resource' =&gt; 'products');
        //var_dump($params['object']-&gt;id);
        if (isset($params['object']-&gt;id)){
          // $opt['id'] = $params['object']-&gt;id;
            $opt['display']  = 'full'; 
            $opt['filter']['reference'] = '['.$params['object']-&gt;reference.']';

            $xml = $webService-&gt;get($opt);
            $x = ($xml-&gt;products[0]-&gt;product-&gt;id);
            $this-&gt;id_product = (int)$x;
            //var_dump($x);
        }

        // Here we get the elements from children of customer markup which is children of prestashop root markup
        $resources = $xml-&gt;children()-&gt;children();

        //$id_product = $resources-&gt;id;
        //unset($resources-&gt;id);
        var_dump($resources-&gt;associations);
        //unset($resources-&gt;product-&gt;associations);

        unset($resources-&gt;manufacturer_name);
        unset($resources-&gt;quantity);
        unset($resources-&gt;id_shop_default);
        unset($resources-&gt;id_default_image);
        unset($resources-&gt;associations);
        unset($resources-&gt;id_default_combination);
        unset($resources-&gt;position_in_category);
        unset($resources-&gt;type);
        unset($resources-&gt;pack_stock_type);
        unset($resources-&gt;date_add);
        unset($resources-&gt;date_upd); 
        var_dump($resources);
}
catch (PrestaShopWebserviceException $e)
{
        // Here we are dealing with errors
        $trace = $e-&gt;getTrace();
        if ($trace[0]['args'][0] == 404) echo 'Bad ID';
        else if ($trace[0]['args'][0] == 401) echo 'Bad auth key';
        else echo 'Other error&lt;br /&gt;'.$e-&gt;getMessage();
}
// Second : We update the data and send it to the web service
if ($params['object']-&gt;id) // Here we check id cause in every resource there's an id
{
        //print_r($params['product']-&gt;categories);exit;
        // get product categories
        $product = $params['object'];
        $categories = $product-&gt;getCategories();
        //var_dump($categories);

        $id_lang = Context::getContext()-&gt;language-&gt;id;
        $resources-&gt;product-&gt;associations-&gt;categories= '';
        foreach($categories as $catId){
          $categorie = new Category((int)$catId);
          $catName = $categorie-&gt;name[$id_lang];
          //var_dump($categorie-&gt;name);
          //get categorie id in remote shop
          $opt = array();
          $opt['resource'] = 'categories';
            // We set an id if we want to retrieve infos from a customer


          $webService = new PrestaShopWebservice(PS_SHOP_PATH, PS_WS_AUTH_KEY, DEBUG);
          if(isset($catId) &amp;&amp; $catName){
            $opt['filter[name]'] = '['.$catName.']' ; // cast string =&gt; int for security measures
            $opt['display']     = '[id]'; 
            // Call

            $xml1 = $webService-&gt;get($opt);
            $resources1 = $xml1-&gt;children()-&gt;children();
            //var_dump($resources1[0]);
            if($resources1-&gt;category-&gt;id[0]!=''){
                $x = $resources-&gt;product-&gt;associations-&gt;categories-&gt;addChild('categorie');
                $x-&gt;addChild('id', $resources1[0]-&gt;id);
            }else{
                $xml3 = $webService-&gt;get(array('url' =&gt; PS_SHOP_PATH.'/api/categories?schema=blank'));
                $resources3 = $xml3-&gt;children()-&gt;children();
                unset($resources3-&gt;id);
                unset($resources3-&gt;position);
                unset($resources3-&gt;date_add);
                unset($resources3-&gt;date_upd);
                //unset($resources -&gt;id_parent); //if unset category will be root. If set it must have id existing parent category!
                unset($resources3-&gt;level_depth);
                unset($resources3-&gt;nb_products_recursive);
                $resources3 -&gt;id_parent = '2';
                $resources3-&gt;name-&gt;language[0][0] = $catName;
                $resources3-&gt;link_rewrite-&gt;language[0][0] = Tools::link_rewrite($catName);
                $resources3-&gt;active = 1;
                $resources3-&gt;id_shop_default = 1;
                $resources3-&gt;is_root_category = 0;

                $opt = array('resource' =&gt; 'categories');

                $opt['postXml'] = $xml3 -&gt; asXML();

                $xml4 = $webService -&gt; add($opt);

                $resources1 = $xml4-&gt;children()-&gt;children();
                //var_dump($resources1);
                // Clean this object
                $x = $resources-&gt;associations-&gt;categories-&gt;addChild('categorie');
                $x-&gt;addChild('id', $resources1-&gt;id);

                }
            }


        }
        //update manufacturer
        //get id_manufacturer for current product
       $id_manufacturer = $params['object']-&gt;id_manufacturer;
        if($id_manufacturer and $id_manufacturer!=0){

        $manufacturer_name = Manufacturer::getNameById((int)$id_manufacturer);
        //var_dump($manufacturer_name);
        //get remote manufacturer name
        $opt = array();
        $opt['resource'] = 'manufacturers';
        $opt['filter[name]'] = '['.$manufacturer_name.']' ; // cast string =&gt; int for security measures
        $opt['display']     = '[id]'; 
            // Call
        $xml2 = $webService-&gt;get($opt);
        $resources2 = $xml2-&gt;children()-&gt;children();
        if($resources2-&gt;manufacturers-&gt;manufacturer[0]-&gt;id)
            $resources-&gt;product-&gt;id_manufacturer = $resources2-&gt;manufacturers-&gt;manufacturer[0]-&gt;id;
            else {
                //create the manufacturer

                    $xml6 = $webService-&gt;get(array('resource' =&gt; 'manufacturers?schema=synopsis'));
                    $resources5 = $xml6-&gt;children()-&gt;children();
                    $resources5-&gt;name = $manufacturer_name;  
                    $resources5-&gt;active = 1; 
                    unset($resources5 -&gt; link_rewrite);

                    $res = $webService-&gt;add(
                        array(
                        'resource' =&gt; 'manufacturers',
                        'active' =&gt; array(),
                        'postXml' =&gt; $xml6-&gt;asXML()
                        )
                    );
                   // var_dump($res);
                    $resources-&gt;product-&gt;id_manufacturer = $resources2-&gt;manufacturer-&gt;id;

            }
        }else
            unset($resources-&gt;product-&gt;id_manufacturer);
        // Here we have XML before update, lets update XML with new values
        foreach ($resources as $nodeKey =&gt; $node)

        {   
            //-&gt;{$nodeKey});
                if(!$params['object']-&gt;{$nodeKey})
                    unset($node);

               // elseif($nodeKey == '')

                elseif($nodeKey == 'link_rewrite' or 'name' ==$nodeKey or 'meta_description' == $nodeKey or 'meta_keywords' == $nodeKey or 'meta_title'  == $nodeKey or 'description' == $nodeKey or 'description_short'== $nodeKey  ){

                    $link_rewrite = $params['object']-&gt;{$nodeKey};
                        foreach($params['object']-&gt;{$nodeKey} as $lang=&gt;$link ){
                              $resources-&gt;$nodeKey= '' ; // Clean this object
                              $resources-&gt;$nodeKey-&gt;addChild('language' ,$link);
                              $resources-&gt;$nodeKey-&gt;language-&gt;AddAttribute('id', $lang);
                        }
                }elseif( $nodeKey ==  'id_category_default'){
                    $categorie = new Category((int)$params['object']-&gt;id_category_default);
                    $catName = $categorie-&gt;name[$id_lang];
                    //var_dump($catName);
                    //get categorie id in remote shop
                    $opt = array();
                    $opt['resource'] = 'categories';
                      // We set an id if we want to retrieve infos from a customer


                    $webService = new PrestaShopWebservice(PS_SHOP_PATH, PS_WS_AUTH_KEY, DEBUG);
                    if (isset($resources-&gt;$nodeKey))
                      $opt['filter[name]'] = '['.$catName.']' ; // cast string =&gt; int for security measures
                      $opt['display']     = '[id]'; 
                      // Call
                      $xml1 = $webService-&gt;get($opt);
                      if($xml1){
                          $resources1 = $xml1-&gt;children()-&gt;children();
                          //echo '***************';
                          //var_dump($resources1);
                          $resources-&gt;$nodeKey = $resources1[0]-&gt;id;
                      }


                }


                else
                $resources-&gt;$nodeKey = $params['object']-&gt;{$nodeKey};


        }
        // And call the web service
        try
        {
                $opt = array('resource' =&gt; 'products');
                //First remove any indentations:
                $opt['putXml'] = $xml-&gt;asXML();
                //var_dump($this-&gt;id_product);
                $opt['id'] = $this-&gt;id_product;
                //$opt['filter[reference]'] = '['.$params['object']-&gt;reference.']';
                $xml = $webService-&gt;edit($opt);
                // if WebService don't throw an exception the action worked well and we don't show the following message
                echo "Successfully updated.";

                exit;
        }
        catch (PrestaShopWebserviceException $ex)
        {
                // Here we are dealing with errors
                $trace = $ex-&gt;getTrace();
                if ($trace[0]['args'][0] == 404) echo 'Bad ID';
                else if ($trace[0]['args'][0] == 401) echo 'Bad auth key';
                else echo 'Other error&lt;br /&gt;'.$ex-&gt;getMessage();
        }
}



}
</code></pre>

<p>The XML Sent</p>

<pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;prestashop xmlns:xlink="http://www.w3.org/1999/xlink"&gt;
&lt;products&gt;
&lt;product&gt;
&lt;id&gt;1&lt;/id&gt;
&lt;id_manufacturer xlink:href="http://www.website.com/api/manufacturers/1"&gt;116&lt;/id_manufacturer&gt;
&lt;id_supplier&gt;0&lt;/id_supplier&gt;
&lt;id_category_default xlink:href="http://www.website.com/api/categories/2"&gt;2&lt;/id_category_default&gt;
&lt;new/&gt;
&lt;cache_default_attribute&gt;0&lt;/cache_default_attribute&gt;
&lt;id_default_image xlink:href="http://www.website.com/api/images/products/1/61" notFilterable="true"&gt;61&lt;/id_default_image&gt;
&lt;id_default_combination notFilterable="true"/&gt;
&lt;id_tax_rules_group xlink:href="http://www.website.com/api/tax_rule_groups/8"&gt;8&lt;/id_tax_rules_group&gt;
&lt;position_in_category notFilterable="true"&gt;0&lt;/position_in_category&gt;
&lt;manufacturer_name notFilterable="true"&gt;Abac&lt;/manufacturer_name&gt;
&lt;quantity notFilterable="true"&gt;0&lt;/quantity&gt;
&lt;type notFilterable="true"&gt;simple&lt;/type&gt;
&lt;id_shop_default&gt;1&lt;/id_shop_default&gt;
&lt;reference&gt;VIPCARD&lt;/reference&gt;
&lt;supplier_reference/&gt;
&lt;location/&gt;
&lt;width&gt;0.000000&lt;/width&gt;
&lt;height&gt;0.000000&lt;/height&gt;
&lt;depth&gt;0.000000&lt;/depth&gt;
&lt;weight&gt;0.000000&lt;/weight&gt;
&lt;quantity_discount&gt;0&lt;/quantity_discount&gt;
&lt;ean13/&gt;
&lt;upc/&gt;
&lt;cache_is_pack&gt;0&lt;/cache_is_pack&gt;
&lt;cache_has_attachments&gt;0&lt;/cache_has_attachments&gt;
&lt;is_virtual&gt;0&lt;/is_virtual&gt;
&lt;on_sale&gt;0&lt;/on_sale&gt;
&lt;online_only&gt;0&lt;/online_only&gt;
&lt;ecotax&gt;0.000000&lt;/ecotax&gt;
&lt;minimal_quantity&gt;1&lt;/minimal_quantity&gt;
&lt;price&gt;99.170000&lt;/price&gt;
&lt;wholesale_price&gt;0.000000&lt;/wholesale_price&gt;
&lt;unity/&gt;
&lt;unit_price_ratio&gt;0.000000&lt;/unit_price_ratio&gt;
&lt;additional_shipping_cost&gt;0.00&lt;/additional_shipping_cost&gt;
&lt;customizable&gt;0&lt;/customizable&gt;
&lt;text_fields&gt;0&lt;/text_fields&gt;
&lt;uploadable_files&gt;0&lt;/uploadable_files&gt;
&lt;active&gt;1&lt;/active&gt;
&lt;redirect_type&gt;404&lt;/redirect_type&gt;
&lt;id_product_redirected&gt;0&lt;/id_product_redirected&gt;
&lt;available_for_order&gt;1&lt;/available_for_order&gt;
&lt;available_date&gt;0215-09-01&lt;/available_date&gt;
&lt;condition&gt;new&lt;/condition&gt;
&lt;show_price&gt;1&lt;/show_price&gt;
&lt;indexed&gt;1&lt;/indexed&gt;
&lt;visibility&gt;both&lt;/visibility&gt;
&lt;advanced_stock_management&gt;0&lt;/advanced_stock_management&gt;
&lt;date_add&gt;2016-04-21 12:19:16&lt;/date_add&gt;
&lt;date_upd&gt;2016-04-21 12:19:16&lt;/date_upd&gt;
&lt;pack_stock_type&gt;0&lt;/pack_stock_type&gt;
&lt;meta_description&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;&lt;/language&gt;&lt;/meta_description&gt;
&lt;meta_keywords&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;&lt;/language&gt;&lt;/meta_keywords&gt;
&lt;meta_title&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;Carte VIP&lt;/language&gt;&lt;/meta_title&gt;
&lt;link_rewrite&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;carte-vip&lt;/language&gt;&lt;/link_rewrite&gt;
&lt;name&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;Carte VIP&lt;/language&gt;&lt;/name&gt;
&lt;description&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;&amp;lt;p&amp;gt;Cette carte virtuelle vous permet de bénéficier d’une réduction systématique de 5% sur tous vos achats. Elle coûte seulement 99€ et reste valable à vie. Elle peut également ouvrir droit à certaines opérations et promotions spéciales.&amp;lt;/p&amp;gt;&lt;/language&gt;&lt;/description&gt;
&lt;description_short&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;&lt;/language&gt;&lt;/description_short&gt;
&lt;available_now&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;&lt;/language&gt;&lt;/available_now&gt;
&lt;available_later&gt;&lt;language id="1" xlink:href="http://www.website.com/api/languages/1"&gt;&lt;/language&gt;&lt;/available_later&gt;
&lt;associations&gt;
&lt;categories nodeType="category" api="categories"&gt;&lt;categorie&gt;&lt;id&gt;2&lt;/id&gt; &lt;/categorie&gt;&lt;/categories&gt;
&lt;images nodeType="image" api="images"&gt;
&lt;image xlink:href="http://www.website.com/api/images/products/1/61"&gt;
&lt;id&gt;61&lt;/id&gt;
&lt;/image&gt;
&lt;/images&gt;
&lt;combinations nodeType="combination" api="combinations"/&gt;
&lt;product_option_values nodeType="product_option_value" api="product_option_values"/&gt;
&lt;product_features nodeType="product_feature" api="product_features"/&gt;
&lt;tags nodeType="tag" api="tags"/&gt;
&lt;stock_availables nodeType="stock_available" api="stock_availables"&gt;
&lt;stock_available xlink:href="http://www.website.com/api/stock_availables/1"&gt;
&lt;id&gt;1&lt;/id&gt;
&lt;id_product_attribute&gt;0&lt;/id_product_attribute&gt;
&lt;/stock_available&gt;
&lt;/stock_availables&gt;
&lt;accessories nodeType="product" api="products"/&gt;
&lt;product_bundle nodeType="product" api="products"/&gt;
&lt;/associations&gt;
&lt;/product&gt;
&lt;/products&gt;
&lt;/prestashop&gt;
</code></pre>