Вылечить "Back Button Blues" - PullRequest
       12

Вылечить "Back Button Blues"

2 голосов
/ 09 января 2009

Когда-нибудь сталкивались с учебником, который, по вашему мнению, имеет большую ценность, но не совсем правильно объяснен? Это моя дилемма. Я знаю, ЭТО ОБУЧЕНИЕ имеет какое-то значение, но я просто не могу его получить.

  1. Где вы вызываете каждую функцию?
  2. Какая функция должна быть вызвана первый и какой следующий, а какой третий?
  3. Будут ли все функции вызываться во всех файлах приложения?
  4. Кто-нибудь знает, как лучше вылечить "Back Button Blues"?

Мне интересно, не вызовет ли это хорошего разговора с автором статьи? Часть, в которой я особенно заинтересован - это управление кнопкой «Назад», чтобы предотвратить повторяющиеся записи в базе данных при нажатии кнопки «Назад». По сути, вы хотите управлять кнопкой возврата, вызывая следующие три функции во время выполнения сценариев в вашем приложении. В каком порядке именно вызывать функции (см. Вопросы выше), не понятно из учебника.

Все движение вперед выполняется используя мою функцию scriptNext. Это вызывается в текущем скрипте в Для активации нового скрипта.

function scriptNext($script_id)
// proceed forwards to a new script
{
   if (empty($script_id)) {
      trigger_error("script id is not defined", E_USER_ERROR);
   } // if

   // get list of screens used in this session
   $page_stack = $_SESSION['page_stack'];
   if (in_array($script_id, $page_stack)) {
      // remove this item and any following items from the stack array
      do {
         $last = array_pop($page_stack);
      } while ($last != $script_id);
   } // if

   // add next script to end of array and update session data
   $page_stack[] = $script_id;
   $_SESSION['page_stack'] = $page_stack;

   // now pass control to the designated script
   $location = 'http://' .$_SERVER['HTTP_HOST'] .$script_id;
   header('Location: ' .$location); 
   exit;

} // scriptNext

Когда любой скрипт завершил обработка завершается вызовом моего функция scriptPrevious. Это будет сбросить текущий скрипт с конца массива стека и реактивировать предыдущий скрипт в массиве.

function scriptPrevious()
// go back to the previous script (as defined in PAGE_STACK)
{
   // get id of current script
   $script_id = $_SERVER['PHP_SELF'];

   // get list of screens used in this session
   $page_stack = $_SESSION['page_stack'];
   if (in_array($script_id, $page_stack)) {
      // remove this item and any following items from the stack array
      do {
         $last = array_pop($page_stack);
      } while ($last != $script_id);
      // update session data
      $_SESSION['page_stack'] = $page_stack;
   } // if

   if (count($page_stack) > 0) {
      $previous = array_pop($page_stack);
      // reactivate previous script
      $location = 'http://' .$_SERVER['HTTP_HOST'] .$previous;
   } else {
      // no previous scripts, so terminate session
      session_unset();
      session_destroy();
      // revert to default start page
      $location = 'http://' .$_SERVER['HTTP_HOST'] .'/index.php';
   } // if

   header('Location: ' .$location); 
   exit;

} // scriptPrevious

Всякий раз, когда активируется скрипт, который может быть либо через scriptNext или scriptPrevious функции, или из-за кнопки НАЗАД в браузер, он будет вызывать следующее функция, чтобы проверить, что это текущий сценарий в соответствии с содержимое стека программы и взять соответствующее действие, если это не так.

function initSession()
// initialise session data
{
   // get program stack
   if (isset($_SESSION['page_stack'])) {
      // use existing stack
      $page_stack = $_SESSION['page_stack'];
   } else {
      // create new stack which starts with current script
      $page_stack[] = $_SERVER['PHP_SELF'];
      $_SESSION['page_stack'] = $page_stack;
   } // if

   // check that this script is at the end of the current stack
   $actual = $_SERVER['PHP_SELF'];
   $expected = $page_stack[count($page_stack)-1];
   if ($expected != $actual) {
      if (in_array($actual, $page_stack)) {// script is within current stack, so remove anything which follows
      while ($page_stack[count($page_stack)-1] != $actual ) {
            $null = array_pop($page_stack);
         } // while
         $_SESSION['page_stack'] = $page_stack;
      } // if
      // set script id to last entry in program stack
      $actual = $page_stack[count($page_stack)-1];
      $location = 'http://' .$_SERVER['HTTP_HOST'] .$actual;
      header('Location: ' .$location);
      exit;
   } // if

   ... // continue processing

} // initSession

Предпринятые действия зависят от того, текущий скрипт существует внутри стек программ или нет. Есть три Возможности:

  • Текущий скрипт не находится в массиве $ page_stack, в этом случае он не разрешено продолжать. Вместо этого заменен сценарием, который находится на конец массива.
  • Текущий скрипт находится в массив $ page_stack, но это не последняя запись В этом случае все следующие записи в массиве удален.
  • Текущий скрипт - последняя запись в массиве $ page_stack. Это ожидаемая ситуация. Пьет все круглый!

Ответы [ 6 ]

9 голосов
/ 09 января 2009

Это хорошая дискуссия, но более важно, что вы должны изучить Post Redirect Get (PRG), также известный как «Get after Post».

http://www.theserverside.com/patterns/thread.tss?thread_id=20936

3 голосов
/ 10 января 2009

Если вы не понимаете мою статью, вам следует внимательно посмотреть на рисунок 1 , который изображает типичный сценарий, когда пользователь проходит через ряд экранов - вход в систему, меню, список, поиск, добавление и обновить. Когда я описываю движение FORWARDS, я имею в виду, что текущий экран приостановлен, пока активирован новый экран. Это происходит, когда пользователь нажимает ссылку на текущем экране. Когда я описываю движение как BACKWARDS, я имею в виду, что пользователь закрывает текущий экран (нажатием кнопки QUIT или SUBMIT) и возвращается к предыдущему экрану, который возобновляет обработку с того места, где он остановился. Это может включать в себя любые изменения, сделанные на экране, который был только что отменен.

Здесь важно поддерживать стек страниц, который не зависит от истории браузера: стек страниц поддерживается приложением и используется для проверки всех запросов. Они могут быть действительными в отношении браузера, но могут быть определены приложением как недействительные и обработаны соответствующим образом.

Стек страницы поддерживается двумя функциями:

  • scriptNext () используется для обработки Движение ВПЕРЕД, которое добавляет новый запись в конце стека и активирует новую запись.
  • scriptPrevious () используется для обработки движение НАЗАД, которое удаляет последняя запись из стека и повторно активирует предыдущую запись.

Теперь возьмем ситуацию в примере, когда пользователь перешел на страницу 4 экрана LIST, перешел на экран ADD, а затем вернулся на страницу 5 экрана LIST. Последним действием на экране ADD было нажатие кнопки SUBMIT, которая использовала метод POST для отправки на сервер сведений, которые были добавлены в базу данных, после чего она автоматически завершалась и возвращалась на экран LIST.

Если вы нажмете кнопку BACK, находясь на странице 5 экрана LIST, история браузера сгенерирует запрос на последнее действие на экране ADD, которое было POST. Это действительный запрос для браузера, но не для приложения. Как приложение может решить, что запрос недействителен? Проверяя со своим стеком страниц. Когда экран ADD был закрыт, его запись была удалена из стека страниц, поэтому любой запрос на экран, которого нет в стеке страниц, всегда можно считать недействительным. В этом случае неверный запрос может быть перенаправлен на последнюю запись в стеке.

Поэтому ответы на ваши вопросы должны быть очевидны:

  • В: Где вы вызываете каждую функцию?
  • A: Вы вызываете scriptNext () функция, когда пользователь выбирает перейти к новому экрану, и вызвать scriptPrevious () функция, когда пользователь завершает работу текущий экран.
  • Q: Какая функция должна быть вызвана первый и какой следующий, а какой третий?
  • A: каждая функция вызывается в ответ на действие, выбранное пользователь, поэтому используется только одна функция за один раз.
  • В: Будут ли все функции вызываться в все файлы в приложении?
  • A: Все функции должны быть доступны во всех файлах в приложении, но вызывается только по выбору пользователя.

Если вы хотите увидеть эти идеи в действии, тогда вы можете загрузить мой пример приложения .

0 голосов
/ 10 января 2009
if ($_POST) {
    process_input($_POST);
    header("Location: $_SERVER[HTTP_REFERER]");
    exit;
}
0 голосов
/ 10 января 2009

@Marston.

Я решил проблему с post / redirect / get, но я считаю, что у руководства есть некоторые достоинства, и, возможно, Тони Марстон сможет это подробно описать. И как это можно использовать для решения не обязательно моей конкретной проблемы, а, возможно, чего-то подобного. Или как это лучше, чем post / redirect / get, если функции могут быть использованы для решения моей конкретной проблемы. Я думаю, что это будет хорошим дополнением к сообществу здесь.

0 голосов
/ 10 января 2009

@ troelskn

Если вы разрабатываете свое приложение без состояния сервера ...

Невозможно разработать эффективное приложение, которое не имеет состояния, в противном случае все, что у вас есть, это набор отдельных страниц, которые не взаимодействуют друг с другом. Поскольку поддержание состояния на клиенте чревато проблемами, эффективной альтернативы нет, кроме как поддерживать состояние на сервере.

0 голосов
/ 10 января 2009

Часть, которая меня особенно интересует, - это управление кнопкой «Назад» для предотвращения дублирования записей в базе данных при нажатии кнопки «Назад».

Ваша предпосылка неверна. Нет такой вещи, как «Back Button Blues», если вы разрабатываете свое приложение как веб-приложение. Если вы разрабатываете свое приложение без какого-либо состояния на стороне сервера, вы никогда не столкнетесь с этой проблемой в первом случае. Этот минималистичный подход к веб-приложениям работает на удивление хорошо и обычно известен как REST.

...