All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.fwbrasil.activate.play.EntityForm.scala Maven / Gradle / Ivy

The newest version!
package net.fwbrasil.activate.play

import play.api.data.FormError
import play.api.data.Form
import play.api.data.Mapping
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import play.api.data.format.Formats._
import net.fwbrasil.activate.statement.StatementMocks
import net.fwbrasil.activate.util.ManifestUtil._
import net.fwbrasil.activate.util.Reflection.newInstance
import net.fwbrasil.activate.util.RichList._
import net.fwbrasil.activate.ActivateContext
import play.api.data.validation.Constraint
import net.fwbrasil.activate.entity.BaseEntity
import net.fwbrasil.activate.util.uuid.UUIDUtil
import net.fwbrasil.activate.entity.IdVar
import play.api.data.format.Formatter
import net.fwbrasil.activate.entity.EntityHelper
import net.fwbrasil.activate.entity.EntityMetadata
import scala.annotation.implicitNotFound
import net.fwbrasil.radon.transaction.TransactionalExecutionContext
import scala.concurrent.Future
import net.fwbrasil.activate.entity.map.MutableEntityMap
import net.fwbrasil.activate.entity.map.EntityMapBase
import net.fwbrasil.activate.entity.id.EntityId
@implicitNotFound("ActivateContext implicit not found. Please import yourContext._")
class EntityForm[T <: BaseEntity](
    mapping: EntityMapping[T],
    data: Map[String, String] = Map.empty,
    errors: Seq[FormError] = Nil,
    value: Option[MutableEntityMap[T]] = None)(
        implicit context: ActivateContext,
        m: Manifest[T])
        extends Form[MutableEntityMap[T]](mapping, data, errors, value) {

    implicit val entityMetadata = EntityHelper.getEntityMetadata(erasureOf[T])

    def fillWith(entityMap: EntityMapBase[T, _]) =
        new EntityForm[T](mapping, mapping.unbind(new MutableEntityMap(entityMap.values))._1)

    def fillWith(entity: T): EntityForm[T] =
        fillWith(new MutableEntityMap(entity))
}

object EntityForm {

    import language.implicitConversions

    implicit def entityMap[T <: BaseEntity](entity: T)(implicit context: ActivateContext, m: Manifest[T]): MutableEntityMap[T] =
        new MutableEntityMap(entity)

    def entity[T <: BaseEntity](implicit context: ActivateContext, m: Manifest[T]) =
        of[T](new EntityFormatter[T])

    def apply[T <: BaseEntity](
        mappings: ((T) => (_, Mapping[_]))*)(
            implicit context: ActivateContext,
            m: Manifest[T]): EntityForm[T] =
        build(mappings.toList)

    private def build[T <: BaseEntity](mappings: List[(T) => (_, Mapping[_])])(implicit context: ActivateContext, m: Manifest[T]): EntityForm[T] = {
        val mock = StatementMocks.mockEntity(erasureOf[T])
        val map = mappings.map(_(mock)).toList.asInstanceOf[List[(Any, Mapping[Any])]]
        val stack = StatementMocks.fakeVarCalledStack.reverse.distinct
        require(stack.size == map.size)
        val properties =
            for (i <- 0 until map.size) yield {
                val property = stack(i).name
                val mapping = map(i)._2
                map(i)._2.withPrefix(property)
            }
        implicit val entityMetadata = EntityHelper.getEntityMetadata(erasureOf[T])
        val mapping = new EntityMapping(properties.toList)
        new EntityForm(mapping)
    }
}

case class EntityMapping[T <: BaseEntity](
    val properties: List[Mapping[_]],
    val key: String = "",
    val constraints: Seq[Constraint[MutableEntityMap[T]]] = Nil)(
        implicit context: ActivateContext,
        m: Manifest[T],
        entityMetadata: EntityMetadata)
        extends Mapping[MutableEntityMap[T]]
        with ObjectMapping {

    def bind(data: Map[String, String]) = {
        val results = properties.map(e => (e.key, e.bind(data)))
        merge(results.map(_._2): _*) match {
            case Left(errors) => Left(errors)
            case Right(values) => {
                require(values.size == results.size)
                val data =
                    for (i <- 0 until results.size)
                        yield (results(i)._1, values(i))
                applyConstraints(new MutableEntityMap(data.toMap))
            }
        }
    }

    def unbind(value: MutableEntityMap[T]) = {
        val data = value.values
        val res =
            (for ((key, value) <- data)
                yield properties.find(_.key == key).map(_.asInstanceOf[Mapping[Any]].unbind(value))).flatten
        res.foldLeft(
            (Map[String, String](), Seq[FormError]()))(
                (t1, t2) => (t1._1 ++ t2._1, t1._2 ++ t2._2))
    }

    def withPrefix(prefix: String) =
        addPrefix(prefix).map(newKey => this.copy(key = newKey)).getOrElse(this)

    def verifying(addConstraints: Constraint[MutableEntityMap[T]]*) = {
        this.copy(constraints = constraints ++ addConstraints.toSeq)
    }

    val mappings = Seq(this) ++ properties

}

class EntityFormatter[T <: BaseEntity](
    implicit context: ActivateContext,
    m: Manifest[T])
        extends Formatter[T] {

    override val format = Some("format.entity", Nil)

    def bind(key: String, data: Map[String, String]) = {
        stringFormat.bind(key, data).right.flatMap { s =>
            scala.util.control.Exception.allCatch[T]
                .either {
                    val id = EntityId.stringToId[T#ID](m.erasure, s)
                    context.byId[T](id).get
                }.left.map(e => Seq(FormError(key, "error.entity", Seq(s))))
        }
    }

    def unbind(key: String, value: T) = Map(key -> EntityId.idToString[T#ID](m.erasure, value.id))
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy