Using the same form to create and edit the same entity

Creating and editing an entity are common tasks that you can see every day. They are very similar but there are some small differences: for example your entity may have foreign keys you don't want to make editable. KForm aims to solve this problem easily, automatizing the progress as far as it's possible.

Example code: you have a forum topic. It has got a title, and three non-editable properties: a primary key, a foreign key to the parent category, and an other foreign key to the topic creator user.

Our form is very simple, it's definition is:

<?php
return array(
    'result_type' => 'array',
    'fields' => array(
        array(
            'name' => 'title',
            'type' => 'text',
            'label' => 'title: ',
            'validation' => array(
                array(
                    'max_length' => true,
                    'params' => array(32)
                )
            )
        ),
        array(
            'type' => 'submit',
            'value' => 'Ok'
        )
    )
);

And the two controller methods to create and edit a topic:

        public function action_create() {
        $view = new View('kform/hello');
        $form = new KForm('topic');
        $view->form = $form;
        if (Request::$method == 'POST' && $form->populate($_POST)) {
            $data = $form->result();
            $data['category_fk'] = 10;
            $data['creator_fk'] = 20;
            $data['id'] = 1;
            print_r($data);
            Session::instance()->set('data', $data);
        }
        $this->request->response = $view;
    }

    public function action_edit() {
        if ( Session::instance()->get('data') == null) {
            $this->request->redirect('/kform/create');
        }
        $view = new View('kform/hello');
        $form = new KForm('topic');
        if (Request::$method == 'POST' && $form->populate($_POST)) {
            $data = $form->result();
            print_r($data);
        } else if (Request::$method == 'GET') {
            $form->pre_populate(Session::instance()->get('data'));
        }
        $view->form = $form;
        $this->request->response = $view;
    }

With the create action the user can create a topic, just as simply as you can see it in the hello world kform tutorial. After successful form submit we set the foreign keys and the primary key - of course in a real-world application it would be done differently, but this applogic-stub is enough for the example. For the same reasons here we store our entity in the session.

In the edit action we first check if is there any editable entity in the session, if not, we redirect the user to create. Then we create the view (which just renders the form) and the form. Then we get our new entity if it was a successful form submit the same way as we did at creation.

Th main point is the else clause. We load our existing entity into the form. The pre_populate method will save the properties of the entity which must not be rendered to the session, and after form submit, the result method will reload these properties into the result.

Configuration

KForm stores the editing progress ID in a hidden input in the rendered form. This identifies the progress if multiple editings are started in the same session. The name of this hidden input is configurable by the 'progress_key' config array item.

The unrendered properties of the entity are also stored in the session. You can configure the session key via the 'session_key' config array item which will be the 'namespace' for KForm.

Defining different properties for the form if runs in edit mode.

Once the pre_populate method is called, the form turns into edit mode. In this case you may want to render your form differently, eg. changing some labels, you don't want to render some fields, you want to change the value of the submit button.

You can declare these things in the config array.

If you want to use a different label for an input in edit mode, you should define your label this way:

'label' => array(
   'on_create' => 'label to be rendered when creating the entity',
   'on_edit' => 'label to be rendered at edit mode'
)

This works in the same way for 'label_key'-s and 'value' attributes (useful for submit buttons).

If you don't want KForm to render an input when it is in edit mode, in the field definition you have to add this item:
'hide_on_edit' => true