Reputation: 466
I'm using Grails 2.4.3 and I'm trying to create an dynamic Abstract Domain Class Controller that contains a few standard Methods, that can be used by every Domain Class.
So I created the DomainClassController
abstract class DomainClassController {
def domainClassSearchService
def domainClass = Foo
ApplicationContext context = ServletContextHolder.servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT) as ApplicationContext
ConfigObject config = context.getBean(GrailsApplication).config
def index() {
if (!domainClass)
return render(text: 'fehler', status: INTERNAL_SERVER_ERROR)
def list = domainClassSearchService.list(params, domainClass, params.max, params.offset, params.sort, params.order)
Integer count = domainClassSearchService.count(params, domainClass)
render view: 'index', model: [list: list, count: count]
}
def search() {
if (!domainClass)
return render(text: 'fehler', status: INTERNAL_SERVER_ERROR)
def list = domainClassSearchService.list(params, domainClass, params.max, params.offset, params.sort, params.order)
Integer count = domainClassSearchService.count(params, domainClass)
render template: 'list', model: [list: list, count: count, params: params]
}
}
Now I want an BarController
that extends the DomainClasscontroller
:
class BarController extends DomainClassController {
def domainClass = Bar
}
How can I set the domainClass in each Controller that the abstract controller can use it for the index and search method?
EDIT
I did it like it's described in the answer to get it work. But now I want to make the create Method dynamic so I added this:
def create(){
def domainClassObject = getDomainClass()?.newInstance()
domainClassObject.properties = params
return render(view: getViewPath() + 'create', model: [domainClass: domainClassObject])
}
This work also at itself but I don't want to use in the GSP the property domainClass
. I want to use the Class name in Lower Cas so f.e. foo
for class Foo
and bar
for the Class Bar
in the view.
How can i set the model name to the ClassName in lowerCase?
Upvotes: 0
Views: 401
Reputation: 27255
You could do this the same way that RestfulController
does. See https://github.com/grails/grails-core/blob/v2.5.4/grails-plugin-rest/src/main/groovy/grails/rest/RestfulController.groovy.
A Class
property named resource
is defined at https://github.com/grails/grails-core/blob/d45c00be6d8fdcce3edd21e16b50e30df9151b58/grails-plugin-rest/src/main/groovy/grails/rest/RestfulController.groovy#L37. The newInstance()
method is invoked on that Class
to create a new instance. See https://github.com/grails/grails-core/blob/d45c00be6d8fdcce3edd21e16b50e30df9151b58/grails-plugin-rest/src/main/groovy/grails/rest/RestfulController.groovy#L267.
class RestfulController<T> {
Class<T> resource
String resourceName
String resourceClassName
boolean readOnly
// ...
RestfulController(Class<T> resource) {
this(resource, false)
}
RestfulController(Class<T> resource, boolean readOnly) {
this.resource = resource
this.readOnly = readOnly
resourceClassName = resource.simpleName
resourceName = GrailsNameUtils.getPropertyName(resource)
}
// ...
/**
* Lists all resources up to the given maximum
*
* @param max The maximum
* @return A list of resources
*/
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond listAllResources(params), model: [("${resourceName}Count".toString()): countResources()]
}
/**
* Creates a new instance of the resource. If the request
* contains a body the body will be parsed and used to
* initialize the new instance, otherwise request parameters
* will be used to initialized the new instance.
*
* @return The resource instance
*/
protected T createResource() {
T instance = resource.newInstance()
bindData instance, getObjectToBind()
instance
}
/**
* List all of resource based on parameters
*
* @return List of resources or empty if it doesn't exist
*/
protected List<T> listAllResources(Map params) {
resource.list(params)
}
/**
* Counts all of resources
*
* @return List of resources or empty if it doesn't exist
*/
protected Integer countResources() {
resource.count()
}
}
Upvotes: 1
Reputation: 9885
You can set the domain class in each controller (subclass), and make it accessible to the abstract class, by implementing it as an abstract method:
DomainClassController.groovy
abstract class DomainClassController {
def domainClassSearchService
ApplicationContext context = ServletContextHolder.servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT) as ApplicationContext
ConfigObject config = context.getBean(GrailsApplication).config
abstract Class getDomainClass()
def index() {
if (!domainClass)
return render(text: 'fehler', status: INTERNAL_SERVER_ERROR)
def list = domainClassSearchService.list(params, domainClass, params.max, params.offset, params.sort, params.order)
Integer count = domainClassSearchService.count(params, domainClass)
render view: 'index', model: [list: list, count: count]
}
def search() {
if (!domainClass)
return render(text: 'fehler', status: INTERNAL_SERVER_ERROR)
def list = domainClassSearchService.list(params, domainClass, params.max, params.offset, params.sort, params.order)
Integer count = domainClassSearchService.count(params, domainClass)
render template: 'list', model: [list: list, count: count, params: params]
}
}
BarController.groovy
class BarController extends DomainClassController {
Class getDomainClass() {
Bar
}
}
Upvotes: 1