How I can read conditions unserialised data in golang in map format?
[map[19:map[conditions:map[0:map[operator:== value:AMW-1900-50SLE-ROOM
is_value_processed:false type:feedexport/rule_condition_product
attribute:sku] 1:map[type:feedexport/rule_condition_product
attribute:sku operator:== value:ASL-B654-77-74-98-ROOM
is_value_processed:false] 2:map[is_value_processed:false
type:feedexport/rule_condition_product attribute:sku operator:==
value:ASL-B217-57-54S-95-ROOM]] type:feedexport/rule_condition_combine
attribute:<nil> operator:<nil> value:1 is_value_processed:<nil>
aggregator:any]]]
This is the code:
package main
import (
"fmt"
"github.com/wulijun/go-php-serialize/phpserialize"
)
func main() {
rules := RulesList()
for _, rule := range rules{
fmt.Println(rule.Conditions.(interface{}))
}
}
type Rule struct {
RuleId int `json:"rule_id"`
Conditions interface{} `json:"conditions"`
}
func RulesList() ([]Rule) {
db := DbConn()
res, err := db.Query(`SELECT r.rule_id, r.conditions_serialized AS
conditions FROM m_feedexport_rule AS r`)
CheckError(err)
rule := Rule{}
rules := []Rule{}
for res.Next() {
var ruleId int
var conditions string
err = res.Scan(&ruleId, &conditions)
CheckError(err)
cons, err := phpserialize.Decode(conditions)
CheckError(err)
rule.RuleId = ruleId
rule.Conditions = cons
rules = append(rules, rule)
}
return rules
}
The result is ok but I need it in map form, now this is the interface which I can't loop over. In case if anyone don't understand the code, ask me. Thanks a lot.
You're talking about the type of the variable cons
, are you?
If yes, the reason its type is interface{}
is because in PHP, it's possible to serialize a value of any type (from bare integer to a complicated object), and hence any deserialization code must cope with it. Since in Go the so-called "empty interface", interface{}
, is satisfied by any type at all (including any custom type implemented by a programmer), it's sensbile for a decoder of PHP-serialized data to return a value of type interface{}
.
After making sure decoding succeeded, you need to either type-assert the resulting value to a type you need or to use a type switch to diverge processing based on the concrete type of the value returned by the decoder.
The approach is very well demonstrated by the package you're using in its own test suite.
A snippet from it demonstrating the basic approach
if decodeRes, err = Decode(result); err != nil {
t.Errorf("decode data fail %v, %v", err, result)
return
}
decodeData, ok := decodeRes.(map[interface{}]interface{})
if !ok {
t.Errorf("decode data type error, expected: map[interface{}]interface{}, get: %T", decodeRes)
return
}
obj, _ := decodeData["object"].(*PhpObject)
if v, _ := obj.GetPrivateMemberValue("a"); v != int64(1) {
t.Errorf("object private value expected 1, get %v, %T", v, v)
}
if v := obj.GetClassName(); v != "A" {
t.Errorf("object class name expected A, get %v", v)
}
Here, decodeRes
is what returned by the decoder. That value is then type-asserted to make sure it's concrete type (also called "dynamic" — meaning "at runtime") is map[interface{}]interface{}
.
Note that the so-called "two-argument" type assert is used (it's also called a "comma-ok idiom") to not make the program panic at runtime in case the concrete type is different from the expected (always do this on data fetched from outside!).
The value of the type-asserted concrete type is stored in the decodeData
variable, and then that variable is inspected further.