开发者

When Should The Session Variable Be Cleared?

The spec for my application states that two users must be able to work on the same record of the web app at the same time without clobbering one another's data (unless, of course they each modify the same field, then it would be the last one to save wins.) It's a medical system, and it's conceivable that the billing people could be working on a record while a tech is updating another section of the record.

So, when the user saves a form, the system should only change the values in the database that the user actually changed. Because I'm using CakePHP, I'm trying to deal with this on the PHP side of things rather than doing it with JavaScript before sending the form data.

My first thought was to check the values in the database immediately prior to the save and only change the values that are not the开发者_开发问答 same. But, if User A saves the form after User B has opened it, and then User B saves the form, then User A's changes will be overwritten by the old data in User B's form.

My next thought was to save the values of the form in the user's session. So, when he opens the form, the data gets stored in the session, and only the values that have changed from what was in his session will get updated in the database. So, the Session would have serialized $old_data in it.

The problem here is that it would cause grief if the user tries to open two records at the same time and then save. So, I need to have the session data stored by record id.

And, this leads me to the final problem. I can unset the data from the session when the user saves the form (and then re-fetch it immediately if they render the same record again). But, this doesn't deal with the situation when the user doesn't save the form. If they open the form and read it and then go away, gradually their session is going to get full of debris.

So, when is the best time and method to clean up the session garbage without wiping out data that they actually do need in the session?


I was up for a bit of a challenge this afternoon so gave this one a try - mainly to see if all the logic could be encapsulated into a component, without having to manually call the code from controller actions.

The resulting SaveDiff component hasn't been used in production so will need some testing. (Feel free to make changes on GitHub if you find any bugs.)

<?php
class ModelsController extends AppController {

    public $components = array(
        'SaveDiff' => array( # include the component
            'actions' => array('edit'), # tell it which actions to work with
        ),
    );

    public function edit($id) {
        $record = $this->read(null, $id)
        # not found
        if (!$record) {
            $this->cakeError('error404');
        }
        # populate form
        if (!$this->data) {
            $this->data = $record;
            return;
        }
        # save form
        $saved = $this->Model->save($this->data);
        if (!$saved) {
            $this->Session->setFlash('Failed validation');
            return;
        }
        # success
        $this->Session->setFlash('Saved changed fields');
        $this->redirect(array('action' => 'index'));
    }
}

During the controller action (ModelsController::edit() in the above example), populate the form using $this->data. The component will fire after the controller action has rendered and save $this->data to the session. Well, unless validation has failed, because we are probably dealing with user-submitted data at that point.

When new requests come in the component fires again, before the controller action, and cleans any unchanged data out of $this->data (by comparing it to the session), meaning it should meet your requirements (only changed fields) and is ready to save.

Note: I have noticed my SaveDiffComponent::extractChanges() method isn't working quite right but I will leave that for you. Make sure to use DebugKit when testing (the Session and Variables tabs) and remember you need to refresh twice to see new session data (because PHP can't read new session data until the next request.. or something like that).


you could put each item in the session data, with each record being its own array. aka $_SESSION["client1"] would be the information for the first client, whereas $_SESSION["client2"] would be the information for the second client.


Thanks for outlining your thought process.

My next thought was to save the values of the form in the user's session. So, when he opens the form, the data gets stored in the session, and only the values that have changed from what was in his session will get updated in the database. So, the Session would have serialized $old_data in it.

I think this IS the best way to do it.

And, this leads me to the final problem. I can unset the data from the session when the user saves the form (and then re-fetch it immediately if they render the same record again). But, this doesn't deal with the situation when the user doesn't save the form. If they open the form and read it and then go away, gradually their session is going to get full of debris.

Keep in mind that the session will eventually expire. At that time, old session data will be removed. If that is too long for you, you could add a datetime to the session data and when a page is loaded, loop through the session data to remove outdated information.

The frequency of this house-cleaning is up to you. I would set it to whatever value you think is the maximum amount of time it would take a person to work on the particular form + 1 minute.

Hope that helps!


I'm not sure about the design of your system, but as you mention this is a medical system, is there some sort of revision identifier to the form? If so, you could have a hidden field that keeps track of the starting point for both users, then can still compare to what has changed without needing to pull so much into the session object.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜