GRAILS: Can I call service logic from _FORM.GSP template? - templates

I'm refactoring scaffolding templates and I hit a wall with this issue:
I was trying to call service (some security logic) from template _FORM.GSP - but in the code part, not in the output part
I've read and tried what was suggested in here: How do I call a Grails service from a gsp?
I've tried to use taglib, but my knowledge of grails may not be extensive enough for that
I've tried add import and def to the beginning of _FORM.GSP file (both grailsApplication and application instantiation of service were crashing on missing property application resp. missing property grailsApplication)
I've even tried to call the taglib from the code both directly as method isAllowedToEdit and also as g.isAllowedToEdit both crashing on unknown method resp. "no such property g"
it seems that template _form.gsp has different rules than standard gsp view
I want to do something like this:
private renderFieldForProperty(p, owningClass, prefix = "") {
boolean hasHibernate = pluginManager?.hasGrailsPlugin('hibernate')
boolean display = true
boolean required = false
if (hasHibernate) {
cp = owningClass.constrainedProperties[p.name]
display = (cp ? cp.display : true)
required = (cp ? !(cp.propertyType in [boolean, Boolean]) && !cp.nullable && (cp.propertyType != String || !cp.blank) : false)
}
/* trying to do this part */
// I want to assign value to cp.editable - so later I can render read-only fields in renderEdit
if (!mySecurityService.canEdit(springSecurityService.currentUser, owningClass.getClass(), actionName, p.name)) {
cp.editable = false
}
/* trying to do this part */
if (display) { %>
<div class="fieldcontain \${hasErrors(bean: ${propertyName}, field: '${prefix}${p.name}', 'error')} ${required ? 'required' : ''}">
<label for="${prefix}${p.name}">
<g:message code="${domainClass.propertyName}.${prefix}${p.name}.label" default="${p.naturalName}" />
<% if (required) { %><span class="required-indicator">*</span><% } %>
</label>
${renderEditor(p)}
</div>
<% } } %>
if there is any way to assign cp.editable - I'll try your suggestions

it seems that template _form.gsp has different rules than standard gsp view
The generated _form.gsp works same as other gsps but the template inside the scr/templates/scaffolding/ is different. Customizing the templates like you are doing is a bit more tricky. Keep in mind that the logic you are writing is for Grails on how to generate views(gsp). Meaning you are telling Grails to check some logic before generating the views in memory or in the file. You might be able to accomplish that to some extend for dynamic (in memory) scaffolding at run-time but for sure not for static scaffolding. That's because Grails
is not aware of currentUser when generating the templates.
Your problem will be much simpler if you generate your views and then customize them instead of modifying their templates. Then you can inject your services and do other checks. However, as you also mentioned those logics are better off in a tag library here.
Also since you mentioned security, rendering a field non-editable does not guaranty inability to edit your fields. I would suggest to put the check logic inside your controller for example in SAVE or UPDATE action to prevent any unauthorized user editing fields.

Did you try this?
<%# page import="com.myproject.MyService" %>
<%
def myService = grailsApplication.classLoader.loadClass('com.myproject.MyService').newInstance()
%>
this will work for sure.
go through this link : click here

Related

Camunda Custom Form Field Type

We are implementing Camunda on our application and we have a problem with forms
We need to implement our own form field type. We use the Camunda Modeler and use the custom type in the Type attribute of the field but when we try to deploy the war we always see the same error
ENGINE-16004 Exception while closing command context: ENGINE-09005 Could not parse BPMN process. Errors:
* unknown type 'file' [...]
We searched in the documentation but we don't see how to implement custom form field types
Any idea how to solve this?
Thanks in advance
You didn't provide much information on your project and how you try to use custom types in embedded? TaskForms.
Camunda has a nice example how to do this with embedded TaskForms here:
https://github.com/camunda/camunda-bpm-examples/tree/master/usertask/task-form-embedded-serialized-java-object
The custom type in generated forms is for types which can be rendered as the value of a single html input field, it is not useful to render complex structures like tables or multiple inputs for bean properties.
https://forum.camunda.org/t/camunda-custom-form-field-type/501 describes how the custom type works:
The custom type must extend AbstractFormFieldType, which provides mappings between model types and form display types, see DateTypeValue for an example. Then you must tell the bpmn engine about your custom type using ProcessEngineConfiguration.setCustomFormTypes() in a ProcessEnginePlugin which has access to the bpm engine configuration.
The generated form will render the form display type as a single input field, only alternatives are datepicker for date and select for enum, as you see in HtmlFormEngine#renderFormField:
if(isEnum(formField)) {
// <select ...>
renderSelectBox(formField, documentBuilder);
} else if (isDate(formField)){
renderDatePicker(formField, documentBuilder);
} else {
// <input ...>
renderInputField(formField, documentBuilder);
}
This is org.camunda.bpm.engine.impl.form.engine.HtmlFormEngine#renderInputField, it renders a single input:
protected void renderInputField(FormField formField,
HtmlDocumentBuilder documentBuilder) {
HtmlElementWriter inputField = new HtmlElementWriter(INPUT_ELEMENT, true);
addCommonFormFieldAttributes(formField, inputField);
String inputType = !isBoolean(formField) ? TEXT_INPUT_TYPE : CHECKBOX_INPUT_TYPE;
inputField.attribute(TYPE_ATTRIBUTE, inputType);
// add default value
Object defaultValue = formField.getDefaultValue();
if(defaultValue != null) {
inputField.attribute(VALUE_ATTRIBUTE, defaultValue.toString());
}
// <input ... />
documentBuilder.startElement(inputField).endElement();
}

How to add multiple forms Joomla 2.5 component

I am developing a joomla website which required some custom component to integrate manage portfolio, user profile etc. We downloaded one of the hello_world MVC component for joomla 2.5[http://docs.joomla.org/Developing_a_Model-View-Controller_Component/2.5/Introduction] and did necessary customization. First component worked well. But now we need a new component that is having multiple forms required to integrate.
Eg: Store types for one form, store details for another form, manage country/ state by another form.
In the default component having option for manage one form [add/edit/delete/view]. Here I tried to modify/replicate but I failed.
Can anyone suggest the architecture/ sample code to manage multiple forms [Add/edit/delete/view] in joomla 2.5 component creation.
Any help will be apreciate?
Supposing You're speaking of forms stored in the model/forms folder... You should try to override the getForm() function in your model, to call the right form. You should pass a 'layout' when calling the page and then get it in the model constructor.
May be so:
class YourComponentModelYourModel extends JModelAdmin{
public function __construct($config = array()){
switch(JRequest::getVar('layout')){
case 'firstlayout' : $this->form='firstform';
break;
case 'secondlayout' : $this->form='secondform';
break;
default : $this->form='defaultform';
}
parent::__construct($config);
}
...
public function getForm($data = array(), $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_yourcomponent.'.$this->form,$this->form,
array('control' => 'jform', 'load_data' => $loadData));
if (empty($form)){return false;}
return $form;
}
You must put a layout for each form in the views/YourView/tmpl folder and the form declaration must call the layout also :
<form action="<?php echo JRoute::_('index.php?option=com_yourcomponent&layout=firstlayout&id='.(int) $this->item->id); ?>"
method="post" name="adminForm" id="draw-form">

grails populating g:select from query

Trying to become a grails convert I have begun converting an existing application to Grails and Groovy. It works very well but I get stuck on the conversion of select tags.
I have a domain class:
package todo
class Person {
String ssn
String firstname
String familyname
String role
String emailname
String emailserver
...
When creating a new "todo" task an owner may be assigned from those persons in the system who are developers and I get this working (a fairly direct translation from PHP):
<select id="owner" name="owner">
<option>Noboby ...</option>
<g:each in="${Person.list()}">
<g:if test="${it?.role=='developer'}">
<option value="${it?.id}">${it?.firstname} ${it?.familyname}</option>
</g:if>
</g:each>
</select>
But every attempt to make it more "Grails-ish" fails. How can it be moulded into Grails v2.2.1 code? I spent hours reading, trying, failing.
If you woulkd like to make it more Grails style, you should perform all your logic within controllers \ services not in the view.
Assuming you have a view createTodo in the folder person and the PersonController, then modify your createTodo action like this:
class PersonController {
def createTodo() {
def developers = Person.findAllWhere(role: 'developer')
[developers: developers, ... /* your other values */]
}
}
So you don't need to handle with database operations in your view.
Next step is to use the g:select tag like this:
<g:select name="owner" from="${developers}" optionValue="${{'${it.firstName} ${it.familyName}'}}" noSelection="['null':'Nobody ...']" optionKey="id" value="${personInstance?.id}" />
Try this code:
<g:select optionKey="id" from="${Person.findAllByRole('developer')}" optionValue="${{it.fullName}}" value="${yourDomainInstance?.person?.id}" noSelection="['null':'Nobody']"></g:select>
And in your class:
class Person {
....
String getFullName(){
it?.firstname+' '+ it?.familyname
}
static transients = ['fullName']
....
}
See g:select tag for more details
Finally, I got it working as I want to and it works (almost) according to the #"Mr. Cat" solution. One little detail, though, 'it' does not exist in the class so the getFullName method had to become:
String getFullName(){
this?.firstname+' '+ this?.familyname
}
Up and working, thank you for all help.

Why use templates in Kohana?

I don't understand the purpose of using templates in Kohana. I see almost no difference in the process of building a view with a template controller vs a regular controller, except that the template controller is tied to a given template and so is less flexible. What are the advantages?
Building view with regular controller:
Class Controller_Hello extends Controller
{
public function action_index()
{
$view = View::factory('page');
$view->page_title = 'My Hello App';
$view->content = 'hello, world!';
$view->sidebar = View::factory('parts/sidebar');
$this->response->body($view);
}
}
Building view with template controller:
Class Controller_Hello extends Controller_Template
{
public $template = 'page';
public function action_index()
{
$this->template->page_title = 'My Hello App';
$this->template->content = 'hello, world!';
$this->template->sidebar = View::factory('parts/sidebar');
}
}
Controller_Template is just an example of how you can implement your own templating-system.
It is not ready-to-use solution (at least for my projects usually). Check this one controller (it is also not ready-to-use solution but possibly it will help you understand point of extending different controllers for different purposes): http://pastie.org/2563595
I am sure there are other, maybe better solutions for templating systems. But why am I using templates in Kohana?
Think about multiple pages, all based upon one layout/design scheme. So I build a template controller using a certain view, defining layout/design, defining content, header and footer "areas". In the template controller I am loading the CSS files and script files, setting the title and meta values of the website, because every single site is using these CSS/script files with the same meta values and title.
So in every Controller extending the template controller I don't need to load the CSS/script files anew, set the meta values and title etc... But I could change all these values, maybe add a CSS file only for a single site.
Maybe all the mentioned sites have the same footer and/or header: I assign the header/footer view to the template within the template controller, so I don't need to do that in all the controller extending the template controller. Or all actions in one controller have the same header/footer, so I assignt he header and footer few in the before() function of the controller...
For me templates in kohana are a good utility for building small web applications.

Adding a search box to filter a list of results in Symfony?

I need to put a search box within a list of objects as a result of a typical indexSuccess action in Symfony. The goal is simple: filter the list according to a criteria.
I've been reading the Zend Lucene approach in Jobeet tutorial, but it seems like using a sledge-hammer to crack a nut (at least for my requirements).
I'm more interested in the auto-generated admin filter forms but I don't know how to implement it in a frontend.
I could simply pass the search box content to the action and build a custom query, but is there any better way to do this?
EDIT
I forgot to mention that I would like to have a single generic input field instead of an input field for each model attribute.
Thanks!
I'm using this solution, instead of integrating Zend Lucene I manage to use the autogenerated Symonfy's filters. This is the way i'm doing it:
//module/actions.class.php
public function executeIndex(sfWebRequest $request)
{
//set the form filter
$this->searchForm = new EmployeeFormFilter();
//bind it empty to fetch all data
$this->searchForm->bind(array());
//fetch all
$this->employees = $this->searchForm->getQuery()->execute();
...
}
I made a search action which does the search
public function executeSearch(sfWebRequest $request)
{
//create filter
$this->searchForm = new EmployeeFormFilter();
//bind parameter
$fields = $request->getParameter($this->searchForm->getName());
//bind
$this->searchForm->bind($fields);
//set paginator
$this->employees = $this->searchForm->getQuery()->execute();
...
//template
$this->setTemplate("index");
}
It's important that the search form goes to mymodule/search action.
Actually, i'm also using the sfDoctrinePager for paginate setting directly the query that the form generate to get results properly paginated.
If you want to add more fields to the search form check this :)
I finally made a custom form using the default MyModuleForm generated by Symfony
public function executeIndex {
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
but displaying only a custom field:
<div id="search_box">
<input type="text" name="criteria" id="search_box_criteria" value="Search..." />
<?php echo link_to('Search', '#my_module_search?criteria=') ?>
</div>
Then I created a route named #my_module_search linked to the index action:
my_module_search:
url: my_module/search/:criteria
param: { module: my_module, action: index }
requirements: { criteria: .* } # Terms are optional, show all by default
With Javascript (jQuery in this case) I append the text entered to the criteria parameter in the href attribute of the link:
$('#search_box a').click(function(){
$(this).attr('href', $(this).attr('href') + $(this).prev().val());
});
And finally, back to the executeIndex action, I detect if text was entered and add custom filters to the DoctrineQuery object:
public function executeIndex {
...
// Deal with search criteria
if ( $text = $request->getParameter('criteria') ) {
$query = $this->pager->getQuery()
->where("MyTable.name LIKE ?", "%$text%")
->orWhere("MyTable.remarks LIKE ?", "%$text%")
...;
}
$this->pager->setQuery($query);
...
// Add a form to filter results
$this->form = new MyModuleForm();
}
Actually, the code is more complex, because I wrote some partials and some methods in parent classes to reuse code. But this is the best I can came up with.