views:

91

answers:

1

I am using a Front Controller to send the user through a series of pages with questions. Pretty much everything must be dynamic as the pages, the questions, and everything else is set in the admin interface and stored in the database.

I am tracking the user's progress through the database by storing a unique identifier in the session and storing the current page the user is on in the database so I can figure out the next page to send them to.

The thing is, there are a lot of special cases to check for. Right now the controller is over 300 lines long and the code is poorly written and I'm the one who wrote it. Plus, I am going to need to add a lot more to this system in the upcoming weeks such as user-generated content and different pages to show depending on where the user is coming from.

I can see that this controller is going to become a big mess fast if I don't organize it well.

What are some good ways or ideas to refactor this?

+2  A: 

Generally it's easier to use URLs to determine what you should send to the client. If your questions are submitted via a <form> you can return a redirect to the next question once you have saved the answer. For example if this was one of your questions:

<form action="/questions/14" method="post">...

This would submit to /questions/14 and once you have saved the answer you can redirect to question 15:

header('Location: /questions/15');
exit;

Once you have URLs in place you can split up your front controller into parts that relate to each question. Then all you need is some routing:

if(preg_match('/\/questions\/([0-9]+)/',$_SERVER['REQUEST_URI'],$matches) > 0) 
{
    $question_num = (int)$matches[1];
    if(!in_array($question_num, $valid_questions)) {
        // return 404
    }

    $controller_name = 'Question_' . $question_num;
    return new $controller_name; 
} 
else // check for urls that aren't questions ...
rojoca
Seems exactly right. Each question should be its own controller action. Process the response, and redirect to whatever the next question is. Protip: If a particular answer require skipping the next question, don't use magic numbers. Instead redirect to $thisQuestionNum+2.
timdev
Thanks! I did things a little differently - all forms still post to the front controller - but now every page controller has a handlePost() method that the Front Controller calls. In the database, the page controller class is no stored along with the template file so the Front Controller figures out the current page the user is on, loads the controller, checks if there is POST data and then calls the Page to load the view.This reduced the Front Controller from over 300 lines to under 30!
Matt McCormick