the soap calls defined in the qbxml.*.inc files are not being correctly generated. bug in code...
The problem I found is in this bit of code in qbxml.7.0.inc
'TxnFilter' =>
array (
'MaxReturned' =>
array (
'type' => 'INTTYPE',
'min' => 1,
),
'' =>
array (
'choice' =>
array (
0 => 'RefNumberFilter',
1 => 'RefNumberRangeFilter',
),
'RefNumberFilter' =>
array (
),
'RefNumberRangeFilter' =>
array (
),
),
'EntityFilter' =>
array (
),
'AccountFilter' =>
array (
),
),
the xsd definition is as follows
<xsd:group name="TxnFilterNoAccount">
<xsd:sequence>
<xsd:element ref="MaxReturned" minOccurs="0"/>
<xsd:choice minOccurs="0">
<xsd:element ref="ModifiedDateRangeFilter"/>
<xsd:element ref="TxnDateRangeFilter"/>
</xsd:choice>
<xsd:element ref="EntityFilter" minOccurs="0"/>
<xsd:choice minOccurs="0">
<xsd:element ref="RefNumberFilter"/>
<xsd:element ref="RefNumberRangeFilter"/>
</xsd:choice>
</xsd:sequence>
</xsd:group>
when qbxml.php generates the .inc file it traverses the xsd documents. but in the above code the keys in the generated array are the same so the final one overwrites the first one.
<xsd:choice minOccurs="0">
<xsd:element ref="RefNumberFilter"/>
<xsd:element ref="RefNumberRangeFilter"/>
</xsd:choice>
overwrites
<xsd:choice minOccurs="0">
<xsd:element ref="ModifiedDateRangeFilter"/>
<xsd:element ref="TxnDateRangeFilter"/>
</xsd:choice>
since they are at the same level in the outputted array and have the same key.
The generator, qbxml.php, does not check to see if the element in a group had already been defined. therefore it will overwrite it.
solution
at line 144 or so look for
$group[_get_name($element)] = _get_element($element, $elements);
and replace with
if(isset($group[_get_name($element)])){
// we don't want to overwrite the exisiting data so we need to merge the definitions
$group[_get_name($element)] = _merge_groups($group[_get_name($element)],_get_element($element, $elements));
}
else {
$group[_get_name($element)] = _get_element($element, $elements);
}
add the following function
function _merge_groups($group1, $group2){
$final_group = array();
$merged_keys = array();
foreach($group1 as $k => $v){
if(!isset($group2[$k])){
// key only exists in $group1
$merged_keys[$k] = true;
$final_group[$k] = $v;
}
else {
// the key exists in both groups
// we need to find out if both values are arrays
if(is_array($v) && is_array($group2[$k])){
$final_group[$k] = _merge_groups($v, $group2[$k]);
$merged_keys[$k] = true;
}
elseif(!is_array($v) && !is_array($group2[$k])){
if($v != $group2[$k] && is_numeric($k)){
$final_group[] = $v;
$final_group[] = $group2[$k];
}
$merged_keys[$k] = true;
}
}
}
foreach($group2 as $k => $v){
if(!isset($merged_keys[$k])){
// merge keys from group2
$merged_keys[$k] = true;
$final_group[$k] = $v;
}
}
return $final_group;
}
What the above code does is it will merge the two arrays, but not exclusively, thus it is better than array_merge(), it will traverse the arrays and find duplicate keys of arrays with both input arrays and merge them etc.
granted its not perfect code but it does the job and is not fully tested.
the final out put for the problem code is
'TxnFilter' =>
array (
'MaxReturned' =>
array (
'type' => 'INTTYPE',
'min' => 1,
),
'' =>
array (
'choice' =>
array (
0 => 'ModifiedDateRangeFilter',
1 => 'RefNumberFilter',
2 => 'TxnDateRangeFilter',
3 => 'RefNumberRangeFilter',
),
'ModifiedDateRangeFilter' =>
array (
),
'TxnDateRangeFilter' =>
array (
),
'RefNumberFilter' =>
array (
),
'RefNumberRangeFilter' =>
array (
),
),
'EntityFilter' =>
array (
),
'AccountFilter' =>
array (
),
),
Comments
Comment #1
yfreeman commentedI forgot to add...
This module is awesome.
Comment #2
yfreeman commentedThe solution is there, a patch needs to be rolled. I've never done one... I don't have the time to learn at the moment...