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.
Related
I know the basic principle of Restful API design. I just want to know what I'm gonna do it with Grails3 URL mapping against multiple search actions.
I created the grails(3.3.9) app with the profile rest-API. The default UrlMapping.groovy looks like this.
class UrlMappings {
static mappings = {
delete "/$controller/$id(.$format)?"(action:"delete")
get "/$controller(.$format)?"(action:"index")
get "/$controller/$id(.$format)?"(action:"show")
post "/$controller(.$format)?"(action:"save")
put "/$controller/$id(.$format)?"(action:"update")
patch "/$controller/$id(.$format)?"(action:"patch")
"/"(controller: 'application', action:'index')
"500"(view: '/error')
"404"(view: '/notFound')
}
}
Domain Class Example
class ProductSanpshot {
String id
Float price
String name
}
class Order {
String id
String status
Float totalPrice
User createdBy
List<ProductSanpshot> ProductSanpshots
String remark
Date dateCreated
}
class User {
String id
String name
}
Controller Example
class OrderController {
def index() {
respond(Order.list())
}
def show() {
respond(Order.get(params.id))
}
}
Based on the URL mapping set which satisfies the basic principle of the Restful design:
When I access /order it would return the order list.
When I access /order/1 it would return the order detail with id value 1.
My questions are:
Normally, we just don't get the order full list but with different parameters.
How can I map the URL to retrieve the order within a particular price range?
The normal implementation would look like this:
class OrderController {
def index() {
respond(Order.list())
}
def show() {
respond(Order.get(params.id))
}
def getByPriceRange() {
def minPrice = params.float("minPrice")
def maxPrice = params.float("maxPrice")
def result = Order.findAllByTotalPriceBetween(minPrice, maxPrice)
respond(result)
}
}
I would access order/getByPriceRange?minPrice=100&maxPrice=200.
I know this might not be so restful.
For default Grails url mapping I will get 404 error. It only maps http get to two actions to each controller. The index and show. And I don't think I have to map each controllers' actions one by one explicitly.
get "/$controller(.$format)?"(action:"index")
get "/$controller/$id(.$format)?"(action:"show")
The other scenarios are:
Get the orders by the status.
Get the order's all product snapshots.
Update the order's status
Update the order's remark
What should I do with the UrlMapping to fulfill these needs by the restful way?
Thanks in advance.
I think you are wrong about that and the url is still restful. Since it is a get request, you have to send your parameters in url. And it is good for several reasons. For example when you add that url to bookmarks, you will get the same result with the desired data without any problem (Especially if this url referring to a page). For my projects I am using National Bank of Belgium's rest api design guide. This was the most detailed guide that I can find and I really like it. You can see that they are using limit and offset parameters for pagination and sort parameter for sorting. In your example it is more like a search operation. Of course there are a lot of approach and I know about pretty much all of them but I really like their approach. I use FIQL for the searches. You can read about it Search/Advanced search section. I don't want to use different parameters for search so I use it like :
someUrl?q=minPrice=gt=10;maxPrice=lt=50
Could not find any library that I like so I wrote my own parser to resolve that. Anyway these are my opinions and as I can see there is no standard for these. I hope it helps and free free to ask anything. Cheers !!
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.
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
Suppose i have a repository that returns a list of Posts. The repository interface has a GetAll() method which does what it suggests.
Now in keeping with the theory that i shouldn't be putting domain logic in the repository, i want to intercept calls to the concrete GetAll() method such that i can add the following logic to the GetAll() result:
return GetAll().OrderByDescending(p => p.Posted).ToList();
The reason i want to intercept this is because (1) i don't want to have the client remember to call an extension method (OrderByDescending or some useless wrapper of that), i want it called every time and (2) i don't want to have all my concrete implementations have to remember to order the GetAll() result - i want this logic in a single place external to any repository.
What's the easiest way to do this?
I'm already using StructureMap so if i can intercept with this it might be a low cost option. But i don't think SM intercepts method calls, just the creation of the object instance?
Do i need to go to a proxy or mixin pattern? Do i need to go all-in with Castle Dynamic Proxy? Or is there another method i should consider or perhaps a combination?
I'm really interested in a concrete suggestion to my particular example above. I'm novice to AOP so please be gentle.
Went with the DynamicProxy option. It was easier to use than i thought.
All it took was the using Castle.DynamicProxy; reference...
A bit of IInterceptor...
public class PostRepoInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
if (invocation.Method.Name.Equals("GetAll", StringComparison.InvariantCultureIgnoreCase))
invocation.ReturnValue = this.GetModifiedGetAllResult(invocation.ReturnValue);
}
private object GetModifiedGetAllResult(object getAllResult)
{
return Post.GetOrderedPosts((IList<Post>)getAllResult);
}
}
Two new lines in StructureMap config:
public RepoRegistry()
{
var pg = new ProxyGenerator();
For<IPostRepository>()
.EnrichAllWith(z => pg.CreateInterfaceProxyWithTarget<IPostRepository>(z, new PostRepoInterceptor()));
}
..and it's done. GetAll() now behaves how i want. I can still use the interfaces the way i'm familar and i've kept it all DRY and decoupled for DDD.
Thanks to Sam and Andre.
AFAIK, StructureMap only intercepts object construction, so using it it's not going to work.
I don't know Castle, but I think that the idea - here - is to apply Decorator pattern, so you could also do it by yourself without recurring to a third party library by following the steps described in the previous link.
That's how I'd do it, since I'm not a big fan of AOP.
HTH
No, it can not change the return value. However, you can access the target inside aspect to change target's property. Assuming you has already Repository defined, here is the code to add post processing aspect to change target property.
IRepository<decimal> Rep = new Repository();
IRepository<decimal> tpRep = (IRepository<decimal>)ObjectProxyFactory.CreateProxy(Rep,
new String[] { "GetAll" },
null,
new Decoration((x, y) =>
{
Console.WriteLine("Entering " + x.GetType().ToString());
if (x.GetType().ToString() == "ThirdPartyHR.Repository")
{
List<decimal> decimals = ((Repository)x).RepList;
IEnumerable<decimal> query = decimals.OrderByDescending(num => num, new SpecialComparer()).ToList<decimal>();
((Repository)x).RepList = (List<decimal>)query;
}
}, null));
tpRep.GetAll();
List<decimal> lstRep = Rep.RepList;
If needed, I can send you complete working code. And, if possible, please reply to me from the article "Add Aspects to Object Using Dynamic Decorator" since I don't automatically get the message here.
There is an article Add Aspects to Object Using Dynamic Decorator.
It describes an approach to adding aspects to object at runtime instead of adding aspects to class at design time. Looks like that is what you want.
O.K. I think that's an easy one!
I have a ViewMasterPage with some links on it (Home/About/Login/ etc). What I want to achieve is simply have the link disabled when it's referral url is already opened (i.e. if the current url is /Register then the Register link should be disabled .. easy hah!?)
As I don't like to write a lot of in-line coding inside of my views, I end up extending HtmlHelper with some extension methods (just to keep the code in .cs files) and in my views I call these methods, here's my register method as an example:
public static string Register (this HtmlHelper html)
{
TagBuilder builder ;
if (HttpContext.Current.Request.Url.AbsoluteUri.ToUpperInvariant().Contains(MainLinks.Register.ToUpperInvariant()))
return MainLinks.Register; // will return the string "Register"
builder = new TagBuilder("a");
builder.InnerHtml = MainLinks.Register;
builder.AddCssClass("register");
builder.Attributes.Add("href", "/register/");
return builder.ToString();
}
Though this works, it still has two problems:
The hard coded string values of the urls (specially for the home link as I compare the AbslouteUri with "http://www.mysite.com/")
My programming instinct doesn't like it, I feel it should be much simpler than that.
Any ideas!
Ps: No javascipt allowed! It's a javascript-free version of the application.
I don't see too much wrong with this, it's clear to see what it does and it works. However, it's probably better to make it a bit more reusable as I can imagine you repeat yourself a bit with the other links. Maybe something like:
public static string RenderLink(this HtmlHelper html, string text, string url, object htmlAttr) {
if (!HttpContext.Current.Request.Url.AbsolutePath.StartsWith(url, StringComparison.InvariantCultureIgnoreCase)) {
return text; //comparison excludes the domain
}
TagBuilder tag = new TagBuilder("a");
tag.SetInnerText(text);
tag.Attributes.Add("href", url);
//... add attributes parsed as htmlAttr here
return tag.ToString();
}
Then add your links to your view like:
<%= Html.RenderLink("Register", "/register/", new { #class="register"}) %>
<%= Html.RenderLink("Account", "/account/", new { #class="account"}) %>
If you wanted to get away from the hard coded domain, then using Request.Url.AbsolutePath instead of AbsoluteUri as above achieves that.
The alternative would be to parse the current page information in the model from the controller, maybe like ViewData.Model.CurrentPage = "Register";, but I wouldn't advise you doing that as I don't see it being the job of the controller in this case.