Playlistr: Albums
Let's add an Album feature to our application and introduce some new ideas.
Albums
Let's start with another simple CRUD feature. This time to create, read, update and delete an Album in our application. We're going to introduce a few new ideas with this one.
This time we'll use qb inside our commandbox-migrations script rather than raw SQL.
Migrate Create
If you remember, we created our commandbox-migrations script in the terminal. We can do it again with migrate create albums
With the script template we can add our qb functions to build our table schema.
component {
function up( schema ) {
schema.create( "albums", function( table ) {
table.increments( "id" );
table.string( "name" );
} );
}
function down( schema ) {
schema.drop( "albums" );
}
}With qb we have access to closure methods that can create and drop a table as well as add columns definitions. We pass the schema from qb into our up() and down() methods to give us access to the features of qb.
The create() closure takes the name of the table we want to create, "albums", and a function to define the columns in that table. The increments() method adds an auto-incrementing integer primary key and string() adds a varchar(255) string column to the table.
In the down() method we'll use drop() to delete our "albums" table.
Album.cfc (Model)
This is the same as the Artist entity and saved as models/Album.cfc
index.cfm & createUpdate.cfm (Views)
These are also the same as those for the Artist.
Next we create our Album service and handler.
Service & Handler
Album Service
Now let's introduce the idea of interacting with our database via a Service component. Add the file models/AlbumService.cfc to your webroot. The start of this Service component should start by injecting WireBox and include a simple init() constructor method.
component {
property wirebox inject="wirebox";
public AlbumService function init() {
return this;
}
}Now we can add new methods to build out the functionality to interface with our database using Quick features.
getByID()
public Album function getByID( required any id) {
return wirebox.getInstance( "Album" )
.findOrFail( id );
}This should look similar to a portion of the update() action from the Artists handler.
getAll()
public array function getAll() {
return wirebox.getInstance( "Album" )
.orderby( "id" )
.get();
}Once again this should look familiar to a portion of the index() action. The get() method returns the collection back as an array.
create()
public Album function create( required struct values ) {
return wirebox.getInstance( "Album" )
.create( values );
}Another similar method. This time we take in a structure of the name/value pairs and pass that on to populate a new row in our database.
update()
public void function update( required any id, required struct values ) {
getByID( id )
.update( values );
}Here we chain the update() onto the end of the getByID() method we wrote earlier and pass on the structure of names/values to update an existing row in our database.
delete()
public void function delete( required any id ) {
getByID( id )
.delete();
}Similar to update(), we chain to the end of getByID() to delete an existing row from our database.
Album Handler
With our new AlbumService we can simplify our handler. So first create your handler handlers/Albums.cfc and start with:
component extends="coldbox.system.EventHandler" {
property AlbumService inject="AlbumService";
}We've added property AlbumService inject="AlbumService"; to the component pseudo constructor to inject the AlbumService into the handler using the WireBox convention.
Action: index()
function index( event, rc, prc ) {
prc.albums = AlbumService.getAll();
if( prc.albums.len() == 0 ) {
relocate( "albums.create" );
}
}We capture all the Albums into the variable prc.albums for our view with the getAll() method in the AlbumService component but bounce the visitor onto the create action if none are returned.
Action: create()
This is the same as Artists.
Action: createAction()
function createAction( event, rc, prc ) {
param rc.name = "";
AlbumService.create( {
name: rc.name
} );
relocate( "albums" );
}This is similar to the Artists action but it now uses the AlbumService to create the database row.
Action: update()
function update( event, rc, prc ) {
param rc.id = "";
var album = AlbumService.getByID( rc.id );
prc.name = album.getName();
prc.action = "Update";
prc.formAction = "albums.updateAction";
event.setView( "albums/createUpdate" );
}Once again this is similar to the Artists action but it now uses the AlbumService to get our Album for updating.
Action: updateAction()
function updateAction( event, rc, prc ) {
param rc.id = "";
param rc.name = "";
AlbumService.update( rc.id, {
name: rc.name
} );
relocate( "albums" );
}Again, like the Artists action we use the AlbumService to update our Album by passing it the id and name/value structure of the columns to be updated.
Action: delete()
function delete( event, rc, prc ) {
param rc.id = "";
AlbumService.delete( rc.id );
relocate( "albums" );
}Finally the delete() action uses the AlbumService to removed the selected row from the database.