created in the spirit of Ruby on Rails.
Write code that runs every time a given object is created, updated, or deleted.
Callbacks in Wheels allow you to have code executed before and/or after certain operations on an object. This requires some further explanation, so let's go straight to an example of a real-world application: the e-commerce checkout.
Let's look at a possible scenario for what happens when a visitor to your imaginary e-commerce website submits her credit card details to finalize an order:
new() method based on the incoming form parameters.save() method on the Order object, which will cause Wheels to first validate the object and then store it in the database if it passes validation.update() method on the object because the user decided to change the shipping method for the order.delete() method on the object because the visitor called in to cancel the order.Let's say you want to have the following things executed somewhere in the code:
It's tempting to put this code right in the controller, isn't it? But if you think ahead a little, you'll realize that you might build an administrative interface for orders and maybe an express checkout as well at some point in the future. You don't want to duplicate all your logic in all these places, do you?
Object callbacks to the rescue! Just implement something similar to the following to keep complex logic out of your controllers and to ensure you stay DRY (Don't Repeat Yourself).
Part of the Order.cfc model file:
<cfcomponent extends="Model">
<cffunction name="init">
<cfset beforeValidationOnCreate("fixCreditCard")>
<cfset afterValidation("calculateShippingCost")>
<cfset afterDelete("sendConfirmationEmail")>
</cffunction>
<cffunction name="fixCreditCard">
Code for stripping out dashes in credit card numbers goes here...
<cfreturn true>
</cffunction>
<cffunction name="calculateShippingCost">
Code for calculating shipping cost goes here...
<cfreturn true>
</cffunction>
<cffunction name="sendConfirmationEmail">
Code for sending confirmation email goes here...
<cfreturn true>
</cffunction>
</cfcomponent>
The above code registers 3 methods to be run at specific points in the life cycle of all objects in your application.
The following 14 functions can be used to register callbacks.
beforeValidation()beforeValidationOnCreate() or beforeValidationOnUpdate()afterValidation()afterValidationOnCreate() or afterValidationOnUpdate()beforeSave()beforeCreate() or beforeUpdate()afterCreate() or afterUpdate()afterSave()beforeDelete()afterDelete()As you can see above, there are places (4, to be exact) where one callback or the other will be executed but not both. Which callback that will be executed depends on whether the object is being saved to the database for the first time or not. The "create" type callbacks will be executed for new objects and the "update" type callbacks for existing objects.
Please note that if you use the updateAll() or the deleteAll() methods in Wheels, they will not instantiate objects by default, and thus any callbacks will be skipped. This is good for performance reasons because if you update 1,000 records at once, you probably don't want to run the callbacks on each object. Especially not if they involve database calls.
However, if you want to execute all callbacks in those methods as well, all you have to do is pass in instantiate=true to the updateAll()/deleteAll() methods.
If you want to completely break the save/delete operation chain for an object, you can do so by returning false from your callback method. (Otherwise, always return true or nothing at all.) By breaking the chain, we mean that if you, for example, have called the save() method on a new object and the method you've registered with a beforeCreate() call returns false, the method will exit early, returning false and no record will be inserted in the database.