SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 36

Hybrid View

  1. #1
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)

    Controllers and Actions in MVC

    I'd like to know how to properly create controllers and actions in MVC. So far I've used them in implementations that were not true MVC so I may not have a correct understanding about when I should create a new controller and when a new action - I'd like to learn some proper basics.

    Let's say I have some common tasks with managing users:

    1. Add user
    2. Edit user
    3. List users
    4. Delete users, hide/unhide users (toggle a flag on or off)
    5. Display single user data

    Below I'm presenting my suggested scenarios, please comment on each one whether it looks good on not:

    Pt. 1 & 2: adding and editing a user are almost identical in html display (same form) so I suspect these will require one controller with two actions. One controller because one controller is always tied to one view. Additionally, I think I will need submit actions that will get values submitted by POST and either redirect to another page or redisplay the form in case of a validation error. So I end up with 4 actions:

    PHP Code:
    class UserFormController {
        
        public function 
    add() {
            
    // ...
        
    }

        public function 
    edit() {
            
    // ...
        
    }

        public function 
    addSubmit() {
            
    // ...
        
    }

        public function 
    editSubmit() {
            
    // ...
        
    }


    Pt. 3: Listing users - there will be features like listing all users, filtering by criteria and pagination. I suspect I can get away with 1 controller with 1 action and simply pass all the necessary parameters from GET to the model in the action.

    Pt. 4:: Deleting (selected) users, hiding/unhiding users - this is supposed to delete the users or perform some other operation in the db on the user and redirect back to the user list. Do I need the view at all in this case? I suppose I can create one controller with 3 actions:

    PHP Code:
    class UserChangeController {

        public function 
    delete() {
            
    // ...
        
    }

        public function 
    hide() {
            
    // ...
        
    }

        public function 
    show() {
            
    // ...
        
    }

    What do I do about the view then? Do I create an empty one or allow my system to have viewless controllers? I'm a little baffled with this one - do I use these actions to pass POST criteria to specific methods in the model that will perform the requested updates on the users in the db? Like this:

    PHP Code:
    class UserChangeController {

        public function 
    delete() {
            
    $userIds array_keys($_POST['checkboxes']);
            
    $this->model->deleteUsers($userIds);

            
    // I don't know if this is the best place to do redirection?
            
    header("Location: " $_POST['redirect']);
            exit;
        }

    Pt. 5:: a page which displays user info - this should be easy, 1 controller and 1 action.

  2. #2
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,149
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    I'd like to know how to properly create controllers and actions in MVC.
    Well... first off, to avoid any debates, we need to clarify which "kind" of MVC you want to implement. Instead of retyping it all, see one of my past posts.
    "First make it work. Then make it better."

  3. #3
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    Well... first off, to avoid any debates, we need to clarify which "kind" of MVC you want to implement. Instead of retyping it all, see one of my past posts.
    In this case I want to implement MVC in its purest traditional sense, the one TomB is advocating.

  4. #4
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    How you actually structure the individual actions is application specific and not specified by MVC itself. However, here's how I do adding/editing. They are essentially identical. I have my model look like something like this:

    PHP Code:
    <?php
    class UserEditController {
        private 
    $user;
        private 
    $userMapper;

        public function 
    __construct(UserMapper $userMapper) {
            
    $this->userMapper $userMapper;
        }    

        public function 
    setEditing($id) {
            
    $this->user= = $this->userMapper->findById($id);                
        }
        
        public function 
    getUser() {
            return 
    $this->user;
        }

        public function 
    save($data) {
            if (
    $data['id'] == null) {
                
    //Adding
            
    }
            else {
                
    //Editing
            
    }
        }


    }
    The controller then does this:

    PHP Code:
    <?php
    class UserEditController {
        private 
    $model;


        public function 
    __construct(UserEditModel $model) {
            
    $this->model $model;
        }

        
    //Default action
        
    public function main($id null) {
            
    $this->model->setEditing($id);
        }

        public function 
    submit() {
            
    //Do some sanity checks on $data then send it to the model for saving
            
    $this->model->save($_POST['user']);                
        }

    }

    The view populates the form from $model->getUser() if $model->getUser() doesn't return null. This way everything is reused. In actual fact, because of the way my DataMapper works (by using ON DUPLICATE KEY UPDATE) I never need the if/else for detecting adding/editing but that's an implementation detail!



    Listing users - there will be features like listing all users, filtering by criteria and pagination. I suspect I can get away with 1 controller with 1 action and simply pass all the necessary parameters from GET to the model in the action.
    Possibly, strictly speaking these should all be separate actions but to achieve combinations your router would need to handle calling multiple actions on one request (Which isn't a bad thing) but that's quite a big topic in itself. The simplest way, with a URL:Controller action router is, as you say, having the controller parse $_GET and set the model's state accordingly. The model should expose methods for sort/filter/paginate and the controller would call each of them.


    Pt. 4:: Deleting (selected) users, hiding/unhiding users - this is supposed to delete the users or perform some other operation in the db on the user and redirect back to the user list. Do I need the view at all in this case? I suppose I can create one controller with 3 actions:
    On which view does the "delete" button sit? If it's the user list, then the UserList controller should have an action called "delete" which calls a (reusable!) model method which contains the implementation. Any place you have a delete user button would call the model's action. On the redirect, you'll send someone to a different page. Perhaps one that sates "The following users have been deleted: x,y,z". That view could then include the list view again to show the updated list, if you so wished. That "Thank you" view may not have a model and almost certainly wouldn't need a controller.


    PHP Code:
    Pt5:: a page which displays user info this should be easy1 controller and 1 action
    Not necessarily. Depending on what it's doing. If it's purely display then you don't need a controller, however if you need to get the ID of the user being edited from $_GET then you need a controller for that. It seems redundant to have a controller with one action that just sets one value on the model but this is where the power of MVC actually comes in; the model's state can be set from anywhere so another part of the system could pull in the model and view from another view without needing the controller.

  5. #5
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Tom, thanks for your code examples. If MVC does not specify the structure of actions then it's even more valuable to see some real world examples.


    Quote Originally Posted by TomB View Post
    PHP Code:
    Pt5:: a page which displays user info this should be easy1 controller and 1 action
    Not necessarily. Depending on what it's doing. If it's purely display then you don't need a controller, however if you need to get the ID of the user being edited from $_GET then you need a controller for that. It seems redundant to have a controller with one action that just sets one value on the model but this is where the power of MVC actually comes in; the model's state can be set from anywhere so another part of the system could pull in the model and view from another view without needing the controller.
    Yes, it's purely display but the user ID sits in the URL of the page so is it possible to do without a controller? I think I need a controller to pass GET to the model's state, is this correct?

    Another thing, even if this was a static page that didn't need any parameters from the URL (for example, a contact page) how would I do without a controller? A page like that needs its own URL (unless I'm including the view's content somewhere else), which equals a fresh page request. If we assume that each page request initiates the MVC in this way:
    PHP Code:
    model = new Model();
    $controller = new Controller($model);
    $view = new View($controller$model);
    echo 
    $view->output(); 
    then it's clear that the page needs a controller because the view requires it. How is it then that I don't need a controller? What am I missing here?

  6. #6
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Yes, it's purely display but the user ID sits in the URL of the page so is it possible to do without a controller? I think I need a controller to pass GET to the model's state, is this correct?
    Yes that's correct. That's a controller action, which then tells the model what user is being dealt with.

    A view only needs a controller if the view has user interaction (or in our case, links/form submissions). These need to link back to a specific (interchangeable) controller. In the real world, to make these actions interchangeable, your view would also need access to a router, which worked out the route for a given controller action (The inverse of what the router does on the request, taking a url and routing to a controller action, in the view the router would take a controller and an action name and generate a URL for it).

    If there are no actions, the view doesn't need to request the controller in its constructor.

    However, "Load the the user with the ID 123 into the view" is a user action if it's coming from a URL so requires an action.

  7. #7
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    So basically, for static pages can I do something like this
    PHP Code:
    $model = new Model();
    $view = new View(null$model);
    echo 
    $view->output(); 
    ?

    To go even further, if I wanted to have an even simpler static page, could I do without the model as well?
    PHP Code:
    $view = new View(nullnull);
    echo 
    $view->output(); 
    The model provides data to the view but if the view only outputs some simple html and doesn't require any data from the model then would it be a good idea to allow views without a model? I suppose this would not be MVC anymore, but perhaps an MVC system could allow to be a V system on some requests?

  8. #8
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Well even better:

    PHP Code:
    $view = new View();
    echo 
    $view->output(); 
    The view shouldn't ask for parameters if it's never going to need them. However, if the view can optionally have a model/controller then yes it makes sense to ask for them. It depends what the view is doing, but it should never ask for constructor arguments if it's never going to use them.

    Edit: Realistically though, for a "static page" you'll probably define it in this kind of way so that it's reusable.

    PHP Code:
    class StaticView {
        private 
    $model;

        public function 
    __construct(StaticModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            return 
    $this->model->getStaticPage();
        }

    You could then optionally have a controller which set a state on the model saying which page to load. The model could then load the page from somewhere. It's a good example of MVC in action actually: The model is interchangeable and could then be substituted to load the static HTML from the filesystem, a database, a web service etc.

    Edit2: And before someone says "Well the view is redundant then!" the view could be substituted to one which does some post-processing on the HTML that's been received.

  9. #9
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    Edit: Realistically though, for a "static page" you'll probably define it in this kind of way so that it's reusable.
    Thanks, this makes sense and the StaticPage view looks quite convenient!

    One more question, on your site you provide an example where UserEditController and UserListController extend Controller and it's not really clear why you are extending Controller. I suppose Controller is some kind of default controller but I can't see anything in it that is actually inherited and used. And if controllers are supposed to be minimalist is it worthwhile creating hierarchies where one extends the other?

  10. #10
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,149
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Sorry, I just have to ask one quick question.

    Quote Originally Posted by TomB View Post
    PHP Code:
    class StaticView {
        private 
    $model;

        public function 
    __construct(StaticModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            return 
    $this->model->getStaticPage();
        }

    Presumably getStaticPage() is returning HTML. Why are we delegating presentation to the model?
    "First make it work. Then make it better."

  11. #11
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    Presumably getStaticPage() is returning HTML. Why are we delegating presentation to the model?
    My guess is that HTML returned by getStaticPage() comes from a data source like a database. So the view is actually using the model to get data from the database, the model is not creating the presentation. We can imagine that the admin panel may have a rich text editor for the page content. This can be looked upon as incorrect because we are throwing HTML into the db and then we are using the value, which is a mix of presentation and content (and possibly some behaviour in javascript) but in the real world this is often the most practical solution. TomB may correct me if I'm wrong on this

  12. #12
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,149
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    My guess is that HTML returned by getStaticPage() comes from a data source like a database. So the view is actually using the model to get data from the database
    I suppose I didn't notice that we were assuming that the static HTML was stored in a database.
    "First make it work. Then make it better."

  13. #13
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by Jeff Mott View Post
    I suppose I didn't notice that we were assuming that the static HTML was stored in a database.

    We're not assuming anything, that's the point. The model could get the HTML from anywhere, the view doesn't care. MVC provides a basic method of applying proper Separation of Concerns to your code. Should a model load HTML? Sure, why not! It is just data after all! A model almost certainly shouldn't be generating HTML on the fly, but loading data is loading data, the model doesn't care whether that data is HTML or any other format or what the view is going to use it for.

    Answer this: Should the model load a CSV file? An XML file? Obviously, the answer is yes. A HTML file is no different. You wouldn't question a MVC set up where the model loaded a CSV file and the view outputted some HTML using data from the CSV (via the model). Why question a MVC set up where a model loads an HTML file and outputs a CSV (or in this case, outputs HTML)? The separation of concerns is the same; as long as the View doesn't know the implementation of the model and the Model doesn't care what the view does with the data then we're all good!

    You may wish to load the HTML and extract some specific data from it prior to displaying it, you may wish to display it as is. The goal here is to separate the loading and processing of the data. This allows us to use the same processing logic on data from multiple sources or apply different processing to data from the same source.

  14. #14
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    I'll amend the example there, occasionally it's useful for a controller to extend a base class but it's certainly not necessary and in the case it isn't. I'll make the example more clear.

  15. #15
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by TomB View Post
    I'll amend the example there, occasionally it's useful for a controller to extend a base class but it's certainly not necessary and in the case it isn't. I'll make the example more clear.
    Okay, that's great! Thanks for your answers, Tom, they are very instructive.

    Off Topic:

    If I may have a suggestion for your site, it would be great if your code examples were actually tested (not unit-tested but simply run by you to check if they execute fine). I tried getting to work your Dice for routing as you explained it but the code fragments had a few typos I had to correct and in the end Dice errored out not being able to find a component whose name started with '$route_' (xdebug pointing to line 33). Probably these are trivial things to correct by someone who knows how these patterns work but a bit more difficult for someone who is just learning them. I'll get to play with DI for routing maybe at some later point so I'm not asking you for help with this now, I just want to make a general suggestion. Also, the working example of Router is not working. Apart from that you've got a lot of useful information on yout site!

  16. #16
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    I'll provide a practical example, because it's probably easier to follow. I won't use HTML as an output format as that's too weighted in PHP and makes things less obvious.



    PHP Code:
    interface TomsModel {    
        public function 
    getData();
    }

    interface 
    TomsView {
        public function 
    output();
        public function 
    getMimeType();

    Let's assume getData() provides a key => value array of some arbitrary data and view:utput() returns a string and getMimeType() returns the MIME type of the data in output();

    I can now define some views to display the data in a variety of formats:

    PHP Code:
    class JSonView implements TomsView {
        private 
    $model;

        public function 
    __construct(TomsModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            return 
    json_encode($this->model->getData());
        }

        public function 
    getMimeType() {
            return 
    'application/json';
        }
    }


    class 
    CsvView implements TomsView {
        private 
    $model;

        public function 
    __construct(TomsModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            
    $stream =  fopen('php://temp/');
            foreach (
    $this->model->getData() as $row) {
                
    fputcsv($stream$row);    
            }
            return 
    stream_get_contents($stream);
        }

        public function 
    getMimeType() {
            return 
    'text/csv';
        }
    }



    //Using the pchart library to display the data as a pie chart: http://pchart.sourceforge.net/documentation.php?topic=exemple15
    class PieChartView implements TomsView {
        private 
    $model;

        public function 
    __construct(TomsModel $model) {
            
    $this->model $model;
        }

        public function 
    output() {
            
    $dataSet = new pData;
            foreach (
    $this->model->getData() as $row) {
                
    $dataSet->addPoint($row);
            }
            
    $dataSet->addAllSeries();

            
    $chart = new pChart(300300);    
            
    $chart->drawBasicPieGraph($dataSet->GetData(), $dataSet->GetDataDescription(),120,100,70,PIE_PERCENTAGE,255,255,218);  
            return 
    $chart->render();
        }

        public function 
    getMimeType() {
            return 
    'image/png';
        }



    The beauty of this is that these views could work with any of these models:


    PHP Code:
    class DatabaseModel implements TomsModel {
        private 
    $pdo;

        public function 
    __construct(PDO $pdo) {
            
    $this->pdo $pdo;
        }

        public function 
    getData() {
            return 
    $this->pdo->query('.....');
        }
    }



    class 
    CSVModel implements TomsModel {
        private 
    $csvFile;

        public function 
    __construct($csvFile) {
            
    $this->csvFile $csvFile;
        }

        public function 
    getData() {
            
    $returnData = array();
            if ((
    $handle fopen($this->csvFile'r')) !== false) {
                    while ((
    $data fgetcsv($handle1000",")) !== FALSE) {
                        
    $returnData[] = $data;
                }

                   }
                
    fclose($handle);

            return 
    $returnData;            

        }
    }


    class 
    SatelliteInteceptorModel implements TomsModel {


        public function 
    __construct(SatelliteStream $statelliteStream) {
            
    $this->satelliteStream $statelliteStream) ;

        }

        private function 
    decode($data) {
            
    //...
        
    }

        public function 
    getData() {
            
    $data $this->decode($this->satelliteStream->interceptData);

            
    //format $data into an array that the view is expecting
            
    return $data;
        }


    Any of these models can be used with any of the views. This is where MVC shines because the data source is entirely disconnected from the display logic. The model provides the view with some data in a format they both know about. The view does whatever it likes to this data in order to display it and the model takes data from any source and puts it into the format that the view can use. This makes the display logic reusable because it can be used with any of the models and it means a new model can be added without having to write a new view for it.

    For example, I could write a new model which combined data from two separate CSV files and still use the same view.

    As you see, it's possible to go from CSV -> CSV using my example code and have a lot of redundant processing but, this redundancy is what allows the view to be agnostic of the data source and is a very small price to pay for having interchangeable components. Yes the view could just load the CSV directly and output it, but then its data source must always be a CSV file.

  17. #17
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,149
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Actually, nevermind. I'll butt out. Sorry for turning this thread debate-ish. I'll stop injecting myself into the conversation.
    "First make it work. Then make it better."

  18. #18
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,149
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    I agree that injecting a templating library/component is definitely the best option. Though, I expect the view would still need to decide for itself which template to render, because the template may need to vary depending on the user input (a result from the controller). For instance, if user input doesn't validate, then the view may need to render a form with errors. Or if the input does validate, then the view may need to render a success message or perhaps a redirect response. Though, I definitely don't think the model should be involved with the templates in any way, shape or form. The model is supposed to be about domain logic, and templates are about presentation.
    "First make it work. Then make it better."

  19. #19
    padawan silver trophybronze trophy markbrown4's Avatar
    Join Date
    Jul 2006
    Location
    Victoria, Australia
    Posts
    4,095
    Mentioned
    28 Post(s)
    Tagged
    1 Thread(s)
    For what it's with worth(not much) I find these discussions interesting but no MVC framework that I've come across is even a close contender to the elegant simplicity of Rails.
    So, if I were using PHP I would try to implement the conventions and methods of Rails because I think they make a lot of sense.

    I'd try to implement code that looked something like this.. lots of psedo code and I haven't written php in years.
    --

    I would set up routes somewhere which map HTTP to a controller and action

    # routes
    Code:
    method url                 controller#action  helper_method
    GET    /users              users#index        users_path
    POST   /users              users#create       users_path
    GET    /users/new          users#new          new_user_path
    GET    /users/:id/edit     users#edit         edit_user_path(user)
    GET    /users/:id          users#show         user_path(user)
    POST   /users/:id          users#update       user_path(user)
    POST   /users/:id/delete   users#delete       delete_user_path(user)
    The model should contain the validations
    # models/user.php
    Code php:
    class User extends ApplicationModel {
      public $name = ''
      public $email = ''
     
      public function validate() {
        $errors = [];
        if ($this->name == '') {
          $errors['name'] = 'Name cannot be blank';
        }
        if (!filter_var($this->$email, FILTER_VALIDATE_EMAIL)) {
          $errors['email'] = 'Email is invalid';
        }
        return $errors
      }
    }
    The controller should expose methods to the view to consume data as well as handling params to the actions and deciding what to do
    # controllers/users_controller.php
    Code php:
    class UsersController extends ApplicationController {
     
        // expose an api to the views
        public function users {
          return User.all()
        }
     
        public function user {
          if (params('id')) {
            return User.find(params('id'))
          }
          else {
            $user = new User
            if (params('user')) {
              $user.attributes(params('user'))
            }
            return $user
          }
        }
     
        // actions
        public function create() {
          if (user().save()) {
            flash('success', 'User created!');
            redirect_to(users_path());
          }
          else {
            flash('error', 'Errors');
            render('new');
          }
        }
     
        public function update() {
          if (user().save()) {
            flash('success', 'User created!');
            redirect_to(users_path());
          }
          else {
            flash('error', 'Errors');
            render('new');
          }
        }
     
        public function delete() {
          user().delete()
          flash('success', 'User deleted!');
          redirect_to(users_path());
        }
    }
    The view should have access to the exposed methods of the controller and helper methods like named routes and flash
    # views/users/index.php
    Code php:
    <h1>Users</h1>
    <ul>
    <?php foreach (users() as $user) { ?>
      <li><?php echo $user.name ?></li>
    <?php } ?>
    </ul>
    # views/users/show.php
    Code php:
    <h1><?php echo user().name ?></h1>
    <p>Email: <?php echo user().email ?></p>
    # views/users/new.php
    Code php:
    <h1>New User</h1>
    <form action="<?php echo users_path() ?>" method="post">
      <?php render('form') ?>
      <input type="submit" value="Create">
    </form>
    # views/users/edit.php
    Code php:
    <h1>Edit User</h1>
    <form action="<?php echo user_path(user()) ?>" method="post">
      <?php render('form') ?>
      <input type="submit" value="Update">
    </form>
    # views/users/_form.php
    Code php:
    <div>
      <label for="user_name">Name</label>
      <input id="user_name" name="user[name]" value="<?php params('user[name]') ?>">
    </div>
    <div>
      <label for="user_email">Email</label>
      <input id="user_email" name="user[email]" value="<?php params('user[email]') ?>">
    </div>
    I'd have an application layout which renders the views
    # views/layouts/application.php
    Code php:
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>untitled</title>
    </head>
    <body>
    <?php if (flash('error')) {
      <div id="error"><?php echo flash('error') ?></div>
    <?php } ?>
    <?php if (flash('success')) {
      <div id="success"><?php echo flash('success') ?></div>
    <?php } ?>
    <div id="content">
      <?php render_view() ?>
    </div>
    </body>
    </html>
    I'd abstract everything that you want to be able to reuse across your models controllers and views into a separate part of the app.

    # framework/application_model.php
    Code php:
    class ApplicationModel {
     
      public static function all() {
        // select * from <pluralised lowercased __CLASS__>;
      }
     
      public static function find($id) {
        // select * from table where id=$id;
      }
     
      public function save() {
        $errors = $this->validate()
        if ($errors.length == 0) {
          // UPDATE table where id=$id
        }
        else {
          return false;
        }
      }
     
      public function delete() {
          // DELETE FROM table where id=$id
      }
     
      public function attributes($attributes) {
        foreach($attributes as $attr => $value) {
          $this->$attr = $value
        }
      }
     
    }
    # framework/application_controller.php
    Code php:
    class ApplicationController {
      public function params($key) {
        // map nested params ?user[name]=mark&user[email]=markbrown4@gmail.com
        // params('user') == { name: 'mark', email: 'markbrown4@gmail.com' }
        // params('user[email]') == 'markbrown4@gmail.com'
      }
     
      public function redirect_to($url, $flash) {}
     
      public function flash($key, $value) {
        // set a short lived variable in session
      }
     
      public function render($view) {
        // render a view from a controller
      }
     
      // 7 rest actions
      public function index() {}
      public function show() {}
      public function new() {}
      public function edit() {}
      public function create() {}
      public function update() {}
      public function delete() {}
    }
    # framework/application_view.php
    Code php:
    class ApplicationView {
      public function flash($key) {
     
      }
      public function render($partial) {
        // render '_$partial.php'
      }
     
      public function render_view() {
      }
    }

    I just thought this may give you some ideas to play with.

  20. #20
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,048
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    Quote Originally Posted by markbrown4
    For what it's with worth(not much) I find these discussions interesting but no MVC framework that I've come across is even a close contender to the elegant simplicity of Rails.
    I was going to say… it looks like you just provided pseudo code for replicating a rails like interface in PHP. Not that it's a bad thing…

    Quote Originally Posted by markbrown4
    So, if I were using PHP I would try to implement the conventions and methods of Rails because I think they make a lot of sense.
    Bingo, we can debate all day that rails is not true MVC but the fact of the matter is the web based derivation of MVC exists because it works very well in a none persistent environment using http.

    Quote Originally Posted by markbrown4
    I'd try to implement code that looked something like this.. lots of psedo code and I haven't written php in years.
    I would recommend the op use Symfony 2 instead re-inventing this wheel. Not to mention Symfony 2 goes way beyond MVC providing strategies for managing dependencies to promoting package management (similar to gems) using composer. Though if the op really has an itch to reinvent the wheel more power to them I guess…
    The only code I hate more than my own is everyone else's.

  21. #21
    padawan silver trophybronze trophy markbrown4's Avatar
    Join Date
    Jul 2006
    Location
    Victoria, Australia
    Posts
    4,095
    Mentioned
    28 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by oddz View Post
    I would recommend the op use Symfony 2 instead re-inventing this wheel. Not to mention Symfony 2 goes way beyond MVC providing strategies for managing dependencies to promoting package management (similar to gems) using composer. Though if the op really has an itch to reinvent the wheel more power to them I guess…
    Aye, I'm not familiar with any of the PHP MVC frameworks out there, I'd heard Cake was Rails inspired but I haven't explored it.
    You're right, those frameworks should be a heck of a lot better than something you can write from scratch - It sounded like the OP was wanting to try to do that though, "what is a good way to implement MVC in PHP?"

    What is the least and most expressive code you can write to get the task done?

  22. #22
    SitePoint Addict bronze trophy
    Join Date
    Apr 2013
    Location
    Ithaca
    Posts
    338
    Mentioned
    6 Post(s)
    Tagged
    1 Thread(s)
    I think it depends on what you wish to accomplish here. Reinventing the wheel is not recommended for working on a project with a strict timeline, especially for commercial project. However, if your primary goal is to learn the basics behind MVC and true OOP, building your own framework will help you a lot.

  23. #23
    SitePoint Guru bronze trophy
    Join Date
    Dec 2003
    Location
    Poland
    Posts
    925
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)
    Yes, I'm experimenting with the concept to understand how it works in detail and if it proves to be worthwhile I'll start implementing it in my projects. That's why I'm starting from scratch. The other reason is that it's hard to find a ready-made framework that would be pure MVC - and because I have already worked with frameworks that are MVC-like to a greater or lesser extent (including my own that works very well for commercial projects) I have no intention dabbling with them. It's not that I find them bad, I just want to see how MVC plays out in its purest possible implementation and possibly simplest as well. Most frameworks are huge, I want something simple but good and add to it over time as my requirements grow.

  24. #24
    padawan silver trophybronze trophy markbrown4's Avatar
    Join Date
    Jul 2006
    Location
    Victoria, Australia
    Posts
    4,095
    Mentioned
    28 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    Yes, I'm experimenting with the concept to understand how it works in detail and if it proves to be worthwhile I'll start implementing it in my projects. That's why I'm starting from scratch. The other reason is that it's hard to find a ready-made framework that would be pure MVC - and because I have already worked with frameworks that are MVC-like to a greater or lesser extent (including my own that works very well for commercial projects) I have no intention dabbling with them. It's not that I find them bad, I just want to see how MVC plays out in its purest possible implementation and possibly simplest as well. Most frameworks are huge, I want something simple but good and add to it over time as my requirements grow.
    You will learn a lot doing that, I'd encourage you to focus on the API and DRY, how much code can you get away with not writing.
    I'm curious why you're interested in a 'pure' implementation. Surely it's more valuable to have the best implementation

  25. #25
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,149
    Mentioned
    14 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Lemon Juice View Post
    I just want to see how MVC plays out in its purest possible implementation and possibly simplest as well.
    You may be interested in Fowler's (non-PHP) article on MVC, as well as the (I believe) original implementation in Smalltalk. Personally, what strikes me is just how little is actually applicable to server-side Web applications. So at the very least, it should be interesting to see what you come up with.
    "First make it work. Then make it better."


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •