Hi Folks,

Lets get the ball rolling and public with this functionality. Here's an initial top level strategy/pseudo code to implement the "Synch Magento Attribute Sets to Content Types"

Pretty much the assumptions are:
1. Magento's Attribute Sets are a near equivalent of Drupal's Node Types
2. Magento's Attribute are a near equivalent of Drupal's Content Field
3. Content Field (date,datestamp,datetime,number_decimal,filefield,number_float,number_integer,nodereference,text) excluding
(userreference)
4. This is going to be a one way sync; strictly Magento to Drupal. (scope purposes)

Comments

sndev’s picture

Title: Add Functionality "Sync Magento Attribute Sets to Drupal Content Types" » Add Functionality "Sync Magento Content Types/Attribute Sets to Drupal Content Types"
sndev’s picture

Hi Maxime,

Here's a working mockup php script on how we are going to check if the attribute sets have changed in magento. $current_set is the Current state of the
Magento Attribute Set and $stored_set_[x] are the previous sync's stored Magento Attribute Set.


//include('../krumo/class.krumo.php');


/**
 * custom array_diff_assoc_recursive
 * by 55 dot php at imars dot com
 */
function array_compare($array1, $array2) {
    $diff = false;
    // Left-to-right
    foreach ($array1 as $key => $value) {
        if (!array_key_exists($key,$array2)) {
            $diff[0][$key] = $value;
        } elseif (is_array($value)) {
             if (!is_array($array2[$key])) {
                    $diff[0][$key] = $value;
                    $diff[1][$key] = $array2[$key];
             } else {
                    $new = array_compare($value, $array2[$key]);
                    if ($new !== false) {
                         if (isset($new[0])) $diff[0][$key] = $new[0];
                         if (isset($new[1])) $diff[1][$key] = $new[1];
                    };
             };
        } elseif ($array2[$key] !== $value) {
             $diff[0][$key] = $value;
             $diff[1][$key] = $array2[$key];
        };
 };
 // Right-to-left
 foreach ($array2 as $key => $value) {
        if (!array_key_exists($key,$array1)) {
             $diff[1][$key] = $value;
        };
        // No direct comparsion because matching keys were compared in the
        // left-to-right loop earlier, recursively.
 };
 return $diff;
};


// this part of script checks if there is a change in the attribute set since the last sync

// simulated result set from magento api of a certain attribute set for example: test_attribute_set
$current_attribute_set	=	array(
														array('attribute_id'=>'98','code'=>'sku','type'=>'text','required'=>'1','scope'=>'global'),		
														array('attribute_id'=>'933','code'=>'test_text','type'=>'text','required'=>'0','scope'=>'store'),		
														array('attribute_id'=>'934','code'=>'test_dropdown','type'=>'select','required'=>0,'scope'=>'store',
																	'allowed_values'=>array(1=>'blue',2=>'red',3=>'green',4=>'black'),
														),
													);

// simulated result set stored in dragento transaction table of an attribute set: test_attribute_set from a previous sync 
$stored_attribute_set_1	=	array(
															array('attribute_id'=>'98','code'=>'sku','type'=>'text','required'=>'1','scope'=>'global'),		
															array('attribute_id'=>'933','code'=>'test_text','type'=>'text','required'=>'0','scope'=>'store'),		
															array('attribute_id'=>'934','code'=>'test_dropdown','type'=>'select','required'=>0,'scope'=>'store',
																	'allowed_values'=>array(1=>'blue',2=>'red',3=>'green',4=>'black'),
															),
								  			  );								  			  					  			  
								  			  
// simulated result set stored in dragento transaction table of an attribute set: test_attribute_set from a previous sync 
$stored_attribute_set_2	=	array(
															array('attribute_id'=>'98','code'=>'sku','type'=>'text','required'=>'1','scope'=>'global'),																	
															array('attribute_id'=>'934','code'=>'test_dropdown','type'=>'select','required'=>0,'scope'=>'store',
																	'allowed_values'=>array(1=>'blue',2=>'red',3=>'green',4=>'black'),
															),
								  			  );								  			  

// simulated result set from magento api of a certain attribute set for example: test_attribute_set
$stored_attribute_set_3	=	array(
														array('attribute_id'=>'98','code'=>'sku','type'=>'text','required'=>'1','scope'=>'global'),		
														array('attribute_id'=>'933','code'=>'test_text','type'=>'text','required'=>'0','scope'=>'store'),		
														array('attribute_id'=>'934','code'=>'test_dropdown','type'=>'select','required'=>0,'scope'=>'store',
															'allowed_values'=>array(1=>'blue',2=>'red',3=>'green',4=>'black'),
														),
														array('attribute_id'=>'935','code'=>'test_text2','type'=>'text','required'=>'0','scope'=>'store'),		
													);								  			  
													
// simulated result set from magento api of a certain attribute set for example: test_attribute_set
$stored_attribute_set_4	=	array(
														array('attribute_id'=>'98','code'=>'sku','type'=>'text','required'=>'1','scope'=>'global'),		
														array('attribute_id'=>'933','code'=>'test_text','type'=>'text','required'=>'0','scope'=>'store'),		
														array('attribute_id'=>'934','code'=>'test_dropdown','type'=>'select','required'=>0,'scope'=>'store',
															'allowed_values'=>array(1=>'blue',2=>'red',3=>'green',4=>'black',5=>'orange',6=>'neon-green'),															
														),
													);								  			  													
													
// simulated result set from magento api of a certain attribute set for example: test_attribute_set
$stored_attribute_set_5	=	array(
														array('attribute_id'=>'98','code'=>'sku','type'=>'text','required'=>'1','scope'=>'global'),		
														array('attribute_id'=>'933','code'=>'test_text','type'=>'text','required'=>'0','scope'=>'store'),		
														array('attribute_id'=>'934','code'=>'test_dropdown','type'=>'select','required'=>0,'scope'=>'store',
															'allowed_values'=>array(1=>'blue',2=>'red',3=>'green'),
														),
													);														
								  			  
									
//krumo($current_array);
//krumo($stored_array);

//there is no change in the attribute set from previous sync to current sync
var_dump(array_compare($current_attribute_set,$stored_attribute_set_1));

//there is change in the attribute set from previous sync to current sync -- one less attribute
var_dump(array_compare($current_attribute_set,$stored_attribute_set_2));

//there is change in the attribute set from previous sync to current sync -- an additional attribute
var_dump(array_compare($current_attribute_set,$stored_attribute_set_3));

//there is change in the attribute set from previous sync to current sync -- an additional value in allowed values of test_dropdown
var_dump(array_compare($current_attribute_set,$stored_attribute_set_4));

//there is change in the attribute set from previous sync to current sync -- one less value in allowed values of test_dropdown
var_dump(array_compare($current_attribute_set,$stored_attribute_set_5));

Assumptions used for this script are:

1. Magento does not track any updated dates for attribute changes on attribute sets
2. We can get an array of attribute sets (attribute_set_id) and an array of attributes inside a particular attribute set
3. For attribute types like select/dropdowns we can also get an array of allowed values

Please confirm this assumptions are correct and can be provided in the xml-rpc side of magento.

Kind regards,
Sndev.

Maxime Topolov’s picture

Hi sndev !

I would suggest to keep track of attributes changes in magento. I mean it would not be a big issue to keep those changes in a table with "last sync date". Also what I would suggest is to implement a service on Drupal side to enable magento to sync drupal on each attribute set change ?

What do you think about ?

sndev’s picture

I like your idea of having a drupal service to enable magento to sync drupal on each attribute set as an additional check to see if an attribute set got modified! That was one of the unknown's I was dealing with... if it was possible/feasible in our magento side of the effort. But perhaps this feature would be good to implement at a later version I really just want to have a working Magento Attribute Set to Drupal Content Type Feature up and going. The team plans a long term commitment of this module.

For now I think we have a transaction log table for Attribute Sets syncs in drupal with a tentative rough draft structure of:

id ,magento_attribute_set_id, drupal_content_type_id, serialize string of magento_attributes_inside_attribute_set, created_time, updated_time

We can detect changes in a magento attribute set mainly by checking the structure & contents of the attribute set and the attributes inside as describe by the above mockup php script. I think this approach will work given if my assumption:

3. For attribute types like select/dropdowns we can also get an array of allowed values

is correct. Am I right to assume that our magento side of the effort can pull through with this functionality, cause I think this is not a standard function provided by magento.

pretty much modifying our existing function of magento_api_catalog_product_attribute_list to include widget information:


/**
 * Retrieve list of attributes and allowed values inside a particular attribute set
 *
 * @param int $attribute_set_id 
 * @return array
 */
function magento_api_catalog_product_attribute_list($attribute_set_id = NULL) {
	// for example this attribute set please take note: of the attribute test_dropdown has allowed_values 
	// pretty much widget information about an attribute type
	$attributes_inside_attribute_set = xmlrpc(_magento_api_get_host(), 'call', $session, 'product_attribute.list', array($attribute_set_id));
	$attributes_inside_attribute_set	=	array(
															array('attribute_id'=>'98','code'=>'sku','type'=>'text','required'=>'1','scope'=>'global'),		
															array('attribute_id'=>'933','code'=>'test_text','type'=>'text','required'=>'0','scope'=>'store'),		
															array('attribute_id'=>'934','code'=>'test_dropdown','type'=>'select','required'=>0,'scope'=>'store',
																	'allowed_values'=>array(1=>'blue',2=>'red',3=>'green',4=>'black'),
															),
														);	
	return $attributes_inside_attribute_set;
}


Maxime, what do you think can I assume that this is feasible?

sndev’s picture

There is also a reason why i think we need to be cautious with adding modified time as an additional check for change in attribute sets. Our approach to include the modified time really matters, my reasons to be cautious are these:

a. Case in point the proposed approach of having a trigger in Magento to change a table in Drupal whenever attribute set(s) get modified makes our application dicey. We have an asymmetric sync between our target platforms (Drupal and Magento), so imagine a situation where our users uninstalls the magento module and then proceeds to update a Magento attribute set, this would cause an error in Magento because the receiving transaction table no longer exist. This approach further complicates an already complicated process.

b. Also looking from the eyes of an outside developer checking at the script. The developer would might not immediately grasp that modified time is not generated from current running script of "Sync Magento Attribute Sets to Drupal Content Types" but would be coming from a magento application trigger when an attribute set gets created/modified.

c. It also increases the number of points of failure in the process. Here's what I mean if there are any errors in the "Sync Magento Attribute Set to Drupal Content Types" I would normally look at the script responsible for this feature, now for any troubleshooting we also have to include the event in "magento attribute set changed" triggered.
Example Imagine a "time out" error happening when the attribute set trigger.

Thanks.

sndev’s picture

I was looking an the function magento_api_catalog_product_attribute_options I think this function fits nicely, I can modify the script to include this option for the widget information. It's not going to be a one stop function to get the array I need to process, but thats okay I can use the functions magento_api_catalog_product_attribute_options and magento_api_catalog_product_attribute_list to generate the needed array.

I answered my own question :)

sndev’s picture

Here's a roadmap on how I intend to deal with Magento's Attribute Types then converting those types to Drupal's Field Types. Please help with feedback as I
personally have not used Magento that much yet. There might be some gotcha's that I am not aware about. Having said that here are the Magento Attribute Types
and my intended approach to convert those attribute types to a drupal field type.

Magento Attribute Types:
1. Text field
2. Text Area
3. Date
4. Yes/No
5. Multiple Select
6. Dropdown
7. Price
8. Gallery
9. Media Image
10. Fixed Product Tax

Action plans to convert to a Drupal field type
1. Text Field
Type: Text, Widget: Text field, Number of values: 1
2. Text Area
Type: Text, Widget: Text area(multiple rows), Number of values: 1
3. Date
Type: Date, Widget: Text Field with custom input format,
Customize Default Value: Whatever is drupal default input format
*** I havent really dug into the details yet, anyone wanna pitch in their opinion on this field?
4. Yes/No
Type: integer, Widget: select list, allowed values: 0,1
5. Multi Select
Type: Text, Widget: Checkboxes/radiobuttons, Number of Values: unlimited, allowed values list would be from the information received in function magento_api_catalog_product_attribute_options
6. Dropdown
Type: Text, Widget: Select list, number of values: 1, allowed values list allowed values list would be from the information received in function magento_api_catalog_product_attribute_options
7. Price
Type: Text, Widget: Text Field, Number of values: 1,
8. Gallery:
Type: File, Widget: Image. Permitted upload file extensions: png gif jpg jpeg
Number of values: unlimited
9. Media Image
*** this doesnt act like a field but acts like an imagecache present. should we ignore this?
10. Fixed Product Tax
Type: text, Widget: Text Field, Number of values: unlimited
*** might i suggest that we ignore this?

valcker’s picture

Hi sndev!

Do you have any news regarding functionality proposed by you? Did you try to implement something? We are going to start working on this part in next few weeks so if you have anything ready it would be great to merge our code :)

chriscalip’s picture

I could not pull it off :( I gave most of the code to one of maxime's co-workers.

Maxime Topolov’s picture

Hi there !

Just to keep you updated :

- We almost finished with a complete Attribute Set <-> CCK syncronisation
- We almost rewrote whole module

This offers following :

- Full support of multi-site / multi-store
- Full support of Drupal multi-site
- Full support of multi-language

We'll soon commit the V2 on Drupal.org... and a new live site using this version.

chriscalip’s picture

Maxime,

I am glad your team is pulling it off. Good one :)

Andrew Gusarov’s picture

Status: Active » Closed (fixed)

V2 has been released