2

In a MVC pattern, what's the best way to handle when a single view could have multiple actions of the same type (e.g POST)?

Say for instance in a TODO list application. You might allow a user to create multiple lists. Each list could have multiple items. So a user navigates to site.com/list/1 which shows them all the items on the 1st list (1 is a GET parameter). There are then 2 forms (POST) on this page to allow a user to:

  1. Create a new item
  2. Delete an existing item

Should the bootstrap create a "listcontroller", inspect the POST variables and then call the appropriate method similar to :

$lc = new ListController();    
if(strtolower($request->verb) === 'post'):
    if(isset($_POST['title'])) :
        $data = $lc->newItem($_POST);
        $load->view('newitem.php', $data);
    else if(isset($_POST['delete']) && isset($_POST['id'])):
        $data = $lc->deleteItem($_POST);
        $load-view('deleteitem.php', $data);                    
    endif;// End if post title
else:
    //GET request here so show view for single list
endif; //

Or is it better to just do something like

$lc = new ListController();
if(isset($_POST)):
    //controller handles logic about what function to call
    $data =  $lc->PostAction($_POST); 
    // $data could also potentially hold correct view name based on post
    $load->view(); 
else:
    //again just show single list
endif;

I'm just struggling how best to have a controller potentially handle multiple different actions, as there's potentially quite a few nested if/else or case statements to handle different scenarios. I know these would have to sit somewhere, but where is cleanest?

I know that there are many frameworks out there, but I'm going through the whole "want to understand best practice" behind it phase. Or is this totally the wrong way to do it? Should the controllers actually be structured differently?

TommyBs
  • 9,354
  • 4
  • 34
  • 65

2 Answers2

2

To begin with, I actually really like, how you are dealing with implementation of MVC. None of that rails-like parody, where view is managed inside the controller.

Here is what I think is the root of your problem: you are still using a "dumb view" approach.

View is not supposed to be a synonym for "template". Instead it should be a full object, which has knowledge-of and ability-to deal with multiple templates. Also, in most of MVC-inspired design patterns, the view instances are able to request information from model layer.

In your code the issue can be traced back to view's factory ( the $load->view() method ), which only gets what controller sends it. Instead controller should only change the name of the view, and maybe send something that would change the state of view.

The best solution for you would be to create full-blown view implementation. Such that view itself could request data from model layer and , based on data it received, decide which template(s) to use and whether to require additional information from model layer.

Community
  • 1
  • 1
tereško
  • 58,060
  • 25
  • 98
  • 150
  • I've never thought of views like that. I always just used to code everything inline, but it just becomes a mess, and clearly I do like and appreciate what the MVC structure brings. I want to understand the concepts and best practice more when coding in this style in PHP and I appreciate what you've written in the other posts you mention. As I commented above, maybe even making it more dynamic with actions in the url might help improve things – TommyBs Jul 23 '12 at 12:29
1

I think you're somewhat on the right track with the latter approach. However, you should not hard code the calling of actions in your bootstrap. The bootstrap should interpret the URL and call the action methods dynamically through the use of a function like call_user_func_array.

Also, I would suggest that you leave the rendering of views up to the action code so the action logic is self sufficient and flexible. That would allow the action to analyse the input for correctness and render errors or views appropriately. Also, you've got the method 'deleteItem' on your controller, but that should really be the work of a model. Perhaps you should read up some more on MVC and try to work with an existing framework to understand the concepts better before you try to implement your own framework (I would suggest the Yii framework for that).

Here's an example of how I think your logic should be implemented in a good MVC framework.

class ListController extends BaseController
{
    public function CreateAction($title){
        if(ctype_alnum($title))
        {
            $list = new List();
            $list->Title = $title;
            if($list->insert())
            {
                $this->render_view('list/create_successful');
            }
            else
            {
                $this->render_view('list/create_failed');
            }
        }
        else
        {
            $this->render_view('list/invalid_title');
        }
    }

    public function DeleteAction($id){
        $list = List::model()->getById($id);

        if($list == null)
        {
            $this->render_view('list/errors/list_not_found');
        }
        elseif($list->delete())
        {
            $this->render_view('list/delete_successful');
        }
        else
        {
            $this->render_view('list/delete_failed');
        }
    }
}

here is a great tutorial on how to write your own MVC framework

Saad Imran.
  • 4,480
  • 2
  • 23
  • 33
  • 1
    Thanks for this. To make it clear,in the above the controller->deleteItem method would merely call a DAO object which would handle the delete. I wasn't explicitly calling the database functions in the controller. I was just a bit confused about where multiple requests to the same page sit, but I guess it's more about how I handle the "actions" and where I build those up in my urls – TommyBs Jul 23 '12 at 12:25
  • Oh okay, I understand. In any case, I think your bootstrap should analyse only the URL request when it decides which controller and action to execute, the POST data should play no part in it (in my opinion). Like you said, it's more about how you choose to build your actions, I think it would make more sense to have `Delete` and `Create` actions rather than a `Post` action, because they really are two different actions. You should try looking into the `CRUD` pattern, it goes nicely with MVC and might give you new ideas. – Saad Imran. Jul 23 '12 at 13:07