I am trying to create nice URL's for my Magento search form, to make:
http://domain.com/catalogsearch/result/?q=KEYWORD
look like this:
http://domain.com/search/KEYWORD
I have written this is my htaccess file:
RewriteRule ^search/([^/]+)/?$ /catalogsearch/result/?q=$1 [QSA,P,NC]
Which works nicely, when I type in http://domain.com/search/KEYWORD it displays the results as it should.
BUT...
I can't workout how to get my search form to go to the nice format URL, it still goes to the original.
My search form is currently like this:
<form id="search_form" action="http://domain.com/catalogsearch/result/" method="get">
<input id="search" type="search" name="q" value="KEYWORD" maxlength="128">
<button type="submit">search</button>
</form>
Any point in the right direction much appreciated.
There are a couple of things going on here, so let me try to explain the best I can.
First and foremost, your main issue is the generation of this new "pretty" search URL. When you use a <form> with method="GET", each input (i.e. <input name="q">) will get appended to the form's action as a query parameter (you'll get /search?q=foo instead of /search/foo).
In order to fix this, you need to do two things:
Change your form tag to look like this:
<form id="search_form" action="<?php echo Mage::getUrl('search'); ?>" method="GET">
This will ensure that the form is submitted to /search instead of /catalogsearch/result. (You'll still get a ?q=foo, though, and that will be resolved in #2.)
Add a bit of JavaScript which hijacks the form submission and forms the desired URL:
var form = document.getElementById('search_form'),
input = document.getElementById('search');
form.onsubmit = function() {
// navigate to the desired page
window.location = form.action + input.value;
// don't actually submit the form
return false;
};
That'll get you up and running, but there are still some other issues which you should resolve.
Using RewriteRule based rewrites with Magento does not work well. I haven't quite figured out the technical reason for this, but I've had the same trouble that you're having. The reason that your rewrite works with the P flag is because the P flag turns the rewrite into a proxy request. This means that your web server will make another request to itself with the new URL, which avoids the typical RewriteRule trouble you'd run into.
So, how do you utilize a custom pretty URL without using RewriteRule? You use Magento's internal rewrite logic! Magento offers regex-based rewrite logic similar to RewriteRule through its configuration XML:
<config>
<global>
<rewrite>
<some_unique_identifier>
<from><![CDATA[#/search/(.*)/?$#]]></from>
<to><![CDATA[/catalogsearch/result/index/q/$1/]]></to>
<complete />
</some_unique_identifier>
</rewrite>
</global>
</config>
By putting that configuration in one of your modules, Magento will internally rewrite requests of the form /search/foo to /catalogsearch/result/index/q/foo/. Note that you have to use Magento's custom parameter structure (name-value pairs separated by /), as it will not parse query string parameters after it performs this internal rewrite. Also note that you have to specify the full module-controller-action trio (/catalogsearch/result/index/) because otherwise q would be interpreted as an action name, not a parameter name.
This is much better than using a proxy request because it doesn't issue a secondary request, and the rewrite happens in Magento's core route handling logic.
This should be enough to get you completely up and running on the right path. However, if you're interested, you could take this one step further.
By using the above techniques, you'll end up with three URLs for your searches: /search/foo, /catalogsearch/result/?q=foo, and /catalogsearch/result/q/foo. This means that you essentially have three pages for each search query, all with the same content. This is not great for SEO purposes. In order to combat this drawback, you can create a 301 permanent redirect from the second two URLs to redirect to your pretty URL, or you can use a <link rel="canonical"> tag to tell search engines that your pretty URL is the main one.
Anyways, I hope that all of this helps and puts you on the right track!
Related
I would like to upgrade one of my joomla 2.5 plugin (self-developed). It is a complex task, but here is this specific issue I couldn't solve. I would like to put an input field with a submit button at my articles (done), and after submitting I want to get it. So simple.
Here is the outline of the code:
The form:
<form action="" method="post">
<input type="text" name="info">
<input type="submit" value="ok">
</form>
The process:
$jinput = JFactory::getApplication()->input;
$foo = $jinput->get('info', '444');
print_r($foo);
Basically it should work, but somehow I don't get the value, always recive the default value '444'. If I change the action to an external php file, and process in php-way, it works.
What I checked so far:
a. change form method to GET. Result: the needed value appears properly in the article's URL, but still print the default value '444' not the value I see in the URL (if the default value isn't set, it doesn't print anything).
b. pass the value to an external .php file, store in session, and echo the session value in the article, but empty again.
Maybe I will force to get the GET values by exploding the $_SERVER["REQUEST_URI"], but I can't sleep until I find out what could be wrong with desired process.
Anyone can help?
UPDATE: maybe important - I use K2 plugin.
So far I could figure out the following:
it is a special case. On my local server the code works fine both with normal joomla articles and K2 component articles.
on my website the code also works fine with normal joomla articles, so it is defenietly a K2 settigns-issue.
there was a chance the problem is related to K2 advanced SEF settings (specifies the url of the K2 item), but it isn't. The problem is on my website, so I used on my localhost-version the SEF settings of the website-version, and I recived the values fine. == not K2 advanced SEF settings problem.
This is the answer for my question: "should find which K2 setting is causing the problem"
UPDATE. Solution: turn off caching at global configuration, so the page isn't loading from cache. In cache are no given values stored - obbbbbviously.
I'm trying to set a class or id parameter on a <h:inputHidden> in JSF. The code looks like this:
<h:inputHidden value="#{getData.name}" class="targ" />
But in the browser, the class isn't set:
<input type="hidden" name="j_idt6" value="j_idt6">
I need to set a class to this parameter, because I have a JavaScript autocomplete function for a <h:inputText> that sets a value in the hidden input, which needs to be passed in the next page.
Any ideas? Thanks!
I know it's a little bit late, but it can help someone in the future.
As inputHidden shows nothing in the browser there's no sense to allow it to have a class.
You can use the Id but as the Id could change as you change the component parents using it would bring some headache.
I'd suggest as a workaround, you can give it a parent so you can manipulate it by javascript.
Exemple:
JSF
<h:panelGroup styleClass="someCssClass">
<h:inputHidden id="someId" value="someValue" />
</h:panelGroup>
Javascript (using jQuery, you could use pure javascript also)
$('.someCssClass input[type=hidden]').val('yourNewValue');
None of these answers here satisfied my needs (need the PrimeFaces component, need class not ID, wrapping is too much work), so here's what I came up with:
Use pass-through attributes: https://www.primefaces.org/jsf-2-2-pass-through-attributes
Use pass:hidden-class="blah" (in my case, it's xmlns:pass up top)
Use [attribute=value] selector:
https://www.w3schools.com/cssref/sel_attribute_value.asp
document.querySelector multiple data-attributes in one element
That basically boils down to using something like this (because h:inputHidden becomes a regular input): document.querySelector("input[hidden-class=" + blah + "]")
Please, see similar question - How can I know the id of a JSF component so I can use in Javascript
You can sed "id" property, but in final html code it can be not the same, but composite: for example, if your input with id="myhidden" is inside form with id="myform", final input will have id="myform:myhidden".
In the end, I used a standard HTML <input type="hidden"> tag, as I had no advantages for using the JSF one. If you're trying to set a value in a hidden input with JavaScript, I recommend using this workaround.
I have a service that takes an .odt template file and some text values, and produces an .odt as it's output. I need to make this service available via HTTP, and I don't quite know what is the most RESTful way to make the interface work.
I need to be able to supply the template file, and the input values, to the server - and get the resulting .odt file sent back to me. The options I see for how this would work are:
PUT or POST the template to the server, then do a GET request, passing along the URI of the template I just posted, plus the input values - the GET response body would have the .odt
Send the template and the parameters in a single GET request - the template file would go in the GET request body.
Like (2) above except do the whole thing as a single POST request instead of GET.
The problem with (1) is that I do not want to store the template file on the server. This adds complexity and storing the file is not useful to me beyond the fact that it's a very RESTful approach. Also, a single request would be better than 2, all other things being equal.
The problem with (2) is that putting a body in a GET request is bordering on abuse of HTTP - it is supported by the software I'm using now, but may not always be.
Number (3) seems misleading since this is more naturally a 'read' or 'get' operation than a 'post'.
What I am doing is inherently like a function call - I need to pass a significant amount of data in, and I am really just using HTTP as a convenient way of exposing my code across the network. Perhaps what I'm trying to do is inherently un-RESTful, and there is no REST-friendly solution? Can anyone advise? Thank you!
Wow, so this answer escalated quickly...
Over the last year or so I've attempted to gain a much better understanding of REST through books, mailing lists, etc. For some reason I decided to pick your question as a test of what I've learned.
Sorry :P
Let's make this entire example one step simpler. Rather than worry about the user uploading a file, we'll instead assume that the user just passes a string. So, really, they are going to pass a string, in addition to the arguments of characters to replace (a list of key/values). We'll deal with the file upload part later.
Here's a RESTful way of doing it which doesn't require anything to be stored on the server. I will use some HTML (albeit broken, I'll leave out stuff like HEAD) as my media type, just because it's fairly well known.
A Sample Solution
First, the user will need to access our REST service.
GET /
<body>
<a rel="http://example.com/rels/arguments" href="/arguments">
Start Building Arguments
</a>
</body>
This basically gives the user a way to start actually interacting with our service. Right now they have only one option: use the link to build a new set of arguments (the name/value pairings that will eventually be used to in the string replacement scheme). So the user goes to that link.
GET /arguments
<body>
<a rel="self" href="/arguments"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}">
<input id="input_string" name="input_string" />
</form>
</body>
This brings us to an instance of an "arguments" resource. Notice that this isn't a JSON or XML document that returns to you just the plain data of the key/value pairings; it is hypermedia. It contains controls that direct the user to what they can do next (sometimes referred to allowing the user to "follow their nose"). This specific URL ("/arguments") represents an empty list of key/value pairings. I could very well have named the url "/empty_arguments" if I wanted to: this is an example why it's silly to think about REST in terms of URLs: it really shouldn't matter what the URL is.
In this new HTML, the user is given three different resources that they can navigate to:
They can use the link to "self" to navigate to same resource they are currently on.
They can use the first form to navigate to a new resource which represents an argument list with the additional name/value pairing that they specify in the form.
They can use the second form to provide the string that they wish to finally do their replacement on.
Note: You probably noticed that the second form has a strange "action" url:
/arguments?{key}={value}
Here, I cheated: I'm using URI Templates. This allows me to specify how the arguments are going to be placed onto the URL, rather than using the default HTML scheme of just using <input-name>=<input-value>. Obviously, for this to work, the user can't use a browser (as browsers don't implement this): they would need to use software that understands HTML and URI templating. Of course, I'm using HTML as an example, your REST service could use some kind of XML that supports URI Templating as defined by the URI Template spec.
Anyway, let's say the user wants to add their arguments. The user uses the first form (e.g., filling in the "key" input with "Author" and the "value" input with "John Doe"). This results in...
GET /arguments?Author=John%20Doe
<body>
<a rel="self" href="/arguments?Author=John%20Doe"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
This is now a brand new resource. You can describe it as an argument list (key/value pairs) with a single key/value pair: "Author"/"John Doe". The HTML is pretty much the same as before, with a few changes:
The "self" link now points to current resources URL (changed from "/arguments" to "/arguments?Author=John%20Doe"
The "action" attribute of the first form now has the longer URL, but once again we use URI Templates to allow us to build a larger URI.
The second form
The user now wants to add a "Date" argument, so they once again submit the first form, this time with key of "Date" and a value of "2003-01-02".
GET /arguments?Author=John%20Doe&Date=2003-01-02
<body>
<a rel="self" href="/arguments?Author=John%20Doe&Date=2003-01-02"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&Date=2003-01-02&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
Finally, the user is ready to process their string, so they use the second form and fill in the "input_string" variable. This once again uses URI Templates, thus having bringing the user to the next resource. Let's say that that the string is the following:
{Author} wrote some books in {Date}
The results would be:
GET /processed_string/%7BAuthor%7D+wrote+some+books+in+%7BDate%7D?Author=John%20Doe&Date=2003-01-02
<body>
<a rel="self" href="/processed_string/%7BAuthor%7D+wrote+some+books+in+%7BDate%7D?Author=John%20Doe&Date=2003-01-02">
<span class="results">John Doe wrote some books in 2003-01-02</span>
</body>
PHEW! That's a lot of work! But it's (AFAIC) RESTful, and it fulfills the requirement of not needing to actually store ANYTHING on the server side (including the argument list, or the string that you eventually want to process).
Important Things to Note
One thing that is important here is that I wasn't just talking about URLs. In fact, the majority of time, I'm talking about the HTML. The HTML is the hypermedia, that that's is such a huge part of REST that is forgotten about. All those APIs that say they are "restful" where they say "do a GET on this URL with these parameters and POST on this URL with a document that looks like this" are not practicing REST. Roy Fielding (who literally wrote the book on REST) made this observation himself.
Another thing to note is that it was quite a bit of pain to just set up the arguments. After the initial GET / to get to the root (you can think of it as the "menu") of the service, you would need to do five more GET calls just to build up your argument resource to make an argument resource of four key/value pairings. This could be alleviated by not using HTML. For example, I already did use URI Templates in my example, there's no reason to say that HTML just isn't good enough for REST. Using a hypermedia format (like some derivation of XML) that supports something similar to forms, but with the ability to specify "mappings" of values, you could do this in one go. For example, we could extend the HTML media type to allow another input type called "mappings"...
So long as the client using our API understands what a "mappings" input type is, they will be able to build their arguments resource with a single GET.
At that point, you might not even need an "arguments" resource. You could just skip right to the "processed_string" resource that contains the mapping and the actual string...
What about file upload?
Okay, so originally you mentioned file uploads, and how to get this without needing to store the file. Well, basically, we can use our existing example, but replace the last step with a file.
Here, we are basically doing the same thing as before, except we are uploading a file. What is important to note is that now we are hinting to the user (through the "method" attribute on the form) that they should do a POST rather than a GET. Note that even though everywhere you hear that POST is a non-safe (it could cause changes on the server), non-idempotent operation, there is nothing saying that it MUST be change state on the server.
Finally, the server can return the new file (even better would be to return some hypermedia or LOCATION header with a link to the new file, but that would require storage).
Final Comments
This is just one take on this specific example. While I hope you have gained some sort of insight, I would caution you to accept this as gospel. I'm sure there have been things that I have said that are not really "REST". I plan on posting this question and answer to the REST-Discuss Mailing List and see what others have to say about it.
One main thing I hope to express through this is that your easiest solution might simply be to use RPC. After all, what was your original attempt at making it RESTful attempting to accomplish? If you are trying to be able to tell people that you accomplish "REST", keep in mind that plenty of APIs have claimed themself "RESTful" that have really just been RPC disguised by URLs with nouns rather than verbs.
If it was because you have heard some of the benefits of REST, and how to gain those benefits implicitly by making your API RESTful, the unfortunate truth is that there's more to REST than URLs and whether you GET or POST to them. Hypermedia plays a huge part.
Finally, sometimes you will encounter issues that mean you might do things that SEEM non-RESTful. Perhaps you need to do a POST rather than a GET because the URI (which have a theoretical infinite amount of storage, but plenty of technical limitations) would get too long. Well then, you need to do POST. Maybe
More resources:
REST-Discuss
My e-mail on this answer to REST-Discuss
RESTful Web Services Cookbook
Hypermedia APIs with HTML5 and Node (Not specifically about REST, but a VERY good introduction to Hypermedia)
What you are doing is not REST-ful - or, at least, is difficult to express in REST, because you are thinking about the operation first, not the objects first.
The most REST-ful expression would be to create a new "OdtTemplate" resource (or get the URI of an existing one), create a new "SetOfValues" resource, then create a "FillInTemplateWithValues" job resource that was tied to both those inputs, and which could be read to determine the status of the job, and to obtain a pointer to the final "FilledInDocument" object that contained your result.
REST is all about creating, reading, updating, and destroying objects. If you can't model your process as a CRUD database, it isn't really REST. That means you do need to, eg, store the template on the server.
You might be better off, though, just implementing an RPC over HTTP model, and submitting the template and values, then getting the response synchronously - or one of the other non-REST patterns you named... since that is just what you want.
If there is no value in storing the templates then option 2 is the most RESTful, but as you are aware there is the possibility of having your GET body dropped.
However, if I was a user of this system, I would find it very wasteful to have to upload the template each time I would like to populate it with values. Instead it would seem more appropriate to have the template stored and allow different requests with different values to populate the resulting documents.
I have a struts2 page which uses a shared action using <s:action> with executeResult="true" to add header contents to the page. However, there's some processing need to be done in the header action, which needs to retrieve the url of the actual page(aka the caller page). But if I use <s:url> within the header action's jsp, it only retrieve the url of the header action. So I would like to ask the experts here to enlighten me on how to achieve the result I want.
Thanks in advance.
I'm not sure I follow... so feel free to correct me if I'm not at all answering what you want.
But you should be able to use the <s:set> tag with the appropriate scope (probably request) before you call <s:action> to make the values you need available to the next action. See: http://struts.apache.org/2.2.1.1/docs/set.html
I would consider using the request object for this:
String referrer = request.getHeader("referer"); //referer spelling intentional
Do whatever you need with it via string manipulation.
So below is what I did to do it.
On the main page, use s:url and s:set to obtain the current url as well as parameters and save it in request scope
<s:set name="pageurl" scope="request">
<s:url includeParams="none" encode="true"/>
</s:set>
<s:set name="pageparams" scope="request" value="#parameters"/>
On the header page, you can retrieve them using below
<form action="<s:property value='#attr.pageurl'/>" >
<s:iterator value="#attr.pageparams" var="param">
<s:hidden name="%{#param.key}" value="%{#param.value}" id="_header_%{#param.key}"/>
</s:iterator>
</form>
I am using an application (a blog) written using the CodeIgniter framework and would like to search my blog from my browsers location bar by adding a string to the end of my blogs url like this:
http://mysite.com/blog/index.php/search...
As you can see in the example above I am not really sure how to format the rest of the url after the search part so I am hoping someone here might be able to point me in the right direction.
This is what the form looks like for the search box if that helps at all.
form class="searchform" action="http://mysite.com/blog/index.php/search" method="post">
<input id="searchtext" class="search_input" type="text" value="" name="searchtext">
<input type="submit" value="Search" name="Search">
</form>
Thx,
Mark
Since your form is posting to http://mysite.com/blog/index.php/search, I'm assuming this 'search' controller's default function is the one your are attempting to submit your data to. I think that the easiest way to do this would be to just grab the post data inside of the controller method you're posting to. Example:
function search()
{
$search_params = $this->input->post('search_text');
}
Then you would have whatever the user input stored as $search_params, and you can take actions from there. Am I misunderstanding what you're asking?
It seems like you're kind of discussing two different approaches. If you wanted to make a request to
mysite.com/blog/index.php/search&q=what_I_am_looking_for
This is going to call the search controllers default method (which is index by default). If you wanted to use the URL to pass parameters like that you would go to your function in the search controller and do:
print_r($this->input->get('q'));
This will print out "what_am_I_looking_for".
An easier approach in my opinion would be to:
1. Create a view called "search_view" with the HTML content you pasted above, and have the form "action" http://www.mysite.com/blog/index.php/test/search
Create a controller called "Test" that looks like the following:
class Test extends CI_Controller {
function search()
{
$search = $this->input->post('searchtext');
print_r($search);
}
public function display_search()
{
$this->load->view('search_view');
}
}
Visit http://www.mysite.com/blog/index.php/test/display_search in your browser. This should present you with the form you placed in search_view.php. Once the form is submitted, you should be sent to the search function and print out the variable $search, which will have whatever text you submitted on that form.
If this isn't what you were looking for then I am afraid I do not understand your question.