Problem/Motivation

Currently I have a use case in the Facet API module illustrated at http://drupal.org/node/593658#comment-5322096 where I need to alter the redirect of the ctools_export_ui::edit_form() form so it maintains the query string variables on redirect. Specifically, when I visit the edit form via a contextual link, a "destination" query string variable is passed so that form submissions redirect back to the page the site builder came from. Viewing the screenshot in the link above, I have an "Add item" button that should always redirect back to the edit form but maintain the "destination" variable so when the user is done adding items and clicks "Save", they are redirected back to the page they came from as expected. However I cannot add query string variables to the redirect since CTools only allows $this->plugin['redirect'][*] to be a string which is passed as the first argument to drupal_goto(). This is unlike core $form_state['redirect'] where it can also be passed as an array that is translated the into arguments passed to drupal_goto().

Proposed resolution

By modifying the logic to make $this->plugin['redirect'][*] behave more like the $form_state['redirect'], developers can either set $this->plugin['redirect'][*] to a string (as the module currently works) or an array to have the added flexibility of being able to pass additional options to drupal_goto().

API changes

The proposed change wouldn't effect the current API since we are simply modifying the $this->plugin['redirect'][*] variables to accept an array in addition to a string.

Comments

cpliakas’s picture

Status: Active » Needs review
StatusFileSize
new2.42 KB

The attached patch makes the proposed change.

The current_search_export_ui::edit_execute_form() is a working example of how the change could be utilized to meet the use case illustrated in #1.

merlinofchaos’s picture

When we have the same code 4 times, and it's now 3 lines of code, this is a clear sign that we should abstract.

Something like this would work as an export ui class method: (this is just off the top of my head, no testing or verifying):

  /**
   * Perform a drupal_goto() to the location provided by the plugin for the operation.
   *
   * @param $op
   *   The operation to use. A string must exist in $this->plugin['redirect'] for this operation.
   * @param $item
   *   The item in use; this may be necessary as item IDs are often embedded in redirects.
   */
  function redirect($op, $item = NULL) {
     $destination = (array) $this->plugin['redirect'][$op];
     if ($item) {
       $export_key = $this->plugin['export']['key'];
       $destination[0] = str_replace('%ctools_export_ui', $item->{$export_key}, $destination[0]);
    }
    call_user_func_array('drupal_goto', $destination); 
  }

This also incidentally makes the variable name more meaningful.

cpliakas’s picture

Assigned: Unassigned » cpliakas
Status: Needs review » Needs work

This approach makes perfect sense to me. I will re-roll a patch with the proposed change.

Thanks for the review,
Chris

cpliakas’s picture

Status: Needs work » Needs review
StatusFileSize
new2.95 KB

The attached patch makes the requested changes. I tested against my customization in the Facet API module and it works as expected. I also removed the customization to test backwards compatibility and that works as well.

The only use case I could find for not passing the $item parameter is the "delete" operation, however looking at the defaults set in the ctools_export_ui_process() function, the "delete" operation is not set as a default so cannot be used with the new ctools_export_ui::redirect() method added in this patch. I can work on it if you feel it would be useful, I just didn't want to introduce too much at one time.

merlinofchaos’s picture

Maybe if $op is not set in the plugin, the redirect should fall back to the base path; it doesn't feel right for the redirect to not actually perform a goto and fail silently if somehow the op is not set.

cpliakas’s picture

Status: Needs review » Needs work

Makes sense. Will roll another patch.

cpliakas’s picture

Status: Needs work » Needs review
StatusFileSize
new3.11 KB

The attached patch adds the change suggested in #5.

merlinofchaos’s picture

Status: Needs review » Fixed

Committed and pushed! Thanks!

cpliakas’s picture

Excellent! This will remove about 40 lines of code in my module, so I appreciate your attention to this :-).

~Chris

emattias’s picture

Could someone explain/show example code of how this should work?

I tried adding this in panels_mini.inc (a export_ui plugin in panels core):


  'redirect' => array(
    'edit' => 'user'
  ),

Unfortunately my specified redirect get's overridden with this code in ctools/includes/export_ui.inc:


  // Define some redirects that should happen after edit/add/clone operations.
  $plugin['redirect'] = array(
    'add' => $base_path,
    'clone' => $base_path,
    'edit' => $base_path,
    'import' => $base_path,
  );

Either the code above should only append to $plugin['redirect'] or I have completely missuderstood how this should be implemented..

I got it working by changing the code above with this:


  $plugin['redirect'] = isset($plugin['redirect']) && is_array($plugin['redirect']) ? $plugin['redirect'] : array();

  // Define some redirects that should happen after edit/add/clone operations.
  $plugin['redirect'] += array(
    'add' => $base_path,
    'clone' => $base_path,
    'edit' => $base_path,
    'import' => $base_path,
  );

I wasn't sure if I had missunderstood this completely so I didn't do a patch. I'll do it if you want me to.

emattias’s picture

Status: Fixed » Active

I was trying to solve this issue: #934738: Don't redirect on update and save for mini panels

What I would like to do is basically say don't redirect at all. From what I can see there is no way to do that? You either specify a location to redirect to or it will redirect to the plugins base path, there is no way to only display the form again. Which is what I want.

cpliakas’s picture

Status: Active » Fixed

Seems like this is a separate issue that the goal of this thread and the patch that was committed. Might be worth opening up a separate issue so that we can follow single ideas more easily and discuss the issue you brought up.

emattias’s picture

Yeah, but first I'd like to be sure that I've implemented this new feature correctly. Could someone please explain or point to an example of how/where you specify the redirect path.

cpliakas’s picture

Here's a quick example. Whether this is the correct place for redirects is irrelevant, I just forked if from Facet API where I did the redirect in this method because I had some complex logic that required it being here.



/**
 * Implements ctools_export_ui::edit_execute_form().
 */
function edit_execute_form(&$form_state) {
  $output = parent::edit_execute_form($form_state);

  // We are redirecting the form if it was executed.
  if (!empty($form_state['executed'])) {
  
    $op = $form_state['op'];
    $path = 'redirect/to/my/path';
  
    // Add your options, for example query string vars.
    $options = array(
      'query' => array(
        'myvar1' => 'myvalue1',
        'myvar2' => 'myvalue2',
      ),
    );
        
    // Set the redirect to an array so that query string vars are maintained.
    $this->plugin['redirect'][$op] = array($path, $options);
  }

  return $output;
}

I guess you could also set the redirect to an array in the plugin definition as well, i.e. $plugin['redirect']['edit'] = array($path, $options).

Hope this helps,
Chris

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.