Configafe configuration: how to iterate over configuration items

In my Play application, I have this configuration:

social { twitter { url="https://twitter.com" logo="images/twitter.png" } facebook { url="https://www.facebook.com" logo="images/facebook.png" } } 

Ho, I iterate over all social records to get url and logo for each record?

 <table border="0" cellspacing="0" cellpadding="2"><tr> @configuration.getConfig("social").map { config => @for(item <- config.entrySet) { <td><a href="item.getString("url")"> <img src="@routes.Assets.at("item.getString("logo")").absoluteURL()" width="24" height="24"/></a></td> } } </table> 

Of course, item.getString in the above snippet doesn't work ... it just shows what I'm trying to achieve.

The ultimate goal would be to add any additional social url without changing the page template.

+7
scala playframework typesafe-config
source share
4 answers

If you change the configuration to:

 "social" : [ { name="twitter" url="https://twitter.com", logo="images/twitter.png" }, { name="facebook" url="https://www.facebook.com", logo="images/facebook.png" } ] 

You can do it as follows:

 @(message: String)(implicit request: RequestHeader) @import play.api.Play.current <table border="0" cellspacing="0" cellpadding="2"><tr> @current.configuration.getConfigList("social").get.map { config => <td><a href="@config.getString("url")"> <img src="@routes.Assets.at(config.getString("logo").get).absoluteURL()" width="24" height="24"/></a></td> } </table> 
+10
source share

For posterity, there is another way to iterate over a nested configuration, just like you do. I prefer this format to an array, and I would prefer to make my configuration cleaner than the code.

 import collection.JavaConversions._ val socialConfig = ConfigFactory.load.getConfig("social") socialConfig.root.map { case (name: String, configObject: ConfigObject) => val config = configObject.toConfig println(config.getString("url")) println(config.getString("logo")) } 

I am sure the OP can convert this to a Twirl pattern. It is as clean as I can get it.

+4
source share

If you are using java, this might be the solution:

 ConfigList socials = ConfigFactory().load.getList("social") for (ConfigValue cv : socials) { Config c = ((ConfigObject)cv).toConfig(); System.out.println(c.getString("url")); System.out.println(c.getString("logo")); } 
+4
source share

socialConfig.root.map does not work.

Here is my solution -

 private val firstSegmentRE = """^(\w+)[\.*].*$""".r // convert "aaa.bbb.ccc" to "aaa" private def parseFirstSegment(fullPath: String) : Option[String] = { if (fullPath.contains(".")) fullPath match { case firstSegmentRE(segment) => Some(segment) case _ => None } else Some(fullPath) } // for all keys in white list get a map of key -> config protected def subConfigMap(config: Config, whiteList: List[String], configName: String) : ErrorOr[Map[String, Config]] = { // This will traverse the whole config and flatten down to the leaves.. val leafKeys : List[String] = config.entrySet() .asScala .map(e => e.getKey) .toList // Remove all after the first dot val nextLevelKeys : List[String] = leafKeys.map(parseFirstSegment) .collect { case Some(firstSegment) => firstSegment } .distinct val keysToSearch = nextLevelKeys.filter(whiteList.contains) // we have a list of valid first level children // parse out subconfigs and convert to map keysToSearch.traverseErrorOr( key => extractSubConfig(config, key, configName).map((key, _)) ) .map(_.toMap) } 

Where extractSubConfig is the method that creates ERROR / Config (scalar splitting), and traverseErrorOr is the method to move through the list and either process all elements or fail, and return an unsuccessful disjunction if it did not work at any point. This method can be done without scalaz by simply sending an answer to help people if they want to.

0
source share

All Articles