Langdon - I am still in two minds as to whether a non-Javascript
version is really necessary.  Because if it is, then I'll need to
write some alternative functionality in some places.  But being able
to use the app on my mobile phone really does sounds neat.
Can you expand on what Ajax specific actions you may create?  The vast
majority of our controllers just have CRUD actions, so there is very
little difference whether the action is called from Ajax or a normal
form submission.  Javascript may make the interface a drag & drop, or
a double-click to edit, but our controller interface primarily remains
index/add/edit/delete etc - it's only how the result of these actions
is returned that needs to be different.

Jitka - I hadn't thought of using the beforeRender and afterRender of
a helper, thats a good idea.  It should be able to simplify one aspect
of my current method.  I agree that there should be a minimum of code
in the controller that applies to a single view type, and tips for
attaining this is what I'm after :)


Anyway, as for the method that I've currently employed.  This is
working well, but I would appreciate any comments as to how this
method would / wouldn't be appropriate for your own applications.

The problem identified is that while the actual functionality of a
controller action should be the same no matter how it was called, each
UI may expect a different format response (ie rendered HTML,
redirects, JSON, AMF).  A simple example of a common action would be:

function edit($id){
        if ( ... not authenticated to edit this id ... ){
                // exit point 1
        }

        if(empty($this->data)) {
                $this->data = $this->Model->read(null, $id);

                // exit point 2
        } else {
                if($this->Model->save($this->data)) {
                        // exit point 3

                } else {
                        // exit point 4
                }
        }
}

with four possible exit points, each indicating a different response
for the action.  Now the method decided upon was to execute a single
function in each of these, which would provide the correct response
based upon the request type, and some passed options (whether this was
successful or an error, and whether the database was modified in this
action).  Something like:

function edit($id){
        if ( ... not authenticated to edit this id ... ){
                return $this->_response( array('success'=>false, 
'modified'=>false,
'msg'=>'Detailed error message', 'redirect'=>'/redirect/location') );
        } else {

                if(empty($this->data)) {
                        $this->data = $this->Model->read(null, $id);

                        return $this->_response( array('success'=>true, 
'modified'=>false,
'vars'=>array('view','data')) );

                } else {
                        if($this->Model->save($this->data)) {
                                return $this->_response( array('success'=>true, 
'modified'=>true,
'msg'=>'Success message', 'redirect'=>'/redirect/location') );

                        } else {
                                return $this->_response( array('success'=>true, 
'modified'=>false,
'msg'=>'Fails validation message',
'vars'=>array('view','data','validation'=>array('Model')) );
                        }
                }
        }
}

In this initial example the options that can be passed are:
success - whether this was a valid request made, or are you trying to
edit someone elses data?
modified - whether the database has been changed by this request - so
some screens may need to be refreshed
msg - Any status message
redirect - If this exit point should not result in a page render, the
desired redirect location
vars - for those output targets that expect an array of data (JSON,
Flash), what data to provide (set view vars, $this->data, validation
info etc)

In further implementation I've also found it necessary to allow a
specific view / layout / file to be rendered, so these options can be
in there too.


The skeleton of the _response function is:


        function _response( $options )
        {
                // compile an array of data, from the requested $options['vars']
                $return_data = array('view'=>$this->viewVars, 
'data'=>$this->data);

                if ( isset($this->RequestHandler) and 
$this->RequestHandler->ext ==
'json' ){
                        // The requester just wants the data as JSON
                        $this->set('JSON', $return_data);

                        $this->RequestHandler->respondAs('js');
                        $this->viewPath = 'json';
                        $this->render('json_vars', 'ajax');


                } else if ( isset($this->RequestHandler) and 
$this->RequestHandler-
>isAjax() ){
                        // Ajax.Updater wants a rendered page, with an optional 
JSON header

                        // set a JSON header of the passed options, for the 
success /
modified etc
                        header( 'X-JSON: '.$json_header_data_string );

                        // if we wanted to redirect, then just render a blank 
page of the
Session flash
                        // otherwise render the specified action/layout/file if 
provided,
or the default
                        $this->render( $action, $layout, $file );


                } else if ( defined('CAKE_AMFPHP_REQUEST') ){
                        // Just return the requested data, CakeAMFPHP will 
convert to AMF
data
                        $amf_data = am( $options, $return_data );
                        return $return_data;


                } else {
                        // The normal html response.
                        // Set a session flash from the provided message
                        $this->Session->setFlash( @$options['msg'] );

                        // Redirect if a location is provided
                        if ( isset($options['redirect']) ){
                                $this->redirect( $options['redirect'] );
                                exit();
                        }

                        // Render either the provided action/layout/file, or 
the default
                        $this->render( $action, $layout, $file );
                }
        }


The advantage to this approach is that with fairly minor modifications
(just to call the _response action), any action can now be requested
as .json, or via Flash, and just the normal set view data (and
validation errors etc) are supplied.

The disadvantage to this approach is that there are bound to be fringe
cases where something non-standard needs to happen, for one particular
UI.  And this will mean either adding options to the passed array, or
adding UI request type checks to the actual actions...  I'm
particularly interested if this looks like it could not work with your
app.

Regards,
Grant Cox


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Cake 
PHP" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/cake-php?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to