We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Splitting logic to indexAction and editAction

class ProfileController extends \Phalcon\Mvc\Controller
{
    // route GET /profile
    public function indexAction()
    {
        $user = $this->_getUser();
        $this->view->pick('registered/profile'); // <form action="/profile/edit" method="post"><input type="text" name="username" value="{{ user.fullname }}" /> ... </form>
        $this->view->setVar('user', $user);
    }

    // route POST /profile/edit
    public function editAction()
    {
        $validator = new Validation();
        $fullName = $this->request->getPost('username', 'string');
        $validator->rules('username', array(
            new Validator\PresenceOf(array('message' => 'Please input username')),
            //...        
        ));

        $validator->validate($this->request->getPost());
        $validationResult = $validator->getMessages();
        if (count($validationResult))
        {
            // *****************************************
            // here I need redirect user to indexAction, i.e. /profile, not render the same in /profile/edit
            // How can I pass all validation messages to indexAction?
            // *****************************************
            return;
        }

        $user = $this->_getUser();
        $user->fullname = $fullName;
        $user->save();
        $this->response->redirect('/profile');
    }

    /**
     * @return User
     */
    private function _getUser()
    {
        $userId = $this->session->get(User::SESSION_ID);
        $user = User::findFirst(array("id = ?0", "bind" => array($userId)));
        return $user;
    }
}

Can I use this flow (i.e., show content and validation messages in one action, and receive data from user in another action)? Of course, I can save validation messages (for example, in session) and get it back in indexAction, but I think it's tricky way.



9.8k
edited Sep '15

Sorry, i haven't read carefully. $this->dispaltcher->forward(........). This as i know is the basic tool for forwarding flow without using the response->redirect. By this and maybe if the forwarded action is in the same controller you can retain some variables that are already defined in a class or POST and globals. Then validation messages could be in $this->validationResult or self::$validationResult or so.

edited Sep '15

If you use $this->dispaltcher->forward, user see results of indexAction (UI, validation messages), but remains on /profile/edit . I don't want this behavior, because:

  1. I haven't GET route to /profile/edit and don't want to add it, because it's incorrect - "edit" action will not be called without data editing.
  2. If user close browser and open it again, browser make GET request to last page /profile/edit and user will receive error. Or I need workaround, it's not good.


9.8k
edited Sep '15

I have such a situation that i store some messages during response redirect (redirecting when user is authorised). So as you mentioned session would be good. You would need to set serialise and then unserialise the messages somehow, if the messages are difficult to serialise/unserialise you would need to make some simple array out of it and then serialise.

Something like that $this->session->set('outstanding_messages_from_redirected_page', serialize($validationResult));
And then on the redirected page: $validationResult=unsersialize($this->session->get('outstanding_messages_from_redirected_page'));
And don't forget to clean the session entry.

You know something like that. Sorry if it once again is not useful for you :)



9.8k

It would be good to check how much data such a serialized object have. You know strlen $this->session->get('outstandingmessagesfromredirectedpage') If it's was too big the simple array would be better.

Thank you. Maybe, people provide another solution, so I not close this answer yet. Also today I found another acceptable solution myself: Don't add /profile/edit URL at all but assign POST /profile route to editAction and GET /profile route to indexAction. After it I can use $this->dispaltcher->forward and private variable in controller to save message.



9.8k
edited Sep '15

Additionall thing for forum users. I've learned that there is $this->flashSession available if someone uses $this->flash system which aims to print messages after redirection (is uses session for it). There is documentation for it. Documentation states that you need to start session first to use this, and at the moment i don't know whether or not you must register flashSession in di manually.

Your business logic - mostly validation etc should be stored in model. You can do it by validation() function in model. Any database actions should be done in repositories like getting/storing/saving/deleteing something - they can be static helpers or just services. Application logic should be stored in services. In controllers you should have only getting params/returning response/checking security(acl)

Validation of user input is the responsibility of Controller in common MVC understanding. Model is for business logic, all data that controller gives to model will be safe and clean.

Yea, of corse, but why do that, when validation() will handle it just fine ? Just use $user->save($params,$whitelist - dont forget about setting it) and validation() will user input too, im using it and i like it more than validating user input in controller too.