简体   繁体   中英

CakePHP - How to add to/edit $this->passedArgs

I have a search with multiple parameters being passed via the url - city, cuisine, features, and what page you're on (thank you paginator)

If user is on page 2 - ...index/page:2 and clicks on the city "New York", they should go to ...index/page:2/city:New York

Then, if they then click on Houston, they should go to ...index/page:2/city:New York_Houston

Is there any easy/built in way to do that? I've started writing my code to break apart the $this->passedArgs, and rebuild it - but this has been a pain so far, and it seems like I'm writing a ton of code for something I'm hoping Cake has a way to handle.


Example:

User is on page 2 of a restaurants list - index/page:2

User clicks "New York", the page refreshes with index/page:2/city:New York

User clicks "San Diego" - the page refreshes with index/page:2/city:New York_San Diego

User clicks "New York" again (to un-toggle it), the page refreshes with index/page:2/city:San Diego


My attempt at creating a list of city-links that would do this kind of toggling:

The biggest issue isn't that I can't do it (the code below works), but 1) it doesn't account for any other query options like page, cuisine, features...etc - and 2) it feels like a TON of code to do something simple.

I'm less concerned about any really minor code errors and more about overall best approach to this problem. (feel free to comment w/ any issues though - I always enjoy hearing better ways to do anything/everything).

Thanks very much ahead of time for any help!

$passedCities = explode("_", $this->passedArgs['city']);

foreach($cities as $city):

    $city_name = trim(ucwords(strtolower($city['City']['name'])));
    $cityExists = in_array($city_name, $passedCities);
    $queryCities = $passedCities;

    if($cityExists) {
        unset($queryCities[array_search($city_name, $queryCities)]);
    } else if($city_name != "") {
        array_unshift($queryCities, $city_name);
    }

    $urlSuffix = "";
    if(count($queryCities) > 0) {
        $urlSuffix = "city:";
        foreach($queryCities as $c) {
            $urlSuffix .= trim($c) . "_";
        }
    }

    $urlSuffix = substr($urlSuffix,0,-1);

    echo "<li>" . $this->Html->link($city_name . 
            " (" . $city[0]['count'] . ")", array($urlSuffix)) . "</li>";

endforeach;

I'd work it this way, and let suppose your model name is Restaurant

I'd make the search form of type 'Get'

echo $form->create('Restaurant',  array('type' => 'get', 'action' => 'index', 'class' => 'search-form'));
echo $form->input('city'); 
echo $form->input('cuisine');  
echo $form->input('feature');  
echo $form->end('Search'); 

In the restaurant controller, in action index

function index() {

    $this->redirectToNamed();
    $conditions = array();
    $params = $this->params['named'];

    if (!empty($params['city'])){
      $conditions['Restaurant.city LIKE'] = '%'.trim($params['city']).'%';
    }
    if (!empty($params['cuisine'])){
      $conditions['Restaurant.cuisine LIKE'] = '%'.trim($params['cuisine']).'%';
    }
    if (!empty($params['background'])){
      $conditions['Restaurant.feature LIKE'] = '%'.trim($params['feature']).'%';
    }
    //refill the form with args
    $this->data['Restaurant'] = $params;

    $restaurants = $this->paginate('Restaurant', $conditions);

}


function redirectToNamed() { 

    $urlArray = $this->params['url'];
    unset($urlArray['url']);

    if( !empty($urlArray) ){
        $this->redirect($urlArray, null, true);
    }
}

If I didn't forget anything, your search form will stay filled with previous params.

Maybe you could save an array with the selected cities in the user session. It is possible to write data into the session using the session component. Have a look into the corresponding CakeBook chapter.

Storing the cities in an array instead of the URL would have the advantage that you don't need to split the search string.

I will answer with a non answer.

For me, it seams that changing city is like performing a new search so I would show page 1 after that. Also because, by changing the search parameters, you will probably not have the same page count. What will happen if user was on page 6, change the parameters, and the search returns only 4 pages?

i'd create a Helper that has a function that creates the link (i'd call them "filters", seems more appropriate). To that function i'd pass the list of elements (cities, cuisine, features,etc) and a copy of the passedArgs variable (i'm not really sure if the helpers can access the passedArgs directly):

function createFilters($elements,$copyPassedArgs,$filterName){

the idea of this function is to create the links like you did it in your example, just change a little bit your code:

/*$urlSuffix = "";
if(count($queryCities) > 0) {
    $urlSuffix = "city:";
    foreach($queryCities as $c) {
        $urlSuffix .= trim($c) . "_";
    }
    $urlSuffix = substr($urlSuffix,0,-1);
}*/

$filter = implode("_",$queryCities);

echo "<li>" . $this->Html->link($city_name . 
        " (" . $city[0]['count'] . ")", array_merge($copyPassedArgs,array($filterName => $filter)) . "</li>";

you'll probably need to change this code, but the main idea is:

  • use implode instead of foreach.
  • use array_merge to merge the passedArgs and the values that you want to change for the link

good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM