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

Form processing best-practice / best-method

Hey All, I'm kind of a beginner with PhalconPHP but loving it so far.

I'm having some trouble understanding one thing, even after reading the documentation I've seen no example of how to handle form submition.

The two only options I thought of is

  1. the form action could point to controller/add in POST which would need a addAction() method in my controller and then bind $_POST to a Model, and save that after validation. But that means I have to do some sort of "if" to make sure If i'm in POST (handle data) or GET (show form).

  2. Use the Event Callbacks and perform the save on the "afterValidation" of a Phalcon\Mvc\Form ... but again, not sure if this makes sense, plus - I might not use Phalcon\Mvc\Form because I'm not sure how to make it print out the specific HTML structure I need.

So those are the two options I thought of, would love to hear your pointers / opinions on this.

Thank you very much Shai.



5.1k

I like the classic CRUD separation so I will say that the best practice is something like this:

class Crud extends Controller
{
    protected $successMessage = 'Action has been successful.';

    public function newAction()
    {
        $this->view->form = new MyForm();
    }

    public function createAction()
    {
        $this->checkRequest();

        try {
            $this->processForm($this->request->getPost());
            $this->view->disable();
            $this->flash->success($this->successMessage);
            $this->redirect(); // redirect to edit or index
        } catch (Exception $e) {
            $this->flash->error($e->getMessage());
        }

        $this->dispatcher->forward(array('action' => 'new'));
    }

    public function editAction($id)
    {
        $this->view->record = MyModel::findById($id);
        $this->view->form =  new MyForm($this->view->record);
    }

    public function updateAction($id)
    {
        $this->checkRequest();

        try {
            $record = MyModel::findById($id);
            $this->processForm($this->request->getPost(), $record);
            $this->view->disable();
            $this->flash->success($this->successMessage);
            $this->redirect(); // redirect to edit or index
        } catch (Exception $e) {
            $this->flash->error($e->getMessage());
        }

        $this->dispatcher->forward(array('action' => 'edit'));
    }

    protected function checkRequest()
    {
        if (!$this->request->isPost()) {
            throw new MyPostRequiredException();
        }
    }

    public function deleteAction($id)
    {
        $this->view->disable();

        try {
            $this->scaffolding->doDelete($id);
            $this->flash->success($this->successMessage); 
        } catch (Exception $e) {
            $this->flash->error($e->getMessage());
        }

        $this->redirect(); // redirect to index/list action or something
    }

    private function processForm($postData, $model = null)
    {
         // perform your binding, saving etc., throw exceptions in case of failure or if form is not valid
    }
}

Ofcourse we have some code repetition here. some things can be done other way, but this is just simple example. Main advantage of flow like this is clear separation for each process. In newAction volt template you have form pointed to createAction and in edit volt template - pointed to update.

Cheers!

OK, That makes total sense. Thanks for writing this great example and helping!

So my new.volt form action would just be with an action="/myobject/create" with POST ?

So why do I need the new MyForm(); ? Doesn't that create the actual HTML as well ?

Thanks for clarifying. Shai



5.1k
edited Aug '14

Propably you are thinking about this part of Phalcon: https://docs.phalcon.io/en/latest/reference/tags.html#creating-forms but what we are using here is: https://docs.phalcon.io/en/latest/reference/forms.html

Especially, check this part: https://docs.phalcon.io/en/latest/reference/forms.html#forms-entities

Hope it will help, good luck!

Ok, trying to implement this practice and i'm still having some logical issues / midunderstanding ...

I'm not sure why do I even need a Form() object to begin with , Couldn't I just make my form in my new.volt file as I do now, and then just point to to /element/create and have createAction() process the POST data?

Or does the Form object organizes this process and lets me handle the data more easily ?