github.com/fedir/buffalo@v0.11.1/route.go (about)

     1  package buffalo
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"html/template"
     7  	"net/url"
     8  	"sort"
     9  	"strings"
    10  
    11  	"reflect"
    12  
    13  	"github.com/gorilla/mux"
    14  	"github.com/markbates/inflect"
    15  )
    16  
    17  // Routes returns a list of all of the routes defined
    18  // in this application.
    19  func (a *App) Routes() RouteList {
    20  	if a.root != nil {
    21  		return a.root.routes
    22  	}
    23  	return a.routes
    24  }
    25  
    26  // RouteInfo provides information about the underlying route that
    27  // was built.
    28  type RouteInfo struct {
    29  	Method      string     `json:"method"`
    30  	Path        string     `json:"path"`
    31  	HandlerName string     `json:"handler"`
    32  	PathName    string     `json:"pathName"`
    33  	Aliases     []string   `json:"aliases"`
    34  	MuxRoute    *mux.Route `json:"-"`
    35  	Handler     Handler    `json:"-"`
    36  	App         *App       `json:"-"`
    37  }
    38  
    39  // String returns a JSON representation of the RouteInfo
    40  func (ri RouteInfo) String() string {
    41  	b, _ := json.MarshalIndent(ri, "", "  ")
    42  	return string(b)
    43  }
    44  
    45  // Alias path patterns to the this route. This is not the
    46  // same as a redirect.
    47  func (ri *RouteInfo) Alias(aliases ...string) *RouteInfo {
    48  	ri.Aliases = append(ri.Aliases, aliases...)
    49  	for _, a := range aliases {
    50  		ri.App.router.Handle(a, ri).Methods(ri.Method)
    51  	}
    52  	return ri
    53  }
    54  
    55  // Name allows users to set custom names for the routes.
    56  func (ri *RouteInfo) Name(name string) *RouteInfo {
    57  	routeIndex := -1
    58  	for index, route := range ri.App.Routes() {
    59  		if route.Path == ri.Path && route.Method == ri.Method {
    60  			routeIndex = index
    61  			break
    62  		}
    63  	}
    64  
    65  	name = inflect.CamelizeDownFirst(name)
    66  
    67  	if !strings.HasSuffix(name, "Path") {
    68  		name = name + "Path"
    69  	}
    70  
    71  	ri.PathName = name
    72  	if routeIndex != -1 {
    73  		ri.App.Routes()[routeIndex] = reflect.ValueOf(ri).Interface().(*RouteInfo)
    74  	}
    75  
    76  	return ri
    77  }
    78  
    79  //BuildPathHelper Builds a routeHelperfunc for a particular RouteInfo
    80  func (ri *RouteInfo) BuildPathHelper() RouteHelperFunc {
    81  	cRoute := ri
    82  	return func(opts map[string]interface{}) template.HTML {
    83  		pairs := []string{}
    84  		for k, v := range opts {
    85  			pairs = append(pairs, k)
    86  			pairs = append(pairs, fmt.Sprintf("%v", v))
    87  		}
    88  
    89  		url, err := cRoute.MuxRoute.URL(pairs...)
    90  		if err != nil {
    91  			return template.HTML(cRoute.Path)
    92  		}
    93  
    94  		result := url.Path
    95  		result = addExtraParamsTo(result, opts)
    96  
    97  		return template.HTML(result)
    98  	}
    99  }
   100  
   101  func addExtraParamsTo(path string, opts map[string]interface{}) string {
   102  	pendingParams := map[string]string{}
   103  	keys := []string{}
   104  	for k, v := range opts {
   105  		if strings.Contains(path, fmt.Sprintf("%v", v)) {
   106  			continue
   107  		}
   108  
   109  		keys = append(keys, k)
   110  		pendingParams[k] = fmt.Sprintf("%v", v)
   111  	}
   112  
   113  	if len(keys) == 0 {
   114  		return path
   115  	}
   116  
   117  	if strings.Contains(path, "?") == false {
   118  		path = path + "?"
   119  	} else {
   120  		if strings.HasSuffix(path, "?") == false {
   121  			path = path + "&"
   122  		}
   123  	}
   124  
   125  	sort.Strings(keys)
   126  
   127  	for index, k := range keys {
   128  		format := "%v=%v"
   129  
   130  		if index > 0 {
   131  			format = "&%v=%v"
   132  		}
   133  
   134  		path = path + fmt.Sprintf(format, url.QueryEscape(k), url.QueryEscape(pendingParams[k]))
   135  	}
   136  
   137  	return path
   138  }
   139  
   140  //RouteHelperFunc represents the function that takes the route and the opts and build the path
   141  type RouteHelperFunc func(opts map[string]interface{}) template.HTML
   142  
   143  // RouteList contains a mapping of the routes defined
   144  // in the application. This listing contains, Method, Path,
   145  // and the name of the Handler defined to process that route.
   146  type RouteList []*RouteInfo
   147  
   148  func (a RouteList) Len() int      { return len(a) }
   149  func (a RouteList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
   150  func (a RouteList) Less(i, j int) bool {
   151  	x := a[i].Path // + a[i].Method
   152  	y := a[j].Path // + a[j].Method
   153  	return x < y
   154  }