github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/webTypeAdmin/fkRefType.go (about)

     1  package webTypeAdmin
     2  
     3  import (
     4  	"fmt"
     5  	"html/template"
     6  	"reflect"
     7  
     8  	"github.com/bronze1man/kmg/kmgType"
     9  )
    10  
    11  var fkRefReflectType = reflect.TypeOf((*FkRef)(nil)).Elem()
    12  
    13  type FkRef interface {
    14  	GetReferenceType() reflect.Type
    15  }
    16  
    17  //xxId refer to another object
    18  //path -> pass to RefType
    19  type fkRefType struct {
    20  	kmgType.KmgType
    21  	referenceType      adminType
    22  	referenceContainer reflect.Value
    23  	keyStringConverter kmgType.StringConverterInterface
    24  	ctx                *context
    25  }
    26  
    27  func (t *fkRefType) init() (err error) {
    28  	if t.referenceType != nil {
    29  		return
    30  	}
    31  	var ok bool
    32  	rrt := reflect.Zero(t.GetReflectType()).Interface().(FkRef).GetReferenceType()
    33  	if t.referenceType, err = t.ctx.typeOfFromReflect(rrt); err != nil {
    34  		return
    35  	}
    36  	rc, ok := getFkRefContainerValue(t.ctx.RootValue, rrt)
    37  	if !ok {
    38  		return fmt.Errorf("[fkRefType.init] not found referenceContainer name:%s", t.GetReflectType().Name())
    39  	}
    40  	t.referenceContainer = rc
    41  	if rc.Type().Key() != t.GetReflectType() {
    42  		return fmt.Errorf("[fkRefType.init] Container key type is not same with self type")
    43  	}
    44  	return nil
    45  }
    46  
    47  func getFkRefContainerValue(v reflect.Value, rrt reflect.Type) (reflect.Value, bool) {
    48  	switch v.Kind() {
    49  	case reflect.Map:
    50  		if v.Type().Elem() == rrt {
    51  			return v, true
    52  		}
    53  		if v.Type().Elem().Kind() == reflect.Ptr && v.Type().Elem().Elem() == rrt {
    54  			return v, true
    55  		}
    56  		return reflect.Value{}, false
    57  	case reflect.Ptr:
    58  		if v.IsNil() {
    59  			return reflect.Value{}, false
    60  		}
    61  		return getFkRefContainerValue(v.Elem(), rrt)
    62  	case reflect.Struct:
    63  		//TODO check mutli container
    64  		len := v.NumField()
    65  		for i := 0; i < len; i++ {
    66  			rv, ok := getFkRefContainerValue(v.Field(i), rrt)
    67  			if ok {
    68  				return rv, true
    69  			}
    70  		}
    71  		return reflect.Value{}, false
    72  	//not enter slice
    73  	//no need to check array
    74  	default:
    75  		return reflect.Value{}, false
    76  	}
    77  	return reflect.Value{}, false
    78  }
    79  func (t *fkRefType) HtmlView(v reflect.Value) (html template.HTML, err error) {
    80  	if err = t.init(); err != nil {
    81  		return
    82  	}
    83  	var templateData selectTemplateData
    84  	templateData.Value = t.keyStringConverter.ToString(v)
    85  	for _, vk := range t.referenceContainer.MapKeys() {
    86  		sk := t.keyStringConverter.ToString(vk)
    87  		templateData.List = append(templateData.List, sk)
    88  	}
    89  	return theTemplate.ExecuteNameToHtml("Select", templateData)
    90  }
    91  
    92  func (t *fkRefType) SaveByPath(v *reflect.Value, path kmgType.Path, value string) (err error) {
    93  	err = t.init()
    94  	if err != nil {
    95  		return
    96  	}
    97  	vk, err := t.keyStringConverter.FromString(value)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	vv := t.referenceContainer.MapIndex(vk)
   102  	if !vv.IsValid() {
   103  		return fmt.Errorf("[fkRefType.save] save value not in container map:%s", value)
   104  	}
   105  	return t.KmgType.SaveByPath(v, path, value)
   106  }