ZF and mysite.com/blog/topic/delete/5

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

koen.h
Forum Contributor
Posts: 268
Joined: Sat May 03, 2008 8:43 am

ZF and mysite.com/blog/topic/delete/5

Post by koen.h »

In another topic this url was mentioned:

mysite.com/blog/topic/delete/5

My question regarding this is twofold:
-with a url structure like this, are you tied to having your commands choose your view? Eg class topic with delete method is called here and at the end of the method you redirect to where you were coming from.
-would it work to reserver urls for view data and use post data for deleting/updating etc? That would mean a request has at least one action (viewing the resource) and optionally a post action.
User avatar
freeformer
Forum Newbie
Posts: 14
Joined: Tue May 13, 2008 1:54 pm
Location: UK

Re: ZF and mysite.com/blog/topic/delete/5

Post by freeformer »

You are able to specify the view that your controller should render. The default view to be loaded from your example would be topic/delete.phtml. This can be changed in the action of the controller.

I'm not entirely sure what your 2nd question is asking...

By default all controllers must have an indexAction() method. This is invoked if you visit mysite.com/blog/topic, for example.

It's pretty standard to then have the other actions in the same class, such as mysite.com/blog/topic/add, mysite.com/blog/topic/edit/4 etc.
koen.h
Forum Contributor
Posts: 268
Joined: Sat May 03, 2008 8:43 am

Re: ZF and mysite.com/blog/topic/delete/5

Post by koen.h »

I'm able to specify the view but some requests don't need a view. With te example url I gave, why would there be a view associated with the action of deleting topic number 5?

Some would counter that it doesn't make sense not to have a view for an url. But think eg ajax request to delete topic number 5: it just needs to update the model, not display a whole new page.

This could be taken care of in the controller (checking if the request is an ajax request and not render the view if that's the case). But why not keep this logic seperate of possible? Some urls map to actions that render a view, some don't.

Going one step further, GET requests map to actions responsible for rendering a view (the indexAction), POST requests to all other actions.
User avatar
freeformer
Forum Newbie
Posts: 14
Joined: Tue May 13, 2008 1:54 pm
Location: UK

Re: ZF and mysite.com/blog/topic/delete/5

Post by freeformer »

I like the idea of keeping requests that don't require views separate - it seems like a logical step to take to separate code that simply interfaces with the model separate from the code that communicates with both model and view.

Would it be best to define a set of URLs that map directly to those that shouldn't have a view rendered... or would it be best to sub-class a custom controller that performs a check to see if the request is an AJAX one?

This post is well timed as i'm about to begin writing an administration backend :)
koen.h
Forum Contributor
Posts: 268
Joined: Sat May 03, 2008 8:43 am

Re: ZF and mysite.com/blog/topic/delete/5

Post by koen.h »

The ajax request may require a view. I just gave that example because it's easy to imagine a request without a view with ajax. So I wouldn't code "ajax = no view" into your application.

I also don't think you need to the create a subset of urls for view/non-view requests.

A solution, that already can be implemented using most frameworks, is using the routes to map to controllers (or commands) that don't use views. Eg http://example.com/ajax/post/25/delete (though I prefer to use POST requests to for deletion).

I'm interested in ideas on how to make this better.
User avatar
freeformer
Forum Newbie
Posts: 14
Joined: Tue May 13, 2008 1:54 pm
Location: UK

Re: ZF and mysite.com/blog/topic/delete/5

Post by freeformer »

Just as a quick note on this topic:

I was reading the ZF documentation today - they implemented a way of checking if a request was AJAX by checking the HTTP HEADER.
7.4.2.4. Detecting AJAX Requests
Zend_Controller_Request_Http has a rudimentary method for detecting AJAX requests: isXmlHttpRequest(). This method looks for an HTTP request header X-Requested-With with the value 'XMLHttpRequest'; if found, it returns true.

Currently, this header is known to be passed by default with the following JS libraries:

Prototype/Scriptaculous (and libraries derived from Prototype)

Yahoo! UI Library

jQuery

MochiKit

Most AJAX libraries allow you to send custom HTTP request headers; if your library does not send this header, simply add it as a request header to ensure the isXmlHttpRequest() method works for you.
It may be rudimentary, but have your commands/controllers sub-class another with this sort of functionality that is executed automatically, you could set up custom routing based on the result...
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: ZF and mysite.com/blog/topic/delete/5

Post by Christopher »

I think you are confusing ZF's coupling of the Controller and View (for convenience) with some requirement that every Action have View. Controllers are for Request handling and program flow, so it is acceptable for a "delete" action to have no response itself. It would just redirect to some other Action.
(#10850)
User avatar
freeformer
Forum Newbie
Posts: 14
Joined: Tue May 13, 2008 1:54 pm
Location: UK

Re: ZF and mysite.com/blog/topic/delete/5

Post by freeformer »

That's understood, but I think that one of the questions raised in the thread was about separating the logic of detecting an AJAX request from individual controllers, and disabling the view requirement that may be the default.

My thoughts are that the super class would detect the AJAX request, disable any view/layout/rendering tasks that are normally called by default, then pass the request onto the Controller so that it can process as normal. Obviously in the action you would simply redirect to another controller/action
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: ZF and mysite.com/blog/topic/delete/5

Post by Christopher »

freeformer wrote:That's understood, but I think that one of the questions raised in the thread was about separating the logic of detecting an AJAX request from individual controllers, and disabling the view requirement that may be the default.
It seems like unless you have a group of requests that can be identified before dispatch that distributing that logic to only the Controllers that need is would probably be best. But perhaps you are making a distinction between the functionality of the Controller class and the application code in each Action method.
freeformer wrote:My thoughts are that the super class would detect the AJAX request, disable any view/layout/rendering tasks that are normally called by default, then pass the request onto the Controller so that it can process as normal. Obviously in the action you would simply redirect to another controller/action
Certainly the most important skill with ZF is to know how to turn things off. ;) It sounds like you want to automate the Ajax detection (which ZF already does), but don't some of these requests have a response and others redirect? How does it know unless you tell it.
(#10850)
koen.h
Forum Contributor
Posts: 268
Joined: Sat May 03, 2008 8:43 am

Re: ZF and mysite.com/blog/topic/delete/5

Post by koen.h »

Every action may have a response of some sort. When deleting topic #5 that response may be whether it was successful or not.
My concern is regarding the coupling of doing update, delete, create actions and the read action. The read action typically displays a html page. The others not.

Take this example from a member here:

Code: Select all

class AuthorController extends Zend_Controller_Action
{
   
    public function loginAction()
    {
        $form = new ZFBlog_Form_AuthorLogin;
 
        if (!$this->getRequest()->isPost() || !$form->isValid($_POST)) {
            $this->view->loginForm = $form;
            return;
        }
 
        $values = $form->getValues();
 
        // Setup DbTable adapter
        $adapter = new Zend_Auth_Adapter_DbTable(
            Zend_Db_Table::getDefaultAdapter() // set earlier in Bootstrap
        );
        $adapter->setTableName('authors');
        $adapter->setIdentityColumn('username');
        $adapter->setCredentialColumn('password');
        $adapter->setIdentity($values['name']);
        $adapter->setCredential(
            hash('SHA256', $values['password'])
        );
 
        // authentication attempt
        $auth = Zend_Auth::getInstance();
        $result = $auth->authenticate($adapter);
 
        // authentication succeeded
        if ($result->isValid()) {
            $auth->getStorage()
                ->write($adapter->getResultRowObject(null, 'password'));
            $this->_helper->redirector('index', 'index', 'admin');
        } else { // or not! Back to the login page!
            $this->view->failedAuthentication = true;
            $this->view->loginForm = $form;
        }   
    }
 
    public function logoutAction()
    {
        Zend_Auth::getInstance()->clearIdentity();
        $this->_helper->redirector('index', 'index');
    }
   
}
The login action does all sorts of things depending on the request parameters and ultimately leads to some html ouput through various means. I'd like to seperate responsabilities here. The login action is for logging in, not for knowing what action it should call to display html.
A login request initiated from a html form ideally contains 2 actions. The first being the login action itself, the second the action that should display the html page after unsuccessful/successful login attempt.

I hope this clears up my problem.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: ZF and mysite.com/blog/topic/delete/5

Post by Christopher »

koen.h wrote:Every action may have a response of some sort. When deleting topic #5 that response may be whether it was successful or not.
My concern is regarding the coupling of doing update, delete, create actions and the read action. The read action typically displays a html page. The others not.
I would disagree that every "action" has a response. Certainly forward is not a response (in the sense I use the word). And though I consider a redirect to technically be a response, it is also not a response in the HTML sense. I gets down to what you call an "action" from the user perspective it is all the code that produces are response. But from a controller architecture, an action usually means executing a specific function/method based on specific URL mapping rules.
koen.h wrote:The login action does all sorts of things depending on the request parameters and ultimately leads to some html ouput through various means. I'd like to seperate responsabilities here. The login action is for logging in, not for knowing what action it should call to display html.
A login request initiated from a html form ideally contains 2 actions. The first being the login action itself, the second the action that should display the html page after unsuccessful/successful login attempt.

I hope this clears up my problem.
I can think of two directions you might take. You could uncouple a specific view from that generic code by have the actual form/view class name be a property of a base controller. Then other classes could extend it an set the appropriate view and redirect.

If code separation is your goal then you might want to think of a callback style design. An Application Controller drives this kind of implementation. An example is the Skeleton Form Controller where you assign separate callback methods for the init, submit and done states of a form. Each is called based on the state of the form. Not sure that is what you are looking for either though...
(#10850)
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: ZF and mysite.com/blog/topic/delete/5

Post by Eran »

koen.h wrote: Take this example:

Code: Select all

class AuthorController extends Zend_Controller_Action
{
// Some code
   
}
The login action does all sorts of things depending on the request parameters and ultimately leads to some html ouput through various means. I'd like to seperate responsabilities here. The login action is for logging in, not for knowing what action it should call to display html.
A login request initiated from a html form ideally contains 2 actions. The first being the login action itself, the second the action that should display the html page after unsuccessful/successful login attempt.

I hope this clears up my problem.
I think the problem in that example is that too much happens in the controller. I ussually have a login action like this:

Code: Select all

 
class AuthorController extends Zend_Controller_Action
{
   
    public function loginAction()
    {
        if ($this->getRequest()->isPost()) {
             $result = Auth::login($_POST); // A separate class handles login validation
             if($result === true) {
                  $this -> _redirect('/index'); // Login successful, redirect to index or do something else
             } else {
                  $this -> initView() -> errors = $result; //Inject login errors into the view
             }
        }
 
        echo $this -> render(); //If we're here we either failed login or just got to the login page
    }
}
 
When its kept simple, I don't see a need for separate actions to handle login. Everything is a case by case scenario.
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Re: ZF and mysite.com/blog/topic/delete/5

Post by alex.barylski »

Just curious, but what is the reason for checking isPost() in the above example? Just to prevent people from signing in using GET parameters?
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: ZF and mysite.com/blog/topic/delete/5

Post by Eran »

No, it's just to check if the login form has been submitted and if so try to login the user based on the data passed. It can be optionally be used with get or both.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Re: ZF and mysite.com/blog/topic/delete/5

Post by John Cartwright »

Hockey wrote:Just curious, but what is the reason for checking isPost() in the above example? Just to prevent people from signing in using GET parameters?
I believe it is just a wrapper for

Code: Select all

$_SERVER['REQUEST_METHOD'] == 'POST'
Post Reply