grails - subdomain based projects and links - grails

I am trying to develop a grails application that has "root" content (www.mydomain.com/about for example) but will also support "projects" based upon the subdomain of the request; for example myproject.mydomain.com > www.mydomain.com/myproject. As a first pass, i have the URL configuration below:
"/$controller/$action?/$id?" {
...
}
"/$project/$controller/$action?/$id?" {
constraints {
}
}
The main drawback so far is that the $project variable must be injected manually into every link (tedious and not DRY):
<g:link controller="foo" action="bar" params="${[project: params.project]}">link</g:link>
Is there a way to automatically inject the $project parameter into all links if it is present, or is there a better way to approach this problem?

Basically you can create a grails plugin that will inject into the controller a new project param with a value based on a custom TagLib <g:project bean="myproject"/> (for instance)
It will force you to define this tagLib on each gsp page of your project but it is still DRYer than each link.
Hope it helps,
Fabien.

I can think of a couple of things.
a) You can place a proxy (Apache or something else) in front of your app-server and do some url-rewriting. Bonus: This would also allow you to do some caching of static resources.
b) This solution is a little more technically interesting. You can look up the project based on the http host header (the subdomain part). This will save you from rewriting all urls, all Grails conventions will still apply so you shouldn't run into any problems with third party plugins and so on.

Related

Architecture of CMS on Top Symfony CMF

Im building a very custom CMS on top of Symfony CMF Components/Bundles. I read almost everything i could about the CMF Components/Bundles and i have the "architecture" kinda defined. Im experienced/familiarized with Symfony2 components.
The CMS should provide a way to manage multiple sites.
A Site contains Pages.
A Page, requires a title and may have content. A page can also have blocks associated(Those already provided by the Block Bundle, and others with custom functionality developed by me for the CMS).
For now i defined two Documents(Site and Page).
Based on the application requirements im using the CoreBundle, BlockBundle, RoutingBundle, DoctrinePHPCRBundle, and DoctrinePHPCRAdminBundle.
Based on this requirements the expected Repository Tree should be something like:
/sites
/site1 ( nodename of the Site Document )
/pages ( all pages of this site )
/page1 ( nodename of a Page Document )
/page2
/routes ( all routes of this site )
/site2
/pages
...
The configurations for CoreBundle:
cmf_core:
persistence:
phpcr:
basepath: /sites
enabled: true
Because i need nodes(/pages, /routes) for each site, how can i initialize them? My first idea was onPostPersist event of a Site document i initialize the required nodes.
use PHPCR\Util\NodeHelper;
...
public function initSiteNodes(ManagerRegistry $registry, Site $site)
{
$session = $registry->getConnection();
NodeHelper::createPath($session, $site->getId()./pages);
NodeHelper::createPath($session, $site->getId()./routes);
$session->save();
}
So my questions are:
Is this architecture feasible and is SonataAdminBundle prepared for such a structure?
Great to hear you are building a custom CMS on top of the CMF. This is one of the main intended use cases for it.
For your usecase, one important thing to note is that the route base paths can be an array of paths. If you know the sites that will exist, you can simply configure base paths for all of them.
If they can be dynamically created, you will need some more work. You could check if the expression language can help you, or write a symfony request listener that comes very early and sets the right base path on the cmf_routing.phpcr_candidates_prefix service.
The sonata phpcr-odm admin was not really optimized for multisite use cases. However, with the help of the permission system, you should be able to control who may see what.
You could also write to the symfony-cmf-users mailing list. A couple of people did multisite projects with the CMF and might have additional ideas or inputs. And feel free to open pull requests or issues on the corresponding CMF repositories if you see things that could be improved.

Different Views for same domain Object in Grails backend and frontend

I've got two grails projects (admin backend and frontend) using the same domain classes from a local plugin.
I need to have different views in the frontend and the backend. E.g. there's a domain class Event. In each of the projects I use GenerateViews. Then I modify the generated gsps. As an example take the list.gsp. In frontend I remove the actions to create a new event from the view and the Controller, in the backend I keep them. That's because in the frontend the users should be only able to see the list of events, while in the backend the admin creates and modifies what is displayed in the frontend. This is the structure I get:
project domain
domain/grails-app/domain/myapp/Event.groovy
project frontend (grails.plugin.location.'domain' = "../domain")
frontend/grails-app/controllers/myapp/frontend/EventController.groovy
frontend/grails-app/views/event/list.gsp (no links to edit / create action)
project backend (grails.plugin.location.'domain' = "../domain")
backend/grails-app/controllers/myapp/backend/EventController.groovy
backend/grails-app/views/event/list.gsp (links to edit/create...)
But when I run my frontend application using run-app, and go to list, the controller is called:
def listEvents(Integer max) {
params.max = Math.min(max ?: 10, 100)
[eventInstanceList: Event.list(params), eventInstanceTotal: Event.count()]
}
and as a result backend/grails-app/views/event/list.gsp is rendered instead of frontend/grails-app/views/event/list.gsp.
The confusion already begins when I'm generating the views. So when I generate views for domain/grails-app/domain/myapp/Event.groovy inside the backend project everything is fine. The views get created inside my backend projectand work as intended.
Then I move ober to the frontend project and generate views for domain/grails-app/domain/myapp/Event.groovy. This time grails will tell me that there already are views, and asks if I want to replace them. If I say yes, it doesn't replace anything, but create the views in my frontend project. Really weird.
I found that there is an older bug report related to this, and I created a new one (http://jira.grails.org/browse/GRAILS-9920).
In the meantime, what should I do to work around this? I could rename my controllers' methods and the views, but I hope that there's a better way. It seems odd, that a view by the same name may override a view in a separate project. Or does something like that only happen when using run-app?
I'm new to Grails, so maybe I missed something obvious, but this really scares me, since it looks like I might accidentally expose actions in one project by modifying the other.

Mvc4 bundling, minification and AngularJS services

Is there a way to customize the way Asp.Net MVC4 bundling&minification feature minifies the js files?
Meaning, I don't want to completely turn off minification, but "as is" it just breaks AngularJs.
Since AngularJs uses DI and IoC approach for injecting services in controllers, the following:
function MyController($scope) { }
Once minified, becomes:
function MyController(n) { }
Normally that wouldn't be a problem, but AngularJs uses the parameter names to understand which service to inject. So $scope should remain $scope, as well as any other parameter in angular controllers. Everything else, like local variables, etc, should be minified normally.
I can't find any clear documentation on how to configure Mvc4 minification, and it seems rather dumb for it to be "all or nothing" so I think I'm missing something.
Thanks.
Actually you can (and should!) write AngularJS code so it is "minification safe". Details are described in the "Dependency Annotation" section of http://docs.angularjs.org/guide/di but in short, for globally defined controllers you can write:
MyController.$inject = ['$scope'];
Please note that globally defined controllers are polluting global namespace (see this for more details) and should be avoided. If you declare a controller on a module level you can make it minification-safe as well:
angular.module('mymodule', []).controller('MyController', ['$scope', function($scope){
//controller code goes here
}]);
if you still want to control what to minify and what not (or if you want to include an already minified version by the plugin vendor) just declare two bundles, and only minify one of them on your BundleConfig.cs:
var dontMinify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/xxxxx.js");
bundles.Add(dontMinify);
var minify = new Bundle("~/bundles/toNotMinify").Include(
"~/Scripts/yyyyyy.js");
minify.Transforms.Add(new JsMinify());
bundles.Add(minify);
For those of you who don't want/can't be arsed to write the "minification-safe" angular-DI syntax, and don't care about variable names being obfuscated, I used BundleTransfomer along with Yui Js minifier - available via nuget:
Install-Package BundleTransformer.Core
Install-Package BundleTransformer.Yui
Gives VERY fine-grained control over minification/obfuscation. In the angular world, just set the obfuscateJavascript within the yui web.config section to false.

Urlmapping for camel case with more than one meaningful step

As we know, grails automatically maps MyController to [root]/my as expected, but if I have MyAnotherController it gets mapped to [root]/myAnother. I would like to get it mapped automatically to [root]/my/another.
Is there a way to do this without putting additional URL mapping directives to conf/UrlMappings.groovy?
There is an open JIRA related to this (placing controllers in sub folders/ packages). Go ahead and vote for it. I would love to see this implemented in Grails.
http://jira.codehaus.org/browse/GRAILS-1243

Scaffolding Web Services in Grails

I need to implement a web app, but instead of using relational database I need to use different SOAP Web Services as a back-end. An important part of application only calls web services and displays the result. Since Web Services are clearly defined in form of Operation: In parameters and Return Type it seems to me that basic GUI could be easily constructed just like in the case of scaffolding based on Domain Entities.
For example in case of SearchProducts web service operation I need to enter search parameters as input, so the search page can be constructed. Operation will return a list of products, so I need a page that will display this list in some kind of table.
Is there already some library in grails that let you achieve this. If not, how would you go about creating one?
Probably the easiest approach is to use wsimport on the WSDL files to generate the client-side stubs. Then you can call methods in the stubs from Groovy just as you would have called them from Java.
For example, consider the WSDL file for Microsoft's TerraServer, located at http://terraservice.net/TerraService.asmx?wsdl . Then you run something like
wsimport -d src -keep http://terraservice.net/TerraService.asmx?WSDL
which puts all the compiled stubs in the src directory. Then you can write Groovy code like
import com.terraserver_usa.terraserver.*;
TerraServiceSoap sei = new TerraService().getTerraServiceSoap()
Place home = new Place(city:'Boston',state:'MA',country:'US')
def pt = sei.convertPlaceToLonLatPt(home)
println "$pt.lat, $pt.lon"
assert Math.abs(pt.lat - 42.360000) < 0.001
assert Math.abs(pt.lon - -71.05000) < 0.001
If you want to access a lot of web services, generate the stubs for all of them. Or you can use dynamic proxies instead.
The bottom line, though, is to let Java do what it already does well, and use Groovy where it makes your life easier.
You should be able to use XFire or CXF Plugins. For automatic scaffolding, modify your Controller.groovy template in scaffolding templates so it auto-generates methods you need.

Resources