Use object in Route with PlayFramework : Reverse routing - binding

Is it possible to generate an url mapped by an object ?
The Pojo Object Mapping is a native function of PlayFramework (1.2.2), but what about the reverse routing?
I would like to do this :
Java:
class MyControler extends Controller {
public static function myAction(MyObject o) {}
}
Route: (something like this ? If it's possible, i don't know the syntax to do it !)
GET /folder/{myObject.name}/{myObject.id} MyController.myAction(myObject)
Template :
Go
Expected result :
Go
(I have a Symfony background, and I search an equivalent to the Object Route Class)
I think Play! don't support this functionnaly, could someone confirm or refute this idea?
Thank you.

What you’re asking for is not currently possible.
So the usual workaround is this pattern:
GET /folder/{id} MyController.myAction
class MyController extends Controller {
public static void myAction(Long id) {
MyObject o = MyObject.findById(id);
// You may probably want to add the following line:
notFoundIfNull(o);
// … then your code here
}
}
The solution is not so verbose, but I agree that further version of Play! should allow a more simple syntax, similar to what you suggested.

Well, if it is going to work, it will need the package declaration :
GET /folder/{models.myObject.name}/{models.myObject.id}

According to Julien Richard-Foy, there is no solution.
So I propose a workaround, a little ugly because the route will be describe twice.
This quick solution breaks the MVC model, but it's possible to do otherwise, sending a UrlHelper to the template for exemple.
In your model, add a generateUrlDetail() method :
public String generateUrlDetail() {
return String.format("/myRoute/%s/%d-%s.html", JavaExtensions.slugify(this.foo.name), this.id, JavaExtensions.slugify(this.bar));
}
Tips : Play! allows to define a route with more identifiers than necessary. So it's possible to write a route with 2+ variables, but only the ID will be used in the action.
GET /myRoute/{foo}/{<[0-9]+>id}-{bar}.html Foo.detail(id)
And in your template :
Go
Render : Go
And it works :)

Try this approach. Bind with the id of the object. Works for me
Go

Related

Laravel 4: how to inject another class in a eloquent model

I'm trying to use the built-in laravel's Ioc container to inject a PageManager class inside a Page model and I'm a little lost.
What I'm trying to achieve is something like that:
class Pages extends Eloquent {
public function __construct(PagesManagerInterface $manager, array $attributes = array())
{
parent::__construct($attributes);
$this->manager = new $manager;
}
public function saveToDisk()
{
$this->manager->writeToFile();
}
But I obtain this error:
ErrorException: Argument 1 passed to Pages::__construct() must be an instance of PagesManagerInterface, none given.
I tried to add this in app/start/global.php:
App::bind('Pages',function(){
return new Pages(new PagesManager);
});
But is seems ignored by the framework, and also i don't know how to insert the $attribute array into this declaration.
I'm a little lost so any help is appreciated!
It's not a good idea to overload a model's constructor because new instances can be spawned behind the scenes through various methods, like Model::find().
When that happens, the dependencies you're asking for in your custom constructor aren't being passed in because the Model class isn't aware of them. So, you get that error message.
See the find() method here: http://laravel.com/api/source-class-Illuminate.Database.Eloquent.Model.html#380-397
See this post by Jason Lewis: http://forums.laravel.io/viewtopic.php?pid=47124#p47124
I think that what you need is:
App::bind('PagesManagerInterface',function(){
return new Pages(new PagesManager);
});
This tells Laravel to inject a new Page object everytime it needs an instance of your PagesManagerInterface wich wasn't passed while creating the model.
In Laravel you can use the IoC Container:
public function saveToDisk(){
$managerObject = app()->make('path\to\class\PagesManagerInterface');
$managerObject->writeToFile();
}

Is there simple way to use bookmarks in controller action's generated urls?

Currently I am working with simple Forum module in ASP.NET MVC 3 which i will add later to my main application. The possibility to link to certain blocks like div used to present thread replies is very useful.
I figured out something which work and propably will be enough for my needs, I just wonder if there is something more elegant and simple aswell. I found a solution using ActionFilters, and since I'm quite begginner in MVC I would like to find some easier solution (if exists). Well i will propably learn ActionFilters soon aswell :)
So here is what I've done:
public ActionResult ShowThread(int id, int? postID)
{
var thread = db.ForumThreads.Find(id);
if (postID != null)
{
return Redirect(Url.Action("ShowThread",new {id=id})+"#post-"+postID.ToString());
}
return View(thread);
}
I know it is quite simple, but it is working. Also it doesn't check if the postID is valid yet, but it is not a part of question.
The solution is to use one of RedirectToAction overloads: http://msdn.microsoft.com/en-us/library/dd470154(v=vs.108).aspx.
Perhaps, in your case, the next one would do: http://msdn.microsoft.com/en-us/library/dd460291(v=vs.108).aspx
And the call would be:
return this.RedirectToAction("ShowThread", new { id = id, post = postID });
Another (simpler, but not safer!) solution is to format the URL you need to redirect to and to use the Redirect() method like this:
var redirectUrl = string.Format("/Home/ShowThread/{0}?post={1}", id, postID);
return this.Redirect(redirectUrl);
Pay attention to your URL mappings, though. The examples above assume the method
public ActionResult ShowThread(int id, int? post)
is in HomeController and the default route has not been changed. Otherwise you should
adjust the URL prepending the controller name (w/o Controller), or
change your default route to map to the controller's name.

How can I create a binding in Ninject that changes based on the requested controller?

I have an ASP.NET MVC 3 app, and have run into the following situation. On my page, I have a side bar, which can contain related links specific to that page, i.e., determined by controller type. The links will be determined by the current page's content.
I have followed Phil Haack's blog post on rendering dynamic side bars such as this using Html.Action and a separate controller. I like the separation of concerns this approach gives me: my controllers don't know anything about the side bar at all, which is the way it should be.
I now want to inject an instance of a derived type of SideBar into my SideBarController, an action on which will be called to render the side bar itself. There is one derived type of SideBar per controller, and so I find myself wanting to write code similar to this:
kernel.Bind<SideBar>().ToMethod(_ => controllerName == "foo"
? new FooSideBar(kernel.Get<UrlHelper>())
: new BarSideBar(kernel.Get<UrlHelper>()));
but there's quite a lot that is wrong about that fragment of code, not least the fact that I can't get hold of the controller name in the lambda, and the question of what happens when a third type of controller comes along, and then a fourth, etc.
Note that I can't use WhenInjectedInto<T>(), as the SideBar instance will always be injected into the SideBarController.
For what it's worth, the instances of SideBar are currently being created via the Ninject Factory extension, so the relevant side bar bindings are as follows (I've hard-bound an implementation of SideBar just to prove the approach so far works):
kernel.Bind<ISideBarFactory>().ToFactory().InRequestScope();
kernel.Bind<SideBar>().To<FooSideBar>().InRequestScope();
Finally, I essentially have a one-to-one mapping between the derived types of SideBar and the controller types. It feels a little bit like there might be a bit of duplication here, but also it represents the relationship between the components, so I think I'm ok with it.
This all makes me think that my approach to this part of the problem is wrong, and so I would welcome suggestions on how to achieve a clean solution with Ninject.
I'll have a go at answering, but I'm not near a computer at the moment, and so it'll be a bit vague.
Fundamentally, you can pass another parameter to Html.Action, so if that parameter is either the Request or something gleaned from the Request (such as the controller name or Url parts) then you can use that to determine which sidebar to show. You may need to inject the factory into the sidebar controller, and use it to create the correct controller, or some other fiddling about, but once you know which sidebar is required, it becomes much easier.
I am not sure if this is possible using ninject but it is using ModelBinding like so:
public interface ISidebar
{
}
public class Sidebar1 : ISidebar
{
}
public class Sidebar2 : ISidebar
{
}
public class SidebarModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var controller = controllerContext.RouteData.Values["Controller"];
var action = controllerContext.RouteData.Values["Action"];
switch (controller.ToString())
{
case "Home":
return new Sidebar1();
default:
return new Sidebar2();
}
throw new NotImplementedException();
}
}
public class TestController : Controller
{
public TestController()
{
}
public string Index(ISidebar sidebar)
{
//Do something with it
return "OK";
}
}
//Add to the Application_Start
ModelBinders.Binders.Add(typeof(ISidebar), new SidebarModelBinder());
EDIT: Took me a while, but managed to get it working using Ninject.
Please read it at: http://blog.voltje.be/2012/08/22/creating-a-dynamic-sidebar-with-asp-net-mvc-ninject/
Suggestion:
Don't inject sidebar.
Instead inject [sidebar]ContentProvider.
Bind a default implementation in global asax (per request), then unbind and rebind if needed in the controller.

Nice URL in CodeIgniter

does anybody knows how i can get nice url`s in CodeIgniter like this: examplepage.com/sites/my-new-project instead of examplepage.com/sites/2
The last segment in the URI can be a title oder an other custom string.
Please help me ;)
Regards,
Peter
CI's URLs are "nice" by default - you choose what they are.
Based on the idea of segments, CI has:
controller/method/params
So for instance:
class Article extends CI_Controller {
function __construct()
{
parent::__construct();
}
function index()
{
// blah
}
function read($article=null)
{
// display article
}
}
You can then produce links like:
site.com/article/read/my-article-title
my-article-title would be a URL slug stored in your database, which the read method will look up and return the appropriate content.
The other way as suggested is routing, but hey, the functionality is built right there so you may as well use it.
You can use routing.php for this, to set up a custom route.
http://codeigniter.com/user_guide/general/routing.html
Good luck.

T4MVC and named parameters

I'm running into an error with T4MVC and named parameters. I have a controller:
public class ProductsController : Controller
{
public virtual ViewResult List(int page = 1)
{
// foo.DoSomething()
}
}
It seems T4MVC creates an overload List() as well. The result is that calling
myProductsController.List(3)
correctly executes foo.DoSomething(). But calling
myProductsController.List()
does NOT execute foo.DoSomething() - T4MVC created an empty List() overload.
I've taken T4MVC out of my project, and everything works fine now. But I'd really like to be able to use it - am I missing a setting somewhere?
UPDATE: Ok, I have a real fix now. It's checked into the Codeplex repository. You can get the latest T4MVC.tt by going to here. Before I include that in the next official build, it would be great if you could try it and confirm that it works for you. Thanks!
You're right, there is a problem here. I had not run into this situation before. For a short term quick fix, just get rid of the following code from T4MVC.tt (around line 370):
<#foreach (var method in controller.ActionMethodsUniqueWithoutParameterlessOverload) { #>
[NonAction]
[<#= GeneratedCode #>, DebuggerNonUserCode]
public <#=method.ReturnTypeFullName #> <#=method.Name #>() {
return new T4MVC_<#=method.ReturnType #>(Area, Name, ActionNames.<#=method.ActionName #>);
}
<#} #>
But I'll need to look for a real fix. Normally, this generation happens when the action has no no-param overload. It just needs to detect that an action with all-optional params should basically be treated as a no-param case.

Resources