views:

120

answers:

2

Hi,

I'm writing an application in CakePHP that, for now, is to be used to make quotes for customers. So Quote is a model. I want to have a separate model/table for something like "Property," which may be used by other models.

Each time a user gets to the "Add Quote" action, I basically want to pull a Property called "nextQuoteNumber" or something along those lines, and then automatically increment that property, even if the new Quote isn't saved. So I don't think just using an autoincrement for Quote's id is appropriate here - also, the "quote number" could be different from the row's id.

I know this is simple enough to do, but I'm trying to figure out the "proper" CakePHP way of doing it! I'm thinking that I should have a method inside the Property model, say "getProperty($property_name)", which would pull the value to return, and also increment the value... but I'm not sure what the best way of doing that is, or how to invoke this method from the Quotes controller.

What should I do? Thanks in advance!

A: 

Your initial approach will produce duplicate quote numbers unless you employing locking in some way.

When the user goes to the "Add Quote" page, you would create a new row in the quotes table, grab the id and throw it into the page. When the user submits the quote, update the row with the new info.

It would be trivial to filter out empty quotes from your queries.

webbiedave
Duplicate numbers shouldn't be a problem, as the property would be updated each time the "Add Quote" page is visited - so if Alice visits and gets number 1001, then Bob visits before Alice saves, he will get number 1002 because Alice's visit to the page will have incremented the property. I'd rather not do the row insertion initially, in case the user leaves the page without saving or clicking "Cancel".
Paul Willy
It's more like this: Bob asks for number. As database retrieves 1001 for Bob, Alice asks for number. Database retrieves 1001 and gives it to Alice. Bob increments then stores number. Then Alice does. They both have the same quote number.
webbiedave
+1  A: 

I ended up doing something a bit more specific, making a model for 'Sequence' rather than the more general 'Property'. Sequence has three fields: id, name, value. Since I currently need a sequence for quotes starting from 1001, there's one row (1, 'Quote', 1001).

In the model file sequence.php is the following:

class Sequence extends AppModel {
var $name = 'Sequence';

function getNext($sequenceName) {
    // Make this a transaction, so two concurrent requests can't get the same value.
    $this->begin();
    // Find the sequence for the given object, let's say 'Quote'
    $row = $this->find('first', array(
        'conditions' => array('Sequence.name' => $sequenceName),
        'fields' => array('id', 'value'),
    ));
    // Save the original value (before incrementing) so we can return it.
    $value = $row['Sequence']['value'];
    // Update the value in the database.
    $row['Sequence']['value'] = $value + 1;
    $this->save($row);
    // Commit the changes to the database, ending the lock.
    $this->commit();
    return $value;
} 

As webbiedave pointed out, atomicity is required or it's possible that two users/quotes could get the same sequence number, hence the begin() and commit() calls.

Then, in my quotes_controller, I added the following in the add() action:

$this->loadModel('Sequence');
$quoteNumber = $this->Sequence->getNext('Quote');

Then I can use the $quoteNumber as I wish.

Hope this helps somebody, and please contribute if there's a better way of doing it. Thanks!

Paul Willy