Skip to content

Quick Start

tonynelson19 edited this page Feb 19, 2013 · 1 revision

So you want to build an application using ColdMVC?

You've come to the right place. In this one-page tutorial, we'll create a very simple application for managing books and performing basic CRUD operations using ColdMVC.

While I'll try to explain some things along the way, once you've completed this tutorial, you should head over to the documentation for a more thorough explanation on how certain things are done.

Installing ColdMVC

Before you can get started creating your application, make sure you're running the latest version of ColdFusion, as the early releases of ColdFusion 9 had some ORM bugs that were fixed in later releases.

Next, you need to install ColdMVC. After you download the framework, you have three options for installing it:

  1. Create a /coldmvc mapping inside ColdFusion Administrator that points to the framework.
  2. Put the framework directly inside your server's web root.
  3. Put the framework directly inside your application's root.

The choice is yours.

Creating your application

Now that ColdMVC is installed, it's time to get started on the application. First, create a new ColdFusion project in your editor of choice and name it BookStore.

Since this will be a database-driven web application, you should also create a new database in your database server. For now, the database can be left completely empty.

Once you've created the database, create a datasource within ColdFusion Administrator that points to your new database and name it BookStore. Technically you can configure the datasource to be named whatever you'd like it to be, but by default ColdMVC will look for a datasource with the same name as the project.

Next, add an Application.cfc inside your BookStore directory with the following content:

component extends="coldmvc.Application" {

}

At this point, your directory structure should look like the following:

/BookStore
	Application.cfc

Creating a home page

Since ColdMVC follows the MVC design pattern where requests are routed through controllers, we'll start by creating a controller for the bookstore.

Inside your BookStore directory, create a new folder called app. This is where the bulk of the code for your application will be located.

Inside the app directory, create a directory called controllers. As the name might imply, this is where your application's controllers will be located.

Now, inside /BookStore/app/controllers/, create an IndexController.cfc with the following content:

component {

}

The IndexController will serve as the home page for the application. At this point it doesn't really do a whole lot, but that's OK.

Next, let's create the view for the home page. In an MVC application, the View is the presentation layer of your application. Simply put, it's where your HTML goes.

Inside the app directory, create a new directory called views. This is where your application's views will be located.

Now, create another directory inside views called index. This is where any views associated with your IndexController will be located.

Finally, inside /BookStore/app/views/index/, create an index.cfm with the following content:

Welcome to my bookstore!

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			IndexController.cfc
		/views
			/index
				index.cfm
	Application.cfc

Testing it out

Now that you've created a simple controller and view for the bookstore, let's test it out.

To do so, create a new directory inside BookStore called public. This will be the publicly accessible web root for your application.

Inside the public directory, create an index.cfm with the following content:

<cfinclude template="/coldmvc/index.cfm" />

This will be the main front controller for your application and act as a centralized entry point for all requests. Basically the file just delegates control of the request to ColdMVC.

Now, open a web browser and test out your application.

If you use localhost for development, go to http://localhost/bookstore/public/index.cfm. You should see a really boring page that says "Welcome to my bookstore!".

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			IndexController.cfc
		/views
			/index
				index.cfm
	/public
		index.cfm
	Application.cfc

Development mode

Your application should now be up and running in all of its limited glory. However, by default your application runs in production mode, which has enhanced application caching enabled, but isn't ideal when you're making lots of changes in your development environment.

To make things a little easier on ourselves in development, let's configure our application to run in development mode.

First, create a new directory called config inside the BookStore directory.

Inside the config directory, create a config.ini with the following content:

[default]

[development]
development = true

This is your application's main configuration file. Right now the file is turning on development mode and telling the application to reload itself on every request. More information can be found in the configuration chapter inside the [documentation] [1].

Also inside the config directory, create an environment.txt with the following content:

development

This file sets your current environment, which is used to load your config variables. More information can be found in the environments chapter inside the [documentation] [1].

Now, go back to your browser and reload your application by appending ?init to the URL. For example, your URL could now be http://localhost/bookstore/public/index.cfm?init.

After the page reloads, you should now see ColdMVC's debug information, which contains a lot of useful stuff, like the current request's controller, action, and view, among other things.

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			IndexController.cfc
		/views
			/index
				index.cfm
	/config
		config.ini
		environment.txt
	/public
		index.cfm
	Application.cfc

Creating a model

Now that you've created a very simple home page for your bookstore, it's time to start working with books.

First, we'll need to create a Book model. This will be a persistent ORM entity that is managed by Hibernate behind the scenes.

Inside your app directory, create a directory called model. This will be the model of your application, where your business logic and persistent model objects are located.

Inside the model directory, create a Book.cfc with the following content:

component persistent="true" extends="coldmvc.Model" {

	property name="id" fieldtype="id" generator="identity";
	property title;
	property author;
	property description;

}

You'll notice that the Book model has four properties: an ID, a title, an author, and a description. If you refresh your page and look at your database, you should see that a table named Book was created for you, with columns that match the properties on your Book model.

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			IndexController.cfc
		/model
			Book.cfc
		/views
			/index
				index.cfm
	/config
		config.ini
		environment.txt
	/public
		index.cfm
	Application.cfc

Performing CRUD

Now that you have a Book model created, it's time to perform some [CRUD] [1].

Inside your controllers directory, create a BookController.cfc with the following content:

component accessors="true" {

	property _Book;

}

This controller will handle the CRUD operations on your books.

Next, we'll create a really simple home page view for books.

Inside /BookStore/app/views/, create a directory called book. This is where all of the views associated with the BookController will be located.

Now create an index.cfm inside the new book directory with the following content:

<cfoutput>
<a href="#linkTo({action='add'})#">Add a Book</a>
or
<a href="#linkTo({action='list'})#">List All Books</a>
</cfoutput>

You should now be able to view your book's home page in your browser by going to http://localhost/bookstore/public/index.cfm/book.

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			BookController.cfc
			IndexController.cfc
		/model
			Book.cfc
		/views
			/book
				index.cfm
			/index
				index.cfm
	/config
		config.ini
		environment.txt
	/public
		index.cfm
	Application.cfc

Adding a book

If you click on the "Add a Book" link on your book's home page, you'll see that nothing happens. Let's change that.

Open up your BookController and update it to the following content:

component accessors="true" {

	property _Book;

	function add() {

		params.book = _Book.new();

	}

}

You've just added an add action that creates a new instance of a Book and puts it into the params scope.

Next, create an add.cfm inside /BookStore/app/views/book/ with the following content:

<cfoutput>
<c:form action="save" bind="book">
	<c:input name="title" />
	<c:input name="author" />
	<c:textarea name="description" />
	<c:submit label="Add Book" />
	<a href="#linkTo({action='list'})#">Back to List</a>
</c:form>
</cfoutput>

You've just created a simple form for adding a book using ColdMVC's built-in custom tags and bound it to a Book param.

If you go to http://localhost/bookstore/public/index.cfm/book/add and view the page source, you should see something like the following:

<form action="http://localhost/bookstore/public/index.cfm/book/save"
	method="post" enctype="multipart/form-data" id="form">
	<div class="wrapper">
		<div class="label">
			<label for="book_title" title="Title">Title:<cf/label>
		</div>
		<div class="field">
			<input type="text" name="book.title" id="book_title" title="Title" value="" />
		</div>
	</div>
	<div class="wrapper">
		<div class="label">
			<label for="book_author" title="Author">Author:<cf/label>
		</div>
		<div class="field">
			<input type="text" name="book.author" id="book_author" title="Author" value="" />
		</div>
	</div>
	<div class="wrapper">
		<div class="label">
			<label for="book_description" title="Description">Description:</label>
		</div>
		<div class="field">
			<textarea name="book.description" id="book_description" title="Description"></textarea>
		</div>
	</div>
	<span class="button">
		<input type="submit" name="save" id="save" title="Add Book" class="button" value="Add Book" />
	</span>
	<a href="http://localhost/bookstore/public/index.cfm/book/list">Back to List</a>
</form>

Not bad for less than 10 lines of code in the view.

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			BookController.cfc
			IndexController.cfc
		/model
			Book.cfc
		/views
			/book
				add.cfm
				index.cfm
			/index
				index.cfm
	/config
		config.ini
		environment.txt
	/public
		index.cfm
	Application.cfc

Saving a book

Now that we have a form for adding a book, let's save it to the database.

You'll notice that the add form that we just created has an action of save, so let's add that action to our BookController.

Once again, open up your BookController and update it to the following content:

component accessors="true" {

	property _Book;

	function add() {

		params.book = _Book.new();

	}

	function save() {

		var book = _Book.new(params.book);

		book.save();

	}

}

If you fill out your form and submit it, you should see a new record created in your database.

Viewing a book

Now that you were able to add a book to your database, let's display the newly created record.

Let's start by updating the BookController to the following content:

component accessors="true" {

	property _Book;

	function add() {

		params.book = _Book.new();

	}

	function save() {

		var book = _Book.new(params.book);

		book.save();

		redirect({action="show", id=book});

	}

	function show() {

		params.book = _Book.get(params.id);

	}

}

You'll notice the BookController's save action now has logic to redirect to the show action after the book is saved.

Now let's add the view. Create a show.cfm inside /BookStore/app/views/book/ with the following content:

<cfoutput>
<c:bind to="book">
	<c:text name="id" />
	<c:text name="title" />
	<c:text name="author" />
	<c:text name="description" />
</c:bind>

<a href="#linkTo({action='list'})#">Back to List</a>
</cfoutput>

If you save another book, you will be redirected to the new book's show page.

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			BookController.cfc
			IndexController.cfc
		/model
			Book.cfc
		/views
			/book
				add.cfm
				index.cfm
				show.cfm
			/index
				index.cfm
	/config
		config.ini
		environment.txt
	/public
		index.cfm
	Application.cfc

Listing books

Now that we can add and view newly created books, let's create a page to display all of the books in the database.

Once again, open your BookController and update it to the following content:

component accessors="true" {

	property _Book;

	function add() {

		params.book = _Book.new();

	}

	function save() {

		var book = _Book.new(params.book);

		book.save();

		redirect({action="show", id=book});

	}

	function show() {

		params.book = _Book.get(params.id);

	}

	function list() {

		params.books = _Book.list({
			sort = "title",
			order = "asc"
		});

	}

}

You've now added a list action that lists all of the books in the database and sorts them by their title in ascending order.

Next, let's create the view that displays the books.

Create a list.cfm located inside /BookStore/app/views/book/ with the following content:

<cfoutput>
<table>
	<thead>
		<tr>
			<th>ID</th>
			<th>Title</th>
			<th>Author</th>
			<th>&nbsp;</th>
			<th>&nbsp;</th>
		</tr>
	</thead>
	<tbody>
		<c:each in="#books#" do="book">
			<tr>
				<td><a href="#linkTo({action='show', id=book})#">#book.id()#</a></td>
				<td>#escape(book.title())#</td>
				<td>#escape(book.author())#</td>
				<td><a href="#linkTo({action='edit', id=book})#">Edit</a></td>
				<td><a href="#linkTo({action='delete', id=book})#">Delete</a></td>
			</tr>
		</c:each>
	</tbody>
</table>

<a href="#linkTo({action='add'})#">Add a Book</a>
</cfoutput>

If you go to http://localhost/bookstore/public/index.cfm/book/list, you should see a table with all of the books in your database.

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			BookController.cfc
			IndexController.cfc
		/model
			Book.cfc
		/views
			/book
				add.cfm
				index.cfm
				list.cfm
				show.cfm
			/index
				index.cfm
	/config
		config.ini
		environment.txt
	/public
		index.cfm
	Application.cfc

Editing books

You'll notice the book list included a link to edit each book, so let's add that action to the application.

Open your BookController and update it to the following content:

component accessors="true" {

	property _Book;

	function add() {

		params.book = _Book.new();

	}

	function save() {

		var book = _Book.new(params.book);

		book.save();

		redirect({action="show", id=book});

	}

	function show() {

		params.book = _Book.get(params.id);

	}

	function list() {

		params.books = _Book.list({
			sort = "title",
			order = "asc"
		});

	}

	function edit() {

		params.book = _Book.get(params.id);

	}

}

You've just added an edit action that finds a book by its ID and puts it into the params scope.

Now let's create the form for editing a book's information. This form will look very similar to your add form.

Inside /BookStore/app/views/book/, create an edit.cfm with the following content:

<cfoutput>
<c:form action="update" bind="book">
	<c:hidden name="id" />
	<c:input name="title" />
	<c:input name="author" />
	<c:textarea name="description" />
	<c:submit label="Update Book" />
	<a href="#linkTo({action='show', id=book})#">Cancel</a>
	<a href="#linkTo({action='list'})#">Back to List</a>
</c:form>
</cfoutput>

You'll notice this form posts to the BookController's update action, so let's add that as well.

Update your BookController to the following content:

component accessors="true" {

	property _Book;

	function add() {

		params.book = _Book.new();

	}

	function save() {

		var book = _Book.new(params.book);

		book.save();

		redirect({action="show", id=book});

	}

	function show() {

		params.book = _Book.get(params.id);

	}

	function list() {

		params.books = _Book.list({
			sort = "title",
			order = "asc"
		});

	}

	function edit() {

		params.book = _Book.get(params.id);

	}

	function update() {

		var book = _Book.get(params.book);

		book.save();

		redirect({action="show", id=book});

	}

}

The new update action will find a book by its ID, populate and save it.

After the book has been updated, the browser is redirected back to the show action.

While we're at it, let's add some links to the show view. Update /BookStore/app/views/book/show.cfm to the following content:

<cfoutput>
<c:bind to="book">
	<c:text name="id" />
	<c:text name="title" />
	<c:text name="author" />
	<c:text name="description" />
</c:bind>

<a href="#linkTo({action='edit', id=book})#">Edit</a>
<a href="#linkTo({action='delete', id=book})#">Delete</a>
<a href="#linkTo({action='list'})#">Back to List</a>
</cfoutput>

At this point, your directory structure should look like the following:

/BookStore
	/app
		/controllers
			BookController.cfc
			IndexController.cfc
		/model
			Book.cfc
		/views
			/book
				add.cfm
				edit.cfm
				index.cfm
				list.cfm
				show.cfm
			/index
				index.cfm
	/config
		config.ini
		environment.txt
	/public
		index.cfm
	Application.cfc

Deleting books

The book list also included a link to delete books, so let's add that action as well.

Update your BookController to the following content:

component accessors="true" {

	property _Book;

	function add() {

		params.book = _Book.new();

	}

	function save() {

		var book = _Book.new(params.book);

		book.save();

		redirect({action="show", id=book});

	}

	function show() {

		params.book = _Book.get(params.id);

	}

	function list() {

		params.books = _Book.list({
			sort = "title",
			order = "asc"
		});

	}

	function edit() {

		params.book = _Book.get(params.id);

	}

	function update() {

		var book = _Book.get(params.book);

		book.save();

		redirect({action="show", id=book});

	}

	function delete() {

		var book = _Book.get(params.id);

		book.delete();

		redirect({action="list"});

	}

}

The new delete action will find a book by its ID, delete it, then redirect to the list action.

Congratulations! You've successfully handled all CRUD operations for books.

Adding a layout

The last item to cover in this tutorial will be layouts. We won't go very detailed into layouts, but more information can be found inside the chapter on layouts in the documentation.

Inside /BookStore/app/, create a directory called layouts.

Inside the layouts directory, create an index.cfm with the following content:

<c:doctype />
<c:html>
	<c:head>
		<c:title>My Bookstore</c:title>
	</c:head>
	<c:body>
		<h1>My Bookstore</h1>
		<c:render />
	</c:body>
</c:html>

This will be the site-wide layout for your entire application.

Now if you view your application in your browser again, you'll notice each view will be displayed inside the layout where it calls <c:render />.

Again, more information can be found inside the chapter on chapter on layouts in the [documentation] [2].

Closing thoughts

All of the code in this tutorial is available on GitHub at https://github.com/tonynelson19/ColdMVC-Samples/tree/master/BookStore.

Thanks for your time and I hope you enjoy working with ColdMVC.