views:

38

answers:

4

Okay, so I'm fairly new to CakePHP. This is the setup:

I've got a Model (Reservation), and a controller, (ReservationController).

I'm trying to provide a simple add() functionality.

The request url is: www.example.com/reservations/add/3

Where 3 is the ID of the event this reservation is for. So far, so good. The problem is, the form is constructed like this:

 <h2>Add reservation</h2>
<?php echo $form->create('Reservation');
echo $form->input('first_name');
echo $form->input('last_name');
echo $form->input('email');
echo $form->input('tickets_student'); echo $form->input('tickets_nstudent');
echo $form->end('Add');?>

When I hit the send button, the request URL becomes simply www.example.com/reservations/add/, and the event id is lost.

I've solved it now by grabbing the id in the controller, and make it available to the form:

// make it available for the form
$this->set('event_id', $eventid);

And then, in the form:

$form->create('Reservation',array('url' => array($event_id)));

It works, but it strikes me as a bit ugly. Isn't there an easier way to make sure the form POST action gets made to the current url, instead of the url without the id?

+1  A: 

Following the strictest convention for just a moment, reading a URL like /reservations/add/3 would be, well, confusing. You're calling on the ReservationsController to act on the Reservation model, but passing it an event ID. Calling /reservations/edit/3 is far less confusing, but just as wrong for your situation since the id value, "3", would be assumed to be a reservation identifier.

Essentially, you're making an ambiguous request at best. This is a simple form to create a reservation and that reservation has to be associated with an event. In a "traditional" scenario, the form would allow the user to select an event from some kind of list. After all, the foreign key, probably event_id in this case, is really just another property of a reservation. The list would have to be populated in the controller; this is usually done via a find( 'list' ) call.

If you already know the event that you want to create the reservation against (which you apparently do), then I'd probably select the analogous method of using a hidden field in the form. You still have to set the value in the controller just as you're doing, but the end result is a bit more Cake-y. The hidden field would be named data[Reservation][event_id] (again, I'm assuming the name of your foreign key field).

Rob Wilkerson
I agree with you, because I am using the same form for add and edit in my projects and it will be confusing, but if @Forceflow uses two separate actions, I believe it will be ok, because he will pass this variable only in add action. then in the edit one he will know the event and it wont be needed to be passed in the url. But there are too many if's in the our assumptions. :)
Nik
A: 

You can do following:

$form->create('Reservation',array('url' => $this->Html->url()));

this way all your variables from the url will be added in the form action :)

Nik
A: 

As Rob Wilkerson suggests, the issue is your URL route doesn't accurately describe the operation being performed. It becomes further confusing when you want to edit the reservation: /reservations/edit/6. Now the number in the URL means something different.

The URL convention I use for situations like these (adapted to your particular case) is /events/3/reservations/add. It takes a bit more up-front to configure your routes, but I've found it's superior for clarity down the road.

Sample routes.php:

Router::connect(
    '/events/:event_id/reservations/:action', 
    array('controller'=>'reservations','action'=>'index'),
    array(
        'pass' => array('event_id'), // pass the event_id as a param to the action
        'event_id' => '[0-9]+',
        'actions'=>'add|index' // only reverse-routes with 'action'=>'add' or 
                               // 'action'=>'index' will match this route
    )
)
// Usage: array('controller'=>'reservations','action'=>'add','event_id'=>3)

Router::connect(
    '/events/:event_id/reservations/:id/:action', 
    array('controller'=>'reservations'),
    array(
        'pass' => array('id'), // pass the reservation id as a param to the action
        'id' => '[0-9]+',
        'event_id' => '[0-9]+',
        'actions'=>'edit|delete' // only reverse-routes with 'action'=>'edit' or 
                                 // 'action'=>'delete' will match this route
    )
)
// Usage: array('controller'=>'reservations','action'=>'edit','event_id'=>3,'id'=>6)

In your FormHelper::create call, you'd have to specify most of the reverse-route you want to follow, but again, the up-front cost will pay dividends in the future. It's usually better to be explicit with Cake than to hope its automagic always works correctly, especially as the complexity of your application increases.

Daniel Wright
A: 
$form->create('Reservation',array('action' => 'add',$eventId);

and in the controller:

    function add($eventId = null)
    {
        {
            if($eventId == null) 
            // error state
        }

    ...

    }

I do it all the time.

Leo
You should correct the evaluation vs assignment bug in your conditional. =)
Daniel Wright
thanks - I've just got in from work and have no real excuse ;) +1
Leo