Jump to content

Search form with multiple fields


nikola
 Share

Recommended Posts

I have a small search form that searches products by selected manufacturer, price or manufacturer and price combined.

Manufacturer is a page list field, and the generated prices are a range.

This is the form:


<label for="search-manufacturer">Manufacturer</label>

<select id="search-manufacturer" name="manufacturer">
<option value="">Any</option>
<!--?php
foreach($pages--->get("/manufacturer/")->children() as $manufacturer) {
$selected = $manufacturer->name == $input->whitelist->manufacturer ? " selected='selected' " : '';
echo "{$manufacturer->title}";
}
?>
</select>

<label for="search-price">Price</label>

<select id="search-price" name="price">
<option value="">Any</option>
<!--?php
foreach(array('0-50', '50-250', '250-500', '500-750', '750-1000', '1000+') as $price) {
$selected = $price == $input--->whitelist->price ? " selected='selected'" : '';
echo "$price";
}
?>
</select>

<input type="submit" id="search-submit" name="submit" value="Search">

What code do I need to put into "manufacturer-search" template to search products by criterions mentioned above?

I've looked into the skyscapers profile but couldn't make it work...

Thanks

Link to comment
Share on other sites

I'm not sure there's enough to go on here to say for sure. Where are you setting the $input->whitelist values? That's probably the same place where you want to build your search selector. Something like this:

$selector = 'parent=/products/, ';

$name = $sanitizer->pageName($input->get->manufacturer);
$man = $pages->get("parent=/manufacturer/, name=$name");
if($man->id) {
$input->whitelist('manufacturer', $man->name);
$selector .= "manufacturer=$man, ";
}

list($priceMin, $priceMax) = explode('-', $input->get->price);
$priceMin = (int) $priceMin;
$priceMax = (int) $priceMax;
if(!$priceMax) $priceMax = 99999; // or some other max value
$input->whitelist('price', "$priceMin-$priceMax");
$selector .= "price>=$priceMin, price<=$priceMax, ";

$selector .= 'limit=25';
$products = $pages->find($selector);

if(count($products)) echo $products->render();
else echo "<h2>Sorry no products found</h2>";
Link to comment
Share on other sites

Ryan, thanks for the exapmle.

It's working fine with manufacturer if I remove code block from selector:

list($priceMin, $priceMax) = explode('-', $input->get->price);
$priceMin = (int) $priceMin;
$priceMax = (int) $priceMax;
if(!$priceMax) $priceMax = 99999; // or some other max value
$input->whitelist('price', "$priceMin-$priceMax");
$selector .= "price>=$priceMin, $price<=$priceMax, ";

If I include this block of code PW throws me an error:

PHP Notice: Undefined offset: 1 in C:\inetpub\wwwroot\pw\site\templates\manufacturer-search.php on line 13 PHP Notice: Array to string conversion in C:\inetpub\wwwroot\pw\site\templates\manufacturer-search.php on line 18 PHP Fatal error: Exception: Field does not exist: Array (in C:\inetpub\wwwroot\pw\wire\core\PageFinder.php line 244)

manufacturer-search.php template consist only of code you posted above.

Link to comment
Share on other sites

  • 2 months later...

Hi! Search realization is impossible to me, prompt as it is possible to solve it if the form with selectors at me looks so:

<form id="city_obj_search" method="get" action="<?php echo $config->urls->root?>city_obj_search/">
<ul>
<li>
<?php
foreach($pages->get("/business_type/")->children() as $type_of_oper) {
$checked = $type_of_oper->name == $input->whitelist->type_of_oper ? " checked='checked' " : '';
echo "<div>
<label>
<input$checked type='checkbox' name='type_of_oper' value='{$type_of_oper->name}'>{$type_of_oper->title}
</label>
</div>" ;
}
?>
</li>
<li>
<label for="district_location">District</label>
<select id="district_location" name="distr">
<option value="any">Any</option>
<?php
foreach($pages->get("/district/")->children() as $distr) {
$selected = $distr->name == $input->whitelist->distr ? " selected='selected' " : '';
echo "<option$selected value='{$distr->name}'>{$distr->title}</option>";
}
?>
</select>
</li>
<li>
<label for="subway_station">Subway station</label>
<select id="subway_station" name="subway">
<option value="any">Any</option>
<?php
foreach($pages->get("/subway_station/")->children() as $subway) {
$selected = $subway->name == $input->whitelist->subway ? " selected='selected' " : '';
echo "<option$selected value='{$subway->name}'>{$subway->title}</option>";
}
?>
</select>
</li>
<li>
<label for="object_cost_ru">Cost in ru</label>
<select id="object_cost_ru" name="costru">
<option value="any">Any</option>
<?php
foreach(array('30000-50000', '50000-100000', '100000-250000', '250000-500000', '500000-1000000', '1000000+') as $costru) {
$selected = $costru == $input->whitelist->costru ? " selected='selected'" : '';
echo "<option$selected value='$costru'>$costru руб.</option>";
}
?>
</select>
</li>
<li>
<label for="object_cost_dol">Cost in dollars</label>
<select id="object_cost_dol" name="costdol">
<option value="any">Any</option>
<?php
foreach(array('1000-3000', '3000-10000', '10000-20000', '20000-30000', '30000+') as $costdol) {
$selected = $costdol == $input->whitelist->costdol ? " selected='selected'" : '';
echo "<option$selected value='$costdol'>$costdol $</option>";
}
?>
</select>
</li>
<li>
<label for='search_id'>ID</label>
<input type="text" placeholder="00000" name="id" id="search_id" value="<?php
if($input->whitelist->id) echo htmlentities($input->whitelist->id, ENT_QUOTES); ?>" />
</li>
<li>
<input type="submit" id="search_submit" name="submit" value="Find!">
</li>
</ul>
</form>

I wish that this request would be processed the search page «city_obj_search/», but the information from the forum (http://processwire.c...op-down-search/) that I use does not help me either an error or an empty result. Help to understand, please.

Link to comment
Share on other sites

I'm not sure I understand the question 100%, but I think we need to take a look at the code that actually generates the selector (rather than just the code that generates the form). Also, while developing search engines, I always find it helpful to output the selector that is being used. Once the site is finished with the development then I remove it. But to do this, you may want to add something like this at the top of your search results:

<?php echo "<h2>" . htmlentities($selector, ENT_QUOTES, "UTF-8") . "</h2>"; ?>
Link to comment
Share on other sites

Thanks for the reply Ryan and code, it clarifies some things )

Question that I asked - I solved (so delete it) and walked right up to the search, the results of which I can not get it.

Form code I've described above, in a search template I use the following code (searching only two fields participate now):

include("./header.inc");
$selector = 'parent=/direction/city/, ';
if($input->get->id) {
	$value = $sanitizer->selectorValue($input->get->id);
	$selector .= "object_id~=$value, ";
	$input->whitelist('id', $value);
}
if($input->get->distr) {
	$distr = $pages->get("/district/" . $sanitizer->pageName($input->get->distr));
	if($distr) {
	$selector .= "parent=$distr, ";
	$input->whitelist('distr', $distr->name);
	}
}
$objects = $pages->find($selector);
$count = count($objects);
echo "<h2>" . htmlentities($selector, ENT_QUOTES, "UTF-8") . "</h2>";
if($count) {
echo "<h2>Found pages: $count</h2>";
foreach($objects as $obj) {
echo "<div><a href='{$obj->url}'>{$obj->title}</a></div>" ;
}
} else echo "<h2>There are no results matching the query</h2>";
include("./footer.inc");

I made them for example, but they do not work, and the reason that I can not yet understand.

upd:

Slowly I begin to understand the structure.

It appears in the search involved a hierarchy of pages. On an example of skyscrapers it: cities -> city -> object -> its properties (height, floors, year).

What if such structure isn't present and my objects aren't enclosed, and are parallel?

What role does this value $selector = 'parent=/direction/city/, '; ?

Differently: how add in search of architects of skyscrapers? )

Edited by AlexV
Link to comment
Share on other sites

AlexV, what was the output of your $selector (in the <h2>?). The code looks good to me, but I don't know the full site structure either, so don't necessarily have the context to relate it to that.

Link to comment
Share on other sites

Ryan, when I remove the code

/*if($input->get->distr) {
	$district = $pages->get("/district/" . $sanitizer->pageName($input->get->distr));
	if($district) {
			$selector .= "parent=$district, ";
			$input->whitelist('distr', $distr->name);
	}
}*/

rest of the code begins to work.

When I turn on, I get:

parent=/direction/city/, parent=1253,

There are no results matching the query

I can guess why. Here is the hierarchy of pages:

|- direction

| |

| |- city

| |- object 1 (object has a Pagefield named «district», in which selected pages «district 1 and so on»)

| |- object 2

| |- and so on

|

|- district

| |- district 1

| |- district 2

I want to get a list of objects from the section «city» criteria «district». How can I do?

upd:

I found the solution, it was too easy, instead of the «parent» it is necessary to use a «field»

$selector .= "parent district_location=$district, ";

But now another question, not displayed «whitelist» )

In what may be the reason?

upd2:

I found the solution works until I add another criterion in the search, for example:

if($input->get->type_of_oper) {
	$type_of_oper = $pages->get("/business_type/" . $sanitizer->pageName($input->get->type_of_oper));
	if($type_of_oper) {
			$selector .= "type_of_operation=$type_of_oper, ";
			$input->whitelist('type_of_oper', $type_of_oper->name);
	}
}

after adding it, I get:

parent=/direction/city/, district_location=, type_of_operation=1021,

how to avoid it?

Edited by AlexV
Link to comment
Share on other sites

$pages->get() will always return a Page object, so rather than doing this:

if($type_of_oper) {

you should do this:

if($type_of_oper->id) {

When a $pages->get() doesn't match anything, it returns a NullPage. The easiest way to check for a NullPage is by seeing if it has an id, like above. Though you could also do this if you preferred:

$p = $pages->get($selector); 
if($p instanceof NullPage) {
  // no page found
} else {
  // page found
}
  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

There are still questions of search. While I can't answer them itself.

First question. Now I have two checkbox, it work by a principle "or", in what case they will work as "and". Now the code in the search template looks like this:

$name = $sanitizer->pageName($input->get->type_of_oper);
$man = $pages->get("parent=/business_type/, name=$name");
if($man->id) {
       $input->whitelist('type_of_oper', $man->name);
       $selector .= "type_of_operation=$man, ";
}

Second question. In the search form has two text fields "from" and "before". How to realize search for them?

Сode search form:

<label for="square">Square</label>
<input type="text" name="squareMin" value="<?php if($input->whitelist->squareMin) echo htmlentities($input->whitelist->squareMin, ENT_QUOTES, "UTF-8"); ?>" />
<input type="text" name="squareMax" value="<?php if($input->whitelist->squareMax) echo htmlentities($input->whitelist->squareMax, ENT_QUOTES, "UTF-8"); ?>" />

Code that I tried to use in search template, but it does not work:

$valueMin = $sanitizer->selectorValue($input->get->squareMin);
$valueMax = $sanitizer->selectorValue($input->get->squareMax);
$selector .= "object_square>=$valueMin, object_square<=$valueMax, ";
Link to comment
Share on other sites

I think that your first example looks fine in terms of the code. I'm not sure I understand the question on that one.

For the second one, what kind of field is object_square? I don't see anything amiss in your code, but based on the operators ">=" and "<=" it makes me think that object_square is an integer and should probably be sanitized/typecast as such, rather than as a string. i.e.

$valueMin = (int) $input->get->squareMin; 

Also there's no reason to run an integer through htmlentities(). There's also no harm in it, but just wanted to mention it might not be necessary if you are keeping it as an integer.

Link to comment
Share on other sites

Thanks for the reply Ryan!

In the second case, I used a «text» field, so that did not work. I changed it on the field «float» and added your code, thank you, it works!

I will describe in more detail the first question.

I have two checkboxes and code which I specified above.

Now when I choose one checkbox search works well. When I choose two checkboxes, search shows that one is chosen only. How it is possible to change a code that search was on two values (which I select checkboxes)?

Link to comment
Share on other sites

It's hard to answer for sure, because I don't see anything in your first code example that draws a relation to multiple checkboxes on the front-end. But based on what you've said, I'm guessing one of the checkboxes has a name of "type_of_oper"? i.e.

<input type='checkbox' name='type_of_oper' value='something' />

If there is another checkbox, then you would need some code to handle that one too. Since these are checkboxes rather than radio buttons, you'll want to give each one a different name in their <input> tag. You could also take an array approach, using the same name and appending "[]" to it so that they come through as an array. But if we're only talking about 2 checkboxes here, then I think it's better to just make them separate.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...