Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

August 21 2012

14:39

Building an ASP.NET MVC4 Application with EF and WebAPI

ASP.NET MVC has come a long way since “The Gu” jotted down some ideas during an airplane ride to a conference in 2007. In just under four years, ASP.NET MVC has seen its fourth release, and it provides developers an environment that eases development, streamlines processes, and promotes modern patterns.


Dive In

Jumping right in is one of the best ways to get a handle of new technology. Let’s go ahead and dive right into teh codez!

Setup

I will be using Visual Studio 2012 Release Candidate, which is available here. I also recommend downloading SQL Server 2012 because the new Management Studio is a much needed improvement over earlier versions.

Once VS 2012 is up and running, go ahead and create a new project. Go to File -> New Project and choose an Internet Application. It’s not a perfect template, but it’ll get the job done.

Project Options

Note: the code for this demo application is located in a Github repo. I won’t go through every single piece of code in this app, but you’ll have a good understanding of an MVC4 application at the end of this tutorial.

Entity Framework

I am going to use Entity Framework (EF) Code First for the data model. EF Code First lets us generate database tables with nothing more than a few Plain Old CLR Objects (POCO). Plus, EF lets us use LINQ to Entities and Lambda expressions, making it easy to query and issue commands. A win win!

Our application will be a review site for reviewing… stuff. Therefore, the data model needs to incorporate all the necessary bits and pieces for a single review. We’ll start with a class called Review. Write the following class in its own file in the Models directory:

// Review.cs
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Review.cs
public class Review
{
    public int Id { get; set; }
    
    [Required]
    public string Content { get; set; }
    
    [Required]
    [StringLength(128)]
    public string Topic { get; set; }
    
    [Required]
    public string Email { get; set; }
    
    [Required]
    public bool IsAnonymous { get; set; }
    
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }
    
    public virtual IEnumerable<Comment> Comments { get; set; }
}

The Review class has it’s Id (the primary key), the Content property to store the review, a Topic such as a restaurant name (or any name of an organization), an Email property, and an IsAnonymous flag to signify if the reviewer is anonymous. The CategoryId and the Category properties create a foreign key relationship to tie a review to a Category (eg: Doctors, Dentists, etc). And last is a collection of Comment objects.

Now write the Comment class. Once again, add the new class to the Models directory:

// Comment.cs
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Comment.cs
public class Comment
{
    public int Id { get; set; }
    
    [Required]
    public string Content { get; set; }
    
    [Required]
    public string Email { get; set; }
    
    [Required]
    public bool IsAnonymous { get; set; }

    public int ReviewId { get; set; }
    public Review Review { get; set; }
}

The comment class has an Id property for the primary key, Content of the comment, an Email property, and an IsAnonymous flag for users. Then there are ReviewId and Review properties to create a foreign key relationship between comments and reviews.

Last is the Category class. Here is its code:

// Category.cs
// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Category.cs
public class Category
{
    public int Id { get; set; }
    
    [Required]
    [StringLength(32)]
    public string Name { get; set; }
}

This class is self-explanatory.

You probably noticed extensive use of the [Required] data annotation in the above classes. These designate a non-nullable field in the database and provide validation later down the road. You can also create your own custom validation attributes if you so desire. In addition to [Required], we also used the virtual keyword for some properties; those properties signify foreign key relationships with other tables.

To create the corresponding tables for these classes, you’ll need to create a DbContext class. The following code creates a context class called ReviewedContext:

    // https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/ReviewedContext.cs
    public class ReviewedContext : DbContext
    {
        public DbSet<Review> Reviews { get; set; }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Comment> Comments { get; set; }

        public ReviewedContext()
        {
            Configuration.ProxyCreationEnabled = false;
        }
    }

EF Code First lets us generate database tables with nothing more than a few Plain Old CLR Objects (POCO).

Every property in this class corresponds to a table when generating the database. The Configuration.ProxyCreationEnabled = false; makes sure that the entities are retrieved as objects of their respective classes instead of proxies–making debugging much easier.

Next, we set up a database initializer. An initializer ensures that the database is created correctly when the data model undergoes any change. Without an initializer, you’ll have to manually delete the database if you make a change to one of your POCOs. There are a few different types of initializers to choose from: DropCreateDatabaseAlways and DropCreateDatabaseIfModelChanges. The names are self explanatory. The one we are going to use is DropCreateDatabaseIfModelChanges.

The DropCreateDatabaseAlways and DropCreateDatabaseIfModelChanges initializers have a side effect: they drop the tables (and thus data) in the database when the model structure changes. But EF Code First provides a third way to generate databases: Migrations. This new feature tracks changes to the database and does not lose data as the POCO classes change.

Here’s the code for our initializer:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/ReviewedContextInitializer.cs
// http://slipsum.com/
public class ReviewedContextInitializer : DropCreateDatabaseIfModelChanges<ReviewedContext>
{
    protected override void Seed(ReviewedContext context)
    {
        // Use the context to seed the db.
    }
}

The ReviewedContextInitializer class overrides the Seed() method. This gives us the ability to fill our database with some test data. Now, we need to visit the Global.asax file and add the following line to the Application_Start() method:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Global.asax.cs
Database.SetInitializer(new ReviewedContextInitializer());

Let’s create some repositories for retrieving data from the database, and we’ll go ahead and setup dependency injection (DI) with Ninject. If you don’t exactly know what DI or Inversion of Control (IoC) are, then take a moment to read this article.

Basically, the idea of dependency injection is to inject a concrete dependency into a class, as opposed to hard coding the class to be dependent upon the concrete dependency. In other words, it’s a decoupling of one concrete class from another. If that’s still clear as mud, let’s look at a brief example:

    public class Foo
    {
        private Bar _bar; 
        
        public Foo()
        {
            _bar = new Bar();
        }
    }

This code creates a class called Foo. It is dependent upon the functionality of an object of type Bar, and the Bar object is created within the Foo class. This can be difficult to maintain and unit test because:

  • Foo and Bar are tightly coupled. As a result, maintenance is less than ideal.
  • Foo is dependent upon a specific implementation of Bar, making unit testing difficult.

This code can be improved upon with just a few modifications. Take a look at the revised Foo class:

    public class Foo
    {
        private IBar _bar;
        
        public Foo(IBar bar)
        {
            _bar = bar;
        }
    }

In just under four years, ASP.NET MVC has seen its fourth release...

Now, the Foo class is not dependent upon a specific implementation of Bar. Instead, an object of a class implementing the IBar interface is supplied to Foo via the latter's constructor. This approach greatly improves maintainability, while also allowing us to inject any IBar object--making it easier to unit test our code.

With that brief description out of the way, let's get Ninject up and running. Fire up the Package Manager Console and run Install-Package Ninject.MVC3. This will add Ninject to our project.

The first repository we'll create is the ReviewsRepository, and it will implement the IReviewRepository interface. Here's the interface:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Abstract/IReviewRepository.cs
public interface IReviewRepository
{
    Review Get(int id);
    IQueryable<Review> GetAll();
    Review Add(Review review);
    Review Update(Review review);
    void Delete(int reviewId);
    IEnumerable<Review> GetByCategory(Category category);
    IEnumerable<Comment> GetReviewComments(int id);
}

This interface ensures that our review repositories provide the basic CRUD operations. We also get the utility of retrieving reviews by a specific category, as well as retrieving the comments for a given review. Now let's write a concrete class implementing this interface:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Models/Repos/ReviewRepository.cs
public class ReviewRepository : IReviewRepository
{
    private ReviewedContext _db { get; set; }

    public ReviewRepository()
        :this (new ReviewedContext())
    {
        
    }

    public ReviewRepository(ReviewedContext db)
    {
        _db = db;
    }

    public Review Get(int id)
    {
        return _db.Reviews.SingleOrDefault(r => r.Id == id);
    }

    public IQueryable<Review> GetAll()
    {
        return _db.Reviews;
    }

    public Review Add(Review review)
    {
        _db.Reviews.Add(review);
        _db.SaveChanges();
        return review;
    }

    public Review Update(Review review)
    {
        _db.Entry(review).State = EntityState.Modified;
        _db.SaveChanges();
        return review;
    }

    public void Delete(int reviewId)
    {
        var review = Get(reviewId);
        _db.Reviews.Remove(review);
    }

    public IEnumerable<Review> GetByCategory(Category category)
    {
        return _db.Reviews.Where(r => r.CategoryId == category.Id);
    }

    public IEnumerable<Comment> GetReviewComments(int id)
    {
        return _db.Comments.Where(c => c.ReviewId == id);
    }
}

WebAPI is a MVC-like framework that we can use to easily create a RESTful API...

This repository relies on a ReviewedContext object that is stored as a class variable. This enables us to use LINQ in any of the repository's methods, making database interaction easy.

WebAPI has a nice feature that lets us add our own DI framework. This feature is beyond the scope of this tutorial, so be sure to read this article to help get that setup.

One of the most important locations for our code is the App_Start folder, which contains a file called NinjectCommonWeb.cs (installing Ninject automatically adds this file to App_Start). This file contains a static class called NinjectWebCommon, and it has a method called RegisterServices(). In this method, add the following code:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/App_Start/NinjectWebCommon.cs
kernel.Bind<IReviewRepository>().To<ReviewRepository>();
kernel.Bind<ICategoriesRepository>().To<CategoriesRepository>();
kernel.Bind<ICommentsRepository>().To<CommentsRepository>();

GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

The first three statements bind an interface to a concrete implementation of the interface, and the fourth line sets up the DI for WebAPI (the feature covered in the aforementioned article).

WebAPI

Let's now create the controllers for the API. WebAPI is a MVC-like framework that we can use to easily create a RESTful service, and it can run inside of a MVC4 application, in its own project, or it can be self hosted outside of IIS. But that's not all; it has many other features, such as: content negotiation (to automatically serialize it data into whatever format is requested), model binding, validation, and many more.

We first need to create an endpoint with WebAPI, and we do that by creating a class that inherits ApiController. Getting started with this is rather easy. Visual Studio 2012 has a new feature that creates a new, partially scaffolded controller.

Create ApiController

This will create a controller class with a few methods already defined for you. Here is an example:

// GET api/default1
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

// GET api/default1/5
public string Get(int id)
{
    return "value";
}

// POST api/default1
public void Post(string value)
{
}

// PUT api/default1/5
public void Put(int id, string value)
{
}

// DELETE api/default1/5
public void Delete(int id)
{
}

The method names correspond to the HTTP verb they represent. We'll now create the ReviewsController class. The code a bit long, but pretty straightforward.

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/ReviewsController.cs
public class ReviewsController : ApiController
{
    private ICategoriesRepository _categoriesRepository { get; set; }
    private IReviewRepository _reviewRepository { get; set; }

    public ReviewsController(IReviewRepository reviewRepository, ICategoriesRepository categoriesRepository)
    {
        _reviewRepository = reviewRepository;
        _categoriesRepository = categoriesRepository;
    }

    // GET api/review
    public IEnumerable<Review> Get()
    {
        var reviews = _reviewRepository.GetAll();
        return reviews;
    }

    // GET api/review/5
    public HttpResponseMessage Get(int id)
    {
        var category = _reviewRepository.Get(id);
        if (category == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK, category);
    }

    // POST api/review
    public HttpResponseMessage Post(Review review)
    {
        var response = Request.CreateResponse(HttpStatusCode.Created, review);
        // Get the url to retrieve the newly created review.
        response.Headers.Location = new Uri(Request.RequestUri, string.Format("reviews/{0}", review.Id));
        _reviewRepository.Add(review);
        return response;
    }

    // PUT api/review/5
    public void Put(Review review)
    {
        _reviewRepository.Update(review);
    }

    // DELETE api/review/5
    public HttpResponseMessage Delete(int id)
    {
        _reviewRepository.Delete(id);
        return Request.CreateResponse(HttpStatusCode.NoContent);
    }

    // GET api/reviews/categories/{category}
    public HttpResponseMessage GetByCategory(string category)
    {

        var findCategory = _categoriesRepository.GetByName(category);
        if (findCategory == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK,_reviewRepository.GetByCategory(findCategory));
    }

    // GET api/reviews/comments/{id}
    public HttpResponseMessage GetReviewComments(int id)
    {

        var reviewComments = _reviewRepository.GetReviewComments(id);
        if (reviewComments == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        return Request.CreateResponse(HttpStatusCode.OK, reviewComments);
    }
}

This code uses IReviewRepository and ICategoriesRepository objects to perform the appropriate action (eg: retrieving data for GET requests, adding data with POST requests, etc). These respositories are injected with Ninject via Constructor Injection.

If you don't have Fiddler yet, get it now--even if you're not a .NET developer.

Notice that some of the methods return different data types. WebAPI gives us the ability to return a non-string data type (such as IEnumerable<Review>), and it will serialize the object to send in the server's response. You can also use the new HttpResonseMessage class to returning a specific HTTP status code along with the returned data. One way to create an HttpResponseMessage object is by calling Request.CreateResponse(responseCode, data).

We can properly test our WebAPI project with a tool such as Fiddler2. If you don't have Fiddler yet, get it now--even if you're not a .NET developer. Fiddler is a fantastic HTTP debugging tool. Once you're running Fiddler, click on RequestBuilder and enter the API URL you want to test. Then choose the appropriate request type. If making a POST request, be sure and specify a Content-Type: application/json header, and then place a valid JSON structure into the request body. The following image demonstrates a raw JSON POST request to the api/reviews URL:

When you send the request, you'll see something like the following image:

Notice the POST request's status code is a 201. WebAPI does a great job of returning the correct status code for a RESTfull web service. Have fun with Fiddler2, it's a fantastic tool!

With WebAPI, you can specify the routing for the controllers (just like MVC). In MVC4, a RouteConfig.cs file is added to the App_Start folder. Routes for a WebAPI project are just like MVC routes.

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/App_Start/RouteConfig.cs
routes.MapHttpRoute(
    name: "GetReviewComments",
    routeTemplate: "api/reviews/comments/{id}",
    defaults: new { id = RouteParameter.Optional, controller = "Reviews", action = "GetReviewComments" }
);

routes.MapHttpRoute(
    name: "GetByCategories",
    routeTemplate: "api/reviews/categories/{category}",
    defaults: new { category = RouteParameter.Optional, controller = "Reviews", action = "GetByCategory" }
);

routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

The DefaultApi route is automatically generated by Visual Studio. The other two routes are custom and map to specific methods on the Reviews controller. There are many articles and tutorials that provide good information on routing. Be sure to check this one out.

MVC4

That covers a lot of what WebAPI has to offer. Next, we'll write a few methods to display the data. We'll consume the API in a little bit, but for now we'll use the repositories in our HomeController. A HomeController was created by Visual Studio; let's just modify its methods to display the data. First, let's get a list of the categories in the Index method.

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/HomeController.cs
private ICategoriesRepository _categoriesRepository { get; set; }
private IReviewRepository _reviewRepository { get; set; }

public HomeController(ICategoriesRepository categoriesRepository, IReviewRepository reviewRepository)
{
    _categoriesRepository = categoriesRepository;
    _reviewRepository = reviewRepository;
}

public ActionResult Index()
{
    var categories = _categoriesRepository.GetAll();
    return View(categories);
}

Here, we continue to use DI by accepting the repositories as parameters for the HomeController constructor. Ninject automatically inject the appropriate concrete classes for us. Next, let's add some code to the Index view to display the categories:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Views/Home/Index.cshtml
@model IEnumerable<Reviewed.Models.Category>

<h3>Pick a Category:</h3>
<ul class="round">
    @foreach(var category in Model)
    {
        <li>
        <a href="@Url.Action("Reviews", new { id = @category.Name} )">@category.Name</a>
        </li>
    }
</ul>

This generates a list of categories that users can click on. Now add a new method to HomeController that retrieves a Review. We'll call this method Reviews, shown here:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Controllers/HomeController.cs
public ActionResult Reviews(string id)
{
    List<Review> reviews = new List<Review>();
    if (!string.IsNullOrWhiteSpace(id))
    {
        reviews = _reviewRepository.GetByCategory(_categoriesRepository.GetByName(id)).ToList();
    }
    else
    {
        reviews = _reviewRepository.GetAll().ToList();
    }

    foreach (var review in reviews)
    {
        var comments = _reviewRepository.GetReviewComments(review.Id);
        review.Comments = comments.ToList();
    }
    return View(reviews);
}

Because a route already exists for /{controller}/{action}/{id}, you can use a URL such as Home/Reviews/Doctors. The routing engine will pass "Doctors" as the id parameter to the Reviews method. We use the id as the category and retrieve all reviews associated with that category. If no category is provided, however, we simple retrieve all reviews in the database. Once we have all the reviews, we pass the review list to the view. Let's look at the view right now:

// https://github.com/jcreamer898/NetTutsMvcEf/blob/master/Reviewed/Views/Home/Reviews.cshtml
<div class="reviews">
@foreach(var review in Model)
{
    <h3>@review.Topic</h3>
    <p>
        @review.Content
    </p>
    
    var hasComments = review.Comments.Count > 0 ? "is-comments" : null;
    
    <ul class="@hasComments">
        @foreach(var comment in review.Comments)
        {
            <li>
                <strong>@(!comment.IsAnonymous ? string.Format("{0} says,", comment.Email) : "")</strong>
                <blockquote>@comment.Content</blockquote>
            </li>
        }
    </ul>
}
</div>

This code uses a new feature of MVC4. The <ul/> element's class attribute will not appear in the HTML if hasComments is null. Read more about this feature here.

JavaScript

No modern web app is complete without JavaScript, and we'll use it to consume our WebAPI service. We'll use Backbone.js for this; so, ahead on over and download Backbone and its dependency Underscore. Place the JavaScript files in the Scripts directory.

We'll take advantage of another new MVC4 feature called script bundling. In the App_Start folder, you'll find the BundleConfig.cs file. In this file, you can configure MVC4 to bundle JavaScript files together. Open it up and add a new bundle, like this:

bundles.Add(new ScriptBundle("~/bundles/backbone").Include(
        "~/Scripts/underscore*",
        "~/Scripts/backbone*"));

Then in the /Views/Shared/_Layout.cshtml file, add the following at the bottom of the page's body:

@Scripts.Render("~/bundles/backbone")

This will bundle your scripts if your application is in debug mode, or leave them alone with it turned off.

The MVC4 code we wrote for retrieving the review list is a fine way of displaying them, but all the new hawtness is using Ajax. So let's refactor the code to use Backbone.js. Through JavaScript, we'll retrieve the views asynchronously after the page has loaded. Create a new file in the Scripts folder called home.js. Add the following code to that file:

var Review = Backbone.Model.extend();
var Reviews = Backbone.Collection.extend({
    model: Review,
    url: '/api/reviews'
});
var Comment = Backbone.Model.extend({});
var Comments = Backbone.Collection.extend({
    model: Comment,
    url: '/api/reviews/comments/'
});

These are the JavaScript data models, each corresponding to a URL to retrieve data from the WebAPI service. Now let's write the view:

var ListReviews = Backbone.View.extend({
    el: '.reviews',
    initialize: function() {
        this.collection.on('reset', this.render, this);
        this.collection.fetch();
    },
    render: function() {
        this.collection.each(this.renderItem, this);
    },
    renderItem: function(model) {
        var view = new ReviewItem({
            model: model
        });
        this.$el.append(view.el);
    }
});

This view is for the entire list of reviews. When the collection's fetch() method is called, it triggers the reset event and then calls render(). The third parameter passed to the on() method is the scope, or what this will be in the render() callback. In the render() method, call the collection's each() method, passing the renderItem() method. The renderItem() method will be called on each item in the collection, generating a new ReviewItem for every review.

The code for ReviewItem follows:

var ReviewItem = Backbone.View.extend({
    events: {
        'click a': 'getComments'
    },
    tagName: 'li',
    initialize: function () {
        
        this.template = _.template($('#reviewsTemplate').html());
        this.collection = new Comments();
        this.collection.on('reset', this.loadComments, this);
        this.render();
    },
    render: function () {
        var html = this.template(this.model.toJSON());
        this.$el.append(html);
    },
    getComments: function () {
        this.collection.fetch({
            data: {
                Id: this.model.get('Id')
            }
        });
    },
    loadComments: function () {
        var self = this,
            item;
        this.comments = this.$el.find('ul');
        this.collection.each(function (comment) {
            item = new CommentItem({
                model: comment
            });
            self.comments.append(item.el);
        });
        
        this.$el.find('a').hide();
    }
});

WebAPI is a fantastic addition to the ASP.NET stack; a feature rich REST based API has never been easier.

The ReviewItem view is responsible for rendering each individual review. The initialize() method compiles the template used to display each review; this template resides in a <script/> element. Backbone pulls the template out of the <script/> element and combines it with the review.

A click event handler is also set up for loading the comments for each review. When the link is clicked, the getComments() method is called, fetching the comments by passing an Id to the WebAPI service. The fetch() method is merely an abstraction to jQuery's $.ajax method, so normal Ajax parameters, like data, can be passed in the fetch() call. Lastly, the loadComments() method will fire and create a new CommentItem view for each comment returned. The tagName on this view ensures the view is created with an <li/> as its $el property.

Next, let's look at the CommentItem view:

var CommentItem = Backbone.View.extend({
    tagName: 'li',
    initialize: function () {
        this.template = _.template($('#commentsTemplate').html());
        this.render();
    },
    render: function () {
        var html = this.template(this.model.toJSON());
        this.$el.html(html);
    }
    
});

This is a simple view that renders each comment. Now let's modify the Review.cshtml view as follows:

@model IEnumerable<Reviewed.Models.Review>

@section scripts {
    <script type="text/javascript" src="/Scripts/home.js"></script>
}

<div class="reviews">
    <ul></ul>
</div>

<script type="text/html" id="reviewsTemplate">

    <h3><%= Topic %></h3>
    <p>
        <%= Content %>
    </p>
    
    <a href="#comments">Load Comments</a>
    <ul></ul>

</script>

<script type="text/html" id="commentsTemplate">
<li>
    <strong><%= !IsAnonymous ? Email + " says," : "" %></strong>
    <blockquote><%= Content %></blockquote>
</li>       
</script>

Notice the @section scripts in the above code. This is not a new feature to MVC4, but it is a great tool to render specific pieces of JavaScript. In the _layout.cshtml file, there's also a @RenderSection("scripts", required: false) which renders the section defined in the view. The <script/> elements are Underscore templates to render content. They follow a Ruby-esque syntax, and anything inside <% %> is evaluated as a statement. Anything inside of <%= %> will output to the HTML. Loops and conditional statements can be used like this:

<ul>
<script type="text/html" id="template">
<% for (var i = 0; i < list.length; i++) { %>
    <li><%= list[i] %></li>
<% } %>
</ul>

<% if (someCondition) { %>
    <%= output %>
<% } %>
</script>

That's the template. To use it, do this:

var template = _.template($('#template').html());
var html = template({
    someCondition: true,
    output: 'hello world',
    list: ['foo', 'bar', 'bam']
});

There are many JavaScript templating frameworks available on the Web: Handlebars.js, mustache.js, and Hogan.js are quite popular. Be sure and check them out and pick the one that works for you.

Conclusion

WebAPI is a fantastic addition to the ASP.NET stack; a feature rich REST based API has never been easier. There are a lot of great new features in MVC4. Be sure and check them out! As I previously mentioned, the code for this example is available on Github. Fork it!


September 24 2011

06:39

20 JavaScript Frameworks Worth Checking Out

The number of web applications being created and used has grown rapidly since the new millenium. And importantly, so has the sheer complexity of them — specially on the front end. No more static pages, no sir!

You have a ton of sections each interacting with each other and the server and yes, it’s as complicated as it sounds and just as hard to pull off. Today, I’d like to talk about a few, choice JavaScript frameworks that aim to simplify front end application development.


Why We Need Frameworks Like These

If you think jQuery is the answer, you lose a cookie and get an F grade!

Creating responsive, fluid, and maintainable interfaces for web apps isn’t as easy as one would imagine — there is data to be sent back to the server and the results parsed, data stores to be updated, views to be re-rendered and so much else that needs to be done in the background. Desktop developers have it much easier with robust tools and well defined workflows. Us, poor web devs? We’ve been twiddling DOM elements, creating models by hand and pulling our hair out trying to keep everything synched.

The monstrous rise in the number of web apps being built recently has really made it apparent that we need better tools and frameworks and the devs have responded with a staggering amount of solutions. Today, we’re going to go over just a few of these. A couple of these are quite old but I’m certain you can learn a lot from perusing their code base.

Sure, a few of these may be a little old but their code bases have lots of lessons to teach.


Sproutcore

Nettuts+ -- JavaScript Frameworks

Sproutcore powers a lot of high profile apps including MobileMe amongst others. Sproutcore has a steeper learning curve compared to the other options but makes up for it with developer productivity once he/she has learned the ropes.

This framework boasts a UI framework, the market standard MVC architecture and well written documentation.

Related links:


Cappuccino

Nettuts+ -- JavaScript Frameworks

Cappuccino was created by the 280North team, now owned by Motorola. This framework gained significant coverage with the release of the 280Slides — built completely with Cappuccino.

This framework varies dramatically from the others in that a developers doesn’t need to understand or work with any of the front end trifecta — HTML, CSS or the DOM. All you need to master is the framework!

Related links:


JavaScriptMVC

Nettuts+ -- JavaScript Frameworks

Built on jQuery, JavaScriptMVC is a veteran in the front end frameworks battlefield, dating back to 2008. Featuring a familiar, and obvious, MVC architecture, this framework is quite full featured with support for code generators, testing and dependency management.

Related links:


Asana Luna

Nettuts+ -- JavaScript Frameworks

Luna is one of those hush-hush private frameworks that people have been talking about. And for good reason, I must admit.

The framework features a lot of niceties including an evolved MVC architecture, pubsub, caching, routing and authentication.

Related links:


Backbone.js

Nettuts+ -- JavaScript Frameworks

Backbone supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.

Related links:


qooxdoo

Nettuts+ -- JavaScript Frameworks

qooxdoo is a universal JavaScript framework that enables you to create applications for a wide range of platforms. With its object-oriented programming model you build rich, interactive applications (RIAs), native-like apps for mobile devices, light-weight traditional web applications or even applications to run outside the browser.

Related links:


Spine

Nettuts+ -- JavaScript Frameworks

Spine is a lightweight framework for building JavaScript web applications. Spine gives you a MVC structure and then gets out of your way, allowing you to concentrate on the fun stuff, building awesome web applications.

Related links:


ActiveJS

Nettuts+ -- JavaScript Frameworks

ActiveJS is a JavaScript application framework that provides local and REST based data modeling and pure DOM view construction with back button and history support along with framework agnosticm and lack of external dependencies.

Related links:


Eyeballs

Nettuts+ -- JavaScript Frameworks

eyeballs.js is a slim javascript library designed to sit on top of a javascript framework, such as jQuery or Prototype. eyeballs.js can sit on top of an already implemented web app with a well thought out object model. It can also be used to build standalone javascript apps, backed by HTML5 local storage or something like CouchDB.

Related links:


Sammy

Nettuts+ -- JavaScript Frameworks

Sammy.js is a tiny JavaScript framework developed to ease the pain and provide a basic structure for developing JavaScript applications.

Sammy tries to achieve this by providing a small ‘core’ framework and an ever-growing list of plugins for specific functionality.

Related links:


Choco

Nettuts+ -- JavaScript Frameworks

Choco brings the MVC to the client side! A Choco app consists of only one HTML page, all the interactions are managed by Javascript. Your UI only uses HTML and CSS!

Related links:


Agility

Nettuts+ -- JavaScript Frameworks

Agility.js is an MVC library for Javascript that lets you write maintainable and reusable browser code without the verbose or infrastructural overhead found in other MVC libraries. The goal is to enable developers to write web apps at least as quickly as with jQuery, while simplifying long-term maintainability through MVC objects.

Related links:


Angular

Nettuts+ -- JavaScript Frameworks

Angular supports the entire development process, provides structure for your web apps, and works with the best JS libraries. With angular, the view and data model are always in sync — there is no need for manual DOM manipulation.

Angular is small, weighing in at 60kb, is compatible with all modern browsers and works great with jQuery.

Related links:


ExtJS

Nettuts+ -- JavaScript Frameworks

Ext JS 4 brings a whole new way to build client applications, by introducing the popular model-view-controller pattern to Ext JS. By allowing the separation of data management, logic and interface elements, Ext JS 4 makes it easier for even large development teams to work independently without worrying about stepping on each other’s toes. Ext JS 4 ships with a helpful MVC guide to get started.

Related links:


Knockout

Nettuts+ -- JavaScript Frameworks

Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model. Any time you have sections of UI that update dynamically (e.g., changing depending on the user’s actions or when an external data source changes), KO can help you implement it more simply and maintainably.

Related links:


Jamal

Nettuts+ -- JavaScript Frameworks

Jamal is a set of conventions and small javascript libraries to archieve a complete separation of html, css and javascript in your web application. Jamal is built on jQuery and inspired by MVC frameworks like Ruby on Rails, CakePHP and its derivatives.

Related links:


PureMVC

Nettuts+ -- JavaScript Frameworks

PureMVC is a lightweight framework for creating applications based upon the classic Model, View and Controller concept.

Based upon proven design patterns, this free, open source framework which was originally implemented in the ActionScript 3 language for use with Adobe Flex, Flash and AIR, is now being ported to all major development platforms.

Related links:


TrimJunction

Nettuts+ -- JavaScript Frameworks

The open source Junction framework is a conventions-over-configuration, synchronizing web MVC framework for JavaScript. TrimPath Junction is a clone or port of the terrific Ruby on Rails web MVC framework into JavaScript.

Related links:


CorMVC

Nettuts+ -- JavaScript Frameworks

CorMVC is a jQuery-powered Model-View-Controller (MVC) framework that can aide in the development of single-page, web-based applications. CorMVC stands for client-only-required model-view-controller and is designed to be lowest possible entry point to learning about single-page application architecture.

Related links:


batman

Nettuts+ -- JavaScript Frameworks

batman.js is a full-stack microframework extracted from real use and designed to maximize developer and designer happiness. It favors convention over configuration, template-less views, and high performance by simply not doing very much. It all adds up to blazingly fast web apps with a great development process; it’s batman.js.

Related links:


That’s a Wrap!

And we’re done here. The number of options here might border on overdoing things at first glance but each of these are a little different in how they tackle this problem and given a problem, different solutions and choices are always a welcome addition.

As I mentioned earlier, if you think a framework should be here but isn’t, just drop us a line below and we’ll update this roundup accordingly. Thank you so much for reading!


Sponsored post
soup-sponsored
06:46
 
 

July 13 2011

20:46

Generating Traditional URLs with ASP.NET MVC3

Advertise here

There are certain truths in the world: we’re born, we die, and URLs should end with a slash if it doesn’t point to a file. The ASP.NET MVC framework bucks tradition and convention, and the built-in methods that generate URLs do so by omitting the trailing slash. It may seem like a non-issue (and to many people it’s not one), but many developers, this author included, are bugged by them.


First, Some Background

URL stands for Uniform Resource Locator; it tells web-aware clients where to locate a particular resource on the Internet. The URL of http://www.example.com/directory/file.html points to a physical file (the resource) called file.html that resides in a directory called directory on a web server found at the example.com domain. When the web server for example.com receives a request for that URL, it knows exactly where to look for the resource. If it finds the file, it serves its contents; if not, it responds with an error.

Traditional web servers do the same thing for directory requests.

Consider the URL of http://www.example.com/directory/. This URL ends with a trailing slash, denoting a directory. When the web server receives this request, it looks for the directory directory, and if it finds it, it gets the default document and returns it to the client. Otherwise, it responds with an error.

These two examples demonstrate a simple process, but it can get more complex with ambiguous requests. For example, the URL http://www.example.com/ambiguous points to a resource called ambiguous, but it is unclear what that resource is. It could be a file, but there is no extension; it could be a directory, but there’s no trailing slash. When receiving a request for this resource, a traditional web server goes through the following process:

  • The server looks for a file called ambiguous. If it finds one, it returns it. Otherwise…
  • It sends a response back to the client, redirecting it to http://www.example.com/ambiguous/
  • The client requests the new URL
  • The server looks for the ambiguous directory and returns the appropriate response

Without explicitly specifying a resource, the requester creates an overhead in both processing time and bandwidth usage.

Without explicitly specifying a resource, the requester creates an overhead in both processing time and bandwidth usage. For this reason, the prevailing rule of thumb has been to put the trailing slash on all URLs that point to a directory. Doing so completely eliminates the wasted processing time and bandwidth usage. It has become second nature to many (maybe most?) web veterans to always include the slash at the end of URLs that do not point to a file.

So where does ASP.NET MVC fit into this? Well, ASP.NET, as you probably know, typically runs on Microsoft’s web server, called IIS. IIS, by default, behaves just like any other web server, but its true power lies in its ability to pass the handling of requests to ISAPI modules or, even better, .NET code. In the case of an ASP.NET MVC application, IIS passes each request to the MVC app for processing. There, the app determines if the request should be routed to a method on a controller, or if it should pass control back to IIS to find a physical file or directory on the file system. So the process of handling a request for http://www.example.com/ambiguous by IIS and an MVC app looks something like this:

Wait, wait, wait! If MVC applications ignore the trailing slash, what’s the problem?

When the app routes the request to a controller, the method on that controller executes, processes whatever data it needs, and returns a result to the client. It does not redirect the client to another URL (unless the method is supposed to do that). MVC applications don’t care if URLs end with a slash or not–in fact, MVC apps ignore trailing slashes. As long as the URL matches a pattern in the routing table, the MVC app will handle the request and return the requested response without causing any extra overhead.

Wait, wait, wait! If MVC applications ignore the trailing slash, what’s the problem? Technically, there isn’t one. The ambiguous URL actually points to a resource on the server: a method on a controller object in the application. But as stated earlier, web developers have been putting slashes at the end of their URLs years before Microsoft released the MVC framework. It’s habit and convention to do so.

Microsoft’s stance on the "issue" is simply to be consistent with the URLs used in our application, and that’s a technically correct stance. But in typical Microsoft fashion, the MVC framework’s helper methods only generate URLs without the trailing slash-meaning developers have to write their own code to achieve "correct" URLs. The solution presented in this article is two-fold:

  • Create an extension method that generates URLs
  • Write customized versions of the RouteLink() method.

Because this solution uses variations of RouteLink(), it’s important that your routes are named. If you’re not naming your routes, you should! Finally, some code!


Generating URLs

The MVC framework provides a class called UrlHelper. As its name implies, its purpose is to help with generating URLs for our application. It has a static method called GenerateUrl() that will do most of the hard work for us. All we have to do is provide a route name and route values. We’ll create an extention method for HtmlHelper objects called RouteUrl(), and it will have two overloads.

Writing method overloads is pretty easy. There’s typically one overload that performs all the work (one overload to rule them all), and the other overloads simply pass through their arguments to it. So you’ll start by writing the main overload, and its code follows:

public static class HtmlHelperExtensions
{
    public static string RouteUrl(this HtmlHelper htmlHelper, string routeName, RouteValueDictionary routeValues)
    {
        string url = UrlHelper.GenerateUrl(
            routeName,
            null /*actionName*/,
            null /*controllerName*/,
            routeValues,
            htmlHelper.RouteCollection,
            htmlHelper.ViewContext.RequestContext,
            true
        );

        return String.Format("{0}/", url);
    }
}

The extension method accepts three arguments. The first is the HtmlHelper object that this method operates on. Note that when calling this method, you do not need to pass the HtmlHelper object; that is done automatically for you. The second argument is the string containing the route’s name. The GenerateUrl() method will use the route’s name to return a URL properly formatted according to the route’s pattern defined in the routing table. The last argument is a RouteValueDictionary object, which contains a set of key/value pairs with all the information needed to generate the URL for the route. This includes the controller and action names, as well as any parameters the UrlHelper may need to generate the URL for the specified route.

The first statement of the method calls UrlHelper.GenerateUrl() to generate the URL. There are two overloads for the GenerateUrl() method, and the above code calls the one with the least amount of parameters. The route name is passed, but you omit the parameters specifying action and controller names. These values are actually held within the routeValues object, which is passed to GenerateUrl() as fourth argument. The HtmlHelper object gives you the next two pieces of information you need, and the final argument passed tells GenerateUrl() to include the implicit MVC values of "action" and "controller".

After the URL is generated, the RouteUrl() method calls String.Format() to create a new string, essentially concatenating the URL and a trailing slash. Note that String.Format() isn’t necessary, and you can simply write return url + "/";. How you create a string is up to you.

With the main worker overload written, now add the lazy one. Here is its code:

public static string RouteUrl(this HtmlHelper htmlHelper, string routeName, object routeValues)
{
    return RouteUrl(htmlHelper, routeName, new RouteValueDictionary(routeValues));
}

This code is straight forward. It calls the main RouteUrl() overload by passing in the appropriate data. Because extension methods are static methods, they can be called just like any other static method-which is the case in this code. Note that you could just as easily have written this code by calling the main RouteUrl() as an instance (extension) method, like this:

// Alternative version
public static string RouteUrl(this HtmlHelper htmlHelper, string routeName, object routeValues)
{
    return htmlHelper.RouteUrl(routeName, new RouteValueDictionary(routeValues));
}

It doesn’t matter. Either way, the job gets done; it comes down to your personal preference.

Calling this method from your view is quite simple. First, make sure the namespace containing the HtmlHelperExtensions class is imported, and simply use the following syntax:

Html.RouteUrl("routeName", new
    {
        controller = "ControllerName",
        action = "ActionName",
        parameterOne = "Hello",
        parameterTwo = "World"
    })

Of course, the values for controller and action, as well as the parameters, will be different for your specific MVC app. But this gives you an idea of how to use the method. Now that you can generate pretty URLs with a trailing slash, it’s time to write more extension methods to generate your links.


Generating Links

One of the most helpful HtmlHelper methods is the RouteLink() method. All you have to do is provide it the route name and values to get a string containing an anchor element with a pretty relative URL to the specified action. Of course, RouteLink() returns anchor elements containing a URL without a trailing slash; so, you need to write your own method that uses RouteUrl().

There are eleven overloads for RouteLink(), so if you want to write your own version of all eleven, feel free. This article will only walk you through the creation of a few-likely the most popular overloads. The RouteLink() method is actually an extension method, and since extensions methods cannot be overridden or hidden, you’ll have to come up with a name for your own method. This article gets super creative and uses MyRouteLink().

The main overload will accept five arguments: the HtmlHelper instance, a link’s text, the route name, a RouteValueDictionary containing the route information, and a dictionary of HTML attributes to apply to the anchor element. Like RouteUrl(), MyRouteLink() is a static method of the HtmlHelperExtensions static class. Here is its code (to save space, the class declaration is omitted):

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    RouteValueDictionary routeValues,
    IDictionary<string, object> htmlAttributes)
{
    string url = RouteUrl(htmlHelper, routeName, routeValues);

    TagBuilder tagBuilder = new TagBuilder("a")
    {
        InnerHtml = (!String.IsNullOrEmpty(linkText)) ? linkText : String.Empty
    };

    tagBuilder.MergeAttributes(htmlAttributes);
    tagBuilder.MergeAttribute("href", url);

    return MvcHtmlString.Create((tagBuilder.ToString(TagRenderMode.Normal)));
}

This code might look familiar to you if you have ever studied the ASP.NET MVC source code. The HtmlHelper class has a private method called GenerateRouteLink(), which was the inspiration for MyRouteLink(). Your method returns an MvcHtmlString object, which is an HTML-encoded string (you don’t have to do any encoding yourself). The first statement of this method uses your RouteUrl() method to get your special URL. Next, you use a TagBuilder object to build an anchor element, populating its InnerHtml property with the link’s text. Then the HTML attributes, those provided by the dictionary and the href attribute, are added to the element. Finally, the HTML output is created as a MvcHtmlString object and returned to the caller.

It’s cake from now on, as the remaining overloads will, in one way or another, call this version of MyRouteLink(). The next overload has a similar signature; the route values and attributes will simply be objects. Here is its code:

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    object routeValues,
    object htmlAttributes)
{
    return MyRouteLink(
        htmlHelper,
        linkText,
        routeName,
        new RouteValueDictionary(routeValues),
        new RouteValueDictionary(htmlAttributes)
    );
}

This code is self-explanitory. You call the main MyRouteLink() overload by passing in the appropriate data. Note you’re using a RouteValueDictionary object for the HTML attributes; it’s a suitable container for HTML attributes.

The next, and final, two overloads are more of the same, except they do not accept an argument for HTML attributes. Here is their code:

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    RouteValueDictionary routeValues)
{
    return MyRouteLink(
        htmlHelper,
        linkText,
        routeName,
        routeValues,
        new RouteValueDictionary()
    );
}

public static MvcHtmlString MyRouteLink(
    this HtmlHelper htmlHelper,
    string linkText,
    string routeName,
    object routeValues)
{
    return MyRouteLink(
        htmlHelper,
        linkText,
        routeName,
        new RouteValueDictionary(routeValues)
    );
}

The first overload in the above code omits the HTML attribute collection and specifies a RouteValueDictionary object for the route values. It calls the overload with a signature of MyRouteLink(HtmlHelper, string, string, RouteValueDictionary, IDictionary<string, object>), and passes an empty RouteValueDictionary object for the HTML attributes. The second overload has a slightly different signature, accepting an object for the route values. It calls the first overload in this code listing to generate the link.

To use this helper method, be sure you import the namespace containing the HtmlHelperExtensions class in your view. Then, you can write something like this:

@Html.MyRouteLink("My Link Text", "route name", new
    {
        controller = "ControllerName",
        action = "ActionName",
        parameterOne = "Hello",
        parameterTwo = "World"
    }
);

This code uses Razor syntax, but you can essentially do the same thing if using the ASPX view engine, like this:

<%:Html.MyRouteLink("My Link Text", "route name", new
    {
        controller = "ControllerName",
        action = "ActionName",
        parameterOne = "Hello",
        parameterTwo = "World"
    }
) %>

This code uses the new <%: %> nugget for HTML encoding output (introduced in .NET 4). The beauty of the MvcHtmlString returned by MyRouteLink() is that it's already HTML encoded, and it will not be re-encoded by using the new nugget. So you can use <%: %> or <%= %> without worrying about encoding or re-encoding.


In Closing

As mentioned earlier, there is nothing technically wrong with the URLs genereated by the MVC framework. They do not cause an overhead, as they point to an actual resource on the server. But if you've been bugged by them, now you can generate traditionally correct URLs with just a little work upfront. Microsoft is right, however: be consistent. Regardless of what URL style you prefer, make sure you consistently use the same one.

Let me know if you have any questions in the comments and thank you so much for reading!

April 28 2011

15:59

Getting Started with Backbone.js

Advertise here

Unlike its web development peers, JavaScript has never really had much in the way of frameworks to provide structure. Thankfully, in recent years, that’s beginning to change.

Today, I’d like to introduce you to Backbone.JS, a sweet little library that makes the process of creating complex, interactive and data driven apps so much easier. It provides a clean way to surgically separate your data from your presentation.


Overview of Backbone.JS

Created by Jeremy Ashkenas, the JS ninja who built CoffeeScript, Backbone is a super light-weight library that lets you create easy to maintain front ends. It’s backend agnostic and works well with any of the modern JavaScript libraries you’re already using.

Backbone is a collection of cohesive objects, weighing in at a shade under 4kb, that lend structure to your code and basically helps you build a proper MVC app in the browser. The official site describes its purpose as so:

Backbone supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.

Let’s face it: the above is a little hard to parse and make sense of. So let’s go ahead and deconstruct the jargon a bit, with help from Jeremy.

Key-value binding and custom events

When a model’s contents or state is changed, other objects that have subscribed to the model are notified so they can proceed accordingly. Here, the views listen to changes in the model, and update themselves accordingly instead of the model having to deal with the views manually.

Rich API of enumerable functions

Backbone ships with a number of very useful functions for handling and working with your data. Unlike other implementation, arrays in JavaScript are pretty neutered, which really is a hampering problem when you have to deal with data.

Views with declarative event handling

Your days of writing spaghetti bind calls are over. You can programmatically declare which callback needs to be associated with specific elements.

RESTful JSON interface

Even though the default method is to use a standard AJAX call when you want to talk to the server, you can easily switch it out to anything you need. A number of adapters have sprung up covering most of the favorites including Websockets and local storage.

To break it down into even simpler terms:

Backbone provides a clean way to surgically separate your data from your presentation. The model that works with the data is only concerned with synchronizing with a server while the view’s primary duty is listening to changes to the subscribed model and rendering the HTML.


A Quick FAQ

I’m guessing you’re probably a little fazed at this point, so let’s clear a few things up:

Does it replace jQuery?

No. They’re pretty complementary in their scopes with almost no overlaps in functionality. Backbone handles all the higher level abstractions, while jQuery – or similar libraries – work with the DOM, normalize events and so on.

Their scopes and use cases are pretty different and because you know one doesn’t mean that you shouldn’t learn the other. As a JavaScript developer, you should know how to effectively work with both.

Why should I be using this?

Because more often than not, the front end code devolves into a steaming, dirty pile of nested callbacks, DOM manipulations, HTML for the presentation amidst other unsayable acts.

Backbone offers a significantly clean and elegant way of managing this chaos.

Where should I be using this?

Backbone is ideally suited for creating front end heavy, data driven applications. Think the GMail interface, new Twitter or any other revelation of the past few years. It makes creating complex apps easier.

While you can shoehorn it for more mainstream web pages, this is really a library that is tailored for web apps.

Is it similar to Cappuccino or Sproutcore?

Yes and no.

Yes, because like the above mentioned frameworks, this is primarily intended for creating complex front ends for web applications.

It’s dissimilar in that Backbone is quite lean, and ships with none of the widget that the others ship with.

Backbone is incredibly light weight, at under 4kb.

There’s also the fact that Cappuccino forces you to write your code in Objective-J, while Sproutcore’s views have to be declared programmatically in JS. While none of those approaches are wrong, with Backbone, normal JavaScript is harnessed by your run of the mill HTML and CSS to get things done, leading to a gentler learning curve.

I can still use other libraries on the page, right?

Absolutely. Not only your typical DOM accessing, AJAX wrapping kind, but also the rest of your templating and script loading kind. It’s very, very loosely coupled, which means you can use almost all of your tools in conjunction with Backbone.

Will it usher in world peace?

No, sorry. But here’s something to cheer you up.

Ok, now with that out of the way, let’s dive in!


Getting to Know Backbone’s Backbone

The MVC in Backbone originally stood for Models, Views and Collections, since there were no controllers in the framework. This has since changed.

Backbone’s core consists of four major classes:

  • Model
  • Collection
  • View
  • Controller

Since we’re a little strapped for time, let’s take a look at just the core classes today. We’re going to do a follow up tut with a super simple app to demonstrate the concepts taught here since it’d be too much to put everything in a single article and expect the reader to parse everything.

Keep your eyes peeled over the next couple of weeks!


Model

Models can mean different things in different implementations of MVC. In Backbone, a model represents a singular entity — a record in a database if you will. But there are no hard and fast rules here. From the Backbone website:

Models are the heart of any JavaScript application, containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control.

The model merely gives you a way to read and write arbitrary properties or attributes on a data set. With that in mind, the single liner below is completely functional:

var Game = Backbone.Model.extend({});

Let’s build on this a bit.

var Game = Backbone.Model.extend({
        initialize: function(){
            alert("Oh hey! ");
        },
		  defaults: {
            name: 'Default title',
            releaseDate: 2011,
        }
    });
 

initialize will be fired when an object is instantiated. Here, I’m merely alerting out inanities — in your app you should probably be bootstrapping your data or performing other housekeeping. I’m also defining a bunch of defaults, in case no data is passed.

Let’s take a look at how to read and write attributes. But first, let’s create a new instance.


// Create a new game
var portal = new Game({ name: "Portal 2", releaseData: 2011});

// release will hold the releaseDate value -- 2011 here
var release = portal.get('releaseDate');

// Changes the name attribute
portal.set({ name: "Portal 2 by Valve"});

If you noticed the get/set mutators, have a cookie! A model’s attributes can’t be read through your typical object.attribute format. You’ll have to go through the getter/setter since there’s a lower chance of you changing data by mistake.

At this point, all the changes are only kept in memory. Let’s make these changes permanent by talking to the server.

portal.save();

That’s it. Were you expecting more? The one-liner above will now send a request to your server. Keep in mind that the type of request will change intelligently. Since this is a fresh object, POST will be used. Otherwise, PUT is used.

There are a lot more features, Backbone models give you by default but this should definitely get you started. Hit the documentation for more information.


Collection

Collections in Backbone are essentially just a collection of models. Going with our database analogy from earlier, collections are the results of a query where the results consists of a number of records [models]. You can define a collection like so:

var GamesCollection = Backbone.Collection.extend({
  model : Game,
  }
});

The first thing to make note of is that we’re defining which model this is a collection of. Expanding on our example earlier, I’m making this collection a collection of games.

Now you can go ahead and play around with your data to your hearts contents. For example, let’s extend the collection to add a method that returns only specific games.

var GamesCollection = Backbone.Collection.extend({
  model : Game,
  old : function() {
    return this.filter(function(game) {
      return game.get('releaseDate') < 2009;
    });
  }
  }
});

That was easy, wasn’t it? We merely check if a game was released before 2009 and if so, return the game.

You can also directly manipulate the contents of a collection like so:

var games = new GamesCollection
games.get(0);

The above snippet instantiates a new collection and then retrieves the model with an ID of 0. You can find an element at a specific position through referencing the index to the at method like so: games.at(0);

And finally, you can dynamically populate your collection like so:

var GamesCollection = Backbone.Collection.extend({
  model : Game,
  url: '/games'
  }
});

var games = new GamesCollection
games.fetch();

We’re merely letting Backbone where to get the data from through the url property. With that done, we’re merely creating a new object and calling the fetch method which fires of an asynchronous call to the server and populates the collection with the results.

That should cover the basics of collections with Backbone. As I mentioned, there are tons of goodies here what with Backbone aliasing a lot of nifty utilities from the Underscore library. A quick read through of the official documentation should get you started.


View

Views in Backbone can be slightly confusing at first glance. To MVC purists, they resemble a controller rather than a view itself.

A view handles two duties fundamentally:

  • Listen to events thrown by the DOM and models/collections.
  • Represent the application’s state and data model to the user.

Let’s go ahead and create a very simple view.

GameView= Backbone.View.extend({
  tagName : "div",
  className: "game",
  render : function() {
    // code for rendering the HTML for the view
  }
});

Fairly simple if you’ve been following this tutorial so far. I’m merely specifying which HTML element should be used to wrap the view through the tagName attribute as well as the ID for it through className.

Let’s move ahead to the rendering portion.

  render : function() {
    this.el.innerHTML = this.model.get('name');

	 //Or the jQuery way
	 $(this.el).html(this.model.get('name'));
  }

el refers to the DOM element referenced by the view. We’re simply accessing the game’s name to the element’s innerHTML property. To put it simply, the div element now contains the name of our game. Obviously, the jQuery way is simpler if you’ve used the library before.

With more complicated layouts, dealing with HTML within JavaScript is not only tedious but also foolhardy. In these scenarios, templating is the way to go.

Backbone ships with a minimal templating solution courtesy of Underscore.JS but you’re more than welcome to use any of the excellent templating solutions available.

Finally, let’s take a look at how views listen to events. DOM events first.

events: {
        'click .name': 'handleClick'
    },

handleClick: function(){
		  alert('In the name of science... you monster');

		  // Other actions as necessary
}

Should be simple enough if you’ve worked with events before. We’re basically defining and hooking up events through the events object. As you can see above, the first part refers to the event, the next specifies the triggering elements while the last part refers to the function that should be fired.

And now onto binding to models and collections. I’ll cover binding to models here.

GameView= Backbone.View.extend({
initialize: function (args) {
        _.bindAll(this, 'changeName');
		  this.model.bind('change:name', this.changeName);
},
});

The first thing to note is how we’re placing the binding code in the initialize functions. Naturally, it’s best to do this from the get go.

bindAll is a utility provided by Underscore that persists the value of a function’s this value. This is specially useful since we’re passing a bunch of functions around and functions specified as callbacks have this value erased.

Now whenever a model’s name attribute is changed, the changeName function is called. You can also make use of the add and remove verbs to poll for changes.

Listening to changes in a collections is as simple as replacing model with collection while binding the handler to the callback.


Controller

Controllers in Backbone essentially let you create bookmarkable, stateful apps by using hashbangs.

var Hashbangs = Backbone.Controller.extend({
  routes: {
    "!/":                 "root",
    "!/games":        "games",
  },
  root: function() {
    // Prep the home page and render stuff
  },

  games: function() {
    // Re-render views to show a collection of books
  },
  });
  

This is very familiar to routing in traditional serverside MVC frameworks. For example, !/games will map to the games function while the URL in the browser itself will be domain/#!/games.

Through intelligent use of hashbangs, you can create apps that are heavily JS based but also bookmarkable.

If you’re worried about breaking the back button, Backbone has you covered too.

// Init the controller like so
var ApplicationController = new Controller; 

Backbone.history.start();

With the above snippet, Backbone can monitor your hashbangs and in conjunction with the routes you’ve specified earlier, make your app bookmarkable.


What I Learned from Backbone

Overall, here are some lessons I learned from the Backbone way of creating applications:

  • We really need MVC for the front end. Traditional methods leave us with code that’s too coupled, messy and incredibly hard to maintain.
  • Storing data and state in the DOM is a bad idea. This started making more sense after creating apps that needed different parts of the app to be updated with the same data.
  • Fat models and skinny controllers are the way to go. Workflow is simplified when business logic is taken care of by models.
  • Templating is an absolute necessity. Putting HTML inside your JavaScript gives you bad karma.

It’s sufficient to say that Backbone has caused a paradigm shift in how front ends should be constructed, at least for me. Given the very broad scope of today’s article, I’m sure you have a ton of questions. Hit the comments section below to chime in. Thank you so much for reading and expect a ton more Backbone tutorials in the future!

February 23 2011

18:38

Create your First Tiny MVC Boilerplate with PHP


I’m often asked about how to create an extremely simple MVC boilerplate for small projects which don’t require a massive framework, like CodeIgniter or CakePHP. We’ll build a solution in ten minutes or so.

It’s important for me to note that I’m not advocating that you shouldn’t use large frameworks. They absolutely have their places, and I use them often. That said, there are definitely times when they can be overkill for smaller projects. When your only requirement is code organization, it’s typically better to scrape together your own MVC boilerplate.


Conclusion

If you enjoyed this video, and would like to take our tiny framework to the next level, we can definitely do so together. Let me know in the comments!

November 17 2010

14:00

Basecamp Style Subdomains With CodeIgniter


CodeIgniter is a simple and lightweight PHP framework used to create powerful web applications. Today, we are going to do something nifty: we’ll combine user names and subdomains to make for a more cohesive user experience.

If you’re a bit confused, this feature allows your users to access their accounts by typing in a custom url, which maps to their user name, such as harbinger.yourapp.com.


Overview

In this tutorial, we are going to be creating both a front-end view and a back-end application view, similar to the configuration used in Basecamp, where visiting basecamphq.com shows the homepage, but visiting a subdomain displays the login page.

We will be using the fictional address nettutsapp.com, and will create a sample “dashboard” page; however, you could incorporate this into an existing project with relative ease.

basecamp-comapre

Before you begin, make sure that you have a web server with PHP installed. You also need to download CodeIgniter; in the example, I am using CodeIgniter 2.0, but the code should work on 1.7.2. So let’s get started!


Step 1: DNS Configuration

First, we need to configure our DNS settings to make all subdomains resolve to a single address. If you are working on a live server, then you will have to change your DNS settings with the company who handles your DNS. This is most commonly your web host or domain registrar.

To cover each configuration in this tutorial would take too much time. Instead, ask your host for some help to set up wildcard subdomains. You might expect to add something like the line below to your DNS configuration.

*.nettutsappapp.com.      IN  A    91.32.913.343

Instead, if you are working on a local server, adding a wildcard subdomain to the hosts file is quite tricky. What I prefer to do is add single entries for testing purposes. These can be deleted after you have finished. For our domain, we need to add four entries as follows:

  • 127.0.0.1     nettutsapp.com
  • 127.0.0.1     user1.nettutsapp.com
  • 127.0.0.1     user2.nettutsapp.com
  • 127.0.0.1     user3.nettutsapp.com

Mac Hosts Configuration

To do this on a Mac, open Terminal and type sudo nano /etc/hosts. Use the arrow keys to move to the bottom of the document, and add the entries to the bottom of the file. Once done, press Ctrl+X and Y to confirm the save.

dns-terminal1

Windows Hosts Configuration

If you are using Windows, browse to the directory C:\Program Files\system32\drivers\etc and open the hosts file in Notepad, or your preferred text editor. Add four entries, shown above, and save the file.

If you’ve made DNS changes to a live server, it will take a while before you notice any effect. If you made changes to your hosts file, the changes will be immediate.


Step 2: Apache Configuration

The aim here is to set up two Virtual Hosts in the Apache Configuration,:one serves the front end page (Basecamp Homepage), and the other serves the page seen when accessed via a subdomain (Dashboard Page).

To add new entries, you need to open the httpd.conf file, which can be found in the Apache installation directory. It’s often found in the bin/apache/conf folder. However, depending on your server configuration, the location may vary.

Once opened, you need to add the two entries, shown below. Be sure to change the DocumentRoot to a location of your choice, which you have created.

Note: Remember the wildcard and the different directory path on the second VirtualHost.

WAMP Users: I recommend reading this post, which describes how to set up VirtualHosts. You may also encounter permission problems; so I recommend placing your VirtualHost directories inside the www directory.

	<VirtualHost *:80>
		DocumentRoot "/Users/densepixel/Sites/MAMP PRO/nettutsappfront"
		ServerName nettutsapp.com
		ServerAlias nettutsapp.com

		<Directory "/Users/densepixel/Sites/MAMP PRO/nettutsappfront">
			Options -Indexes
			Options FollowSymLinks
			AllowOverride All
		</Directory>
	</VirtualHost>

	<VirtualHost *:80>
		DocumentRoot "/Users/densepixel/Sites/MAMP PRO/nettutsapp"
		ServerName nettutsapp.com
		ServerAlias *.nettutsapp.com

		<Directory "/Users/densepixel/Sites/MAMP PRO/nettutsapp">
			Options -Indexes
			Options FollowSymLinks
			AllowOverride All
		</Directory>
	</VirtualHost>

Once you have saved the file, you need to restart Apache for the changes to take effect.

Make sure that you have created the directories you specified in the httpd.conf file before starting the server.


Step 4: Testing Our Server Configuration

Before we test the configuration, place a basic html page in each of the directories you created earlier. Maybe add a single line of text to each, so you can differentiate them. I have copied an example for you to use.

<!DOCTYPE html>
<html lang="">
<head>
	<meta charset="utf-8">
	<title>NetTuts App Front</title>
</head>
<body>
	NetTutsApp Front
</body>
</html>

Next, open your favorite browser, and first check the address nettutsapp.com. If everything works, you should be looking at the page you placed in the ‘nettutsappfront‘ directory.

Next, check a subdomain, eg. user1.nettutsapp.com; this should show you the other page you created in the directory.

config-success

You can go on to check the other subdomains you specified in the hosts file, which should all show the page saved within our directory.

Step 5: CodeIgniter Installation

This tutorial assumes that you know how to install CodeIgniter. If not, you should take a look at this video tutorial by Jeffrey Way, which explains the process in detail.

Place the CodeIgniter files into our directory after deleting the html page we created before. If you are using CodeIgniter 1.7.2, you may want to take the application folder out of the system folder.

nettutsapp-ci

Test the installation by browsing to the URL user1.nettutsapp.com, and you should see the CodeIgniter Welcome Page.

nettutsapp-ci-welcome

Step 6: Setting up CodeIgniter

Set up CodeIgniter as you normally would, as described in this tutorial. You may want to remove the index.php from the URL, autoload some libraries or helpers, etc. For the purposes of this tutorial, we need to autoload the database library and the url helper. Open the autoload.php file in the config directory, and add the relevant entries.

We also need to change the default controller to one which we will be making, called dashboard. This value can be changed within the /config/routes.php file.

Base_url

For the user subdomains, we need to make the base_url variable dynamic, as the application will be receiving requests from a number of potential subdomains.

The easiest way to do this is by using the HTTP_HOST variable. Open the config.php file, and find the variable $config['base_url'], and replace it with the following code:

if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on"){$ssl_set = "s";} else{$ssl_set = "";}
$config['base_url'] = 'http'.$ssl_set.'://'.$_SERVER['HTTP_HOST'];

This code allows for HTTPS connections, however, if you never plan on using HTTPS, you can simplify it to base_url = $_SERVER['HTTP_HOST'].

Database Settings

Before we go ahead and add the database settings into our CodeIgniter application, we need to create both the database and a sample table.

This example application uses one database and one table. This table will hold all the subdomains currently assigned, and some basic information about them. If you’ve decided to use this code in your own application, you’ll have to generally assign multiple users to a single subdomain, however that database schema is beyond the scope of this tutorial.

The table is named nt_subdomains, within the database ntapp, and has four fields:

  • subdomain_id(primary, auto_increment)
  • subdomain_name
  • user_fname
  • user_sname

I have also populated the table with two records, which match the subdomains we’ve added to our hosts file:

php-my-admin

Now we can open the database config, file found in /application/config/database.php, and edit the following values so that they match your personal configuration settings.

$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root'; //MAMP default
$db['default']['password'] = 'root'; //MAMP default
$db['default']['database'] = 'ntapp';

And we’re done setting up our CodeIgniter installation. Let’s start using the subdomains in our application.


Step 7: Creating Our Controllers and Views

For this application, we are going to create two controllers. The first is an error controller, which displays an error if the subdomain has not been registered for use in the application. The other controller is our main dashboard controller, which is what the user sees if the subdomain has been added to our database.

Error Controller

Let’s go ahead and create our error controller. First, create a new file in the /application/controllers directory, and call it error.php.
Note: The name of the file is important

<?php

class Error extends Controller {

	function Error()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('error');
	}
}

Add the code above to our new error.php file. The index function loads a view called ‘error‘, which we will be creating later.

Dashboard Controller

Now we need to create the main dashboard controller, which will be loaded when a user enters one of the subdomains. The controller will then check whether the subdomain has been registered, and will redirect as necessary. We’ll add this code later, but first, we need to create the basic controller.

Create a new file within the controllers directory, and name it dashboard.php. Within this file, we need to create the controller and load the dashboard view. Copy the code below and save the file.

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('dashboard');
	}
}

Error View

The error page will be displayed when a user tries to access a subdomain, which has not been registered for use by the application. For the purposes of the tutorial, simply create a basic page, displaying the message Subdomain Not Registered. Add the code below to a new file called error.php and save it within the application/views folder.

<html>
<head>
	<title>Application Error : Nettuts App</title>
</head>
<body>

	<h1>Nettuts Application Error</h1>

	<p>Subdomain Not Registered</p>

</body>
</html>

Dashboard View

initial-dashboard

For the time being, we will only be creating a basic dashboard page. You can use the same structure as the error view, and just change it to read Nettuts Dashboard, or something along those lines. Save the page as dashboard.php, within the application/views folder.

Test the two views by visiting the URLs:

  • user1.nettutsapp.com/index.php/error
  • user1.nettutsapp.com/index.php/dashboard

Working? Let’s move on.


Step 8: Extending Our Dashboard Controller (Part 1)

The next step is to extract the subdomain name in our controller so we can use it in a database query.

We are going to insert our subdomain checking code into the construct function within the dashboard controller. (Underneath the parent::Controller()). This means that the subdomain will be checked when any of the functions within the dashboard controller are accessed.

The easiest way to extract the subdomain name is to use the PHP explode function, and set the delimiter to ‘.’. As we only need the first part, we can split it into two parts, and then assign the first part (the subdomain name) to a variable.

To test this, we can echo the variable out in the controller itself. See the code below:

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();

		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2); //creates the various parts
		$subdomain_name = $subdomain_arr[0]; //assigns the first part
		echo $subdomain_name; // for testing only
	}

}

Access your subdomain URLs, and you should see the correct subdomain echoed on your page, as below.
Note: You can delete the echo statement now.

subdomain-parse1

Now that we have access to the subdomain name in our controller, we can check to see if it has been added the table we created earlier.

We will be using CodeIgniter’s ActiveRecord Class to build our queries, which will check the table for the accessed subdomain. If it is present, then the user will be able to access the dashboard page. If, on the other hand, the subdomain has not been entered, then they are denied access, and are then redirected to the error page we created earlier.

For this tutorial, we won’t be using models as it makes the tutorial much easier to follow. CodeIgniter is quite flexible in that it doesn’t force you to use them.

First, we need to assemble the query as show below. This code will only work in PHP5, as it uses method chaining; however, you can change it to your liking.

// adds on from rest of construct //
$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
$query = $this->db->get();

We can use the CodeIgniter function row() to check whether that subdomain exists in the table. If it doesn’t, then we need to use the redirect function to redirect our users to the error controller. The next part of the code is below:

// adds on from previous code //
if($query->num_rows() < 1)
		{
		redirect ('error');
		}

Let’s test this by accessing user1.nettutsapp.com, which should direct you to the dashboard page. Now, try user3.nettutsapp.com, which should redirect you to the error page as it was not entered into the table.

subdomain-comapre1

Step 9: Extending Our Dashboard Controller (Part 2)

Now we can use the information in the table to display specific information for each subdomain.

We’ll add to the index function in our dashboard controller. First, copy the subdomain name code and the database query we used before.

function index()
	{
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];

		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();

	}

We are using CodeIgniter’s row() function to retrieve the result of the query. The row function returns a single result row, which means we don’t need to use a foreach loop; it’s unnecessary.

// adds on from rest of index function //
$subdomain_info = $query->row();

Then, assign the user_fname and user_sname column values to the array, $data, which is then passed to the view.

$data['fname'] = $subdomain_info->user_fname;
$data['sname'] = $subdomain_info->user_sname;
$this->load->view('dashboard', $data);

We can use these values within our view by using the variables $fname and $sname. Open the dashboard view and edit it to read:

	<p>Welcome to your dashboard
	<b><?php echo $fname; ?> <?php echo $sname ?></b>
	</p>

And we’re done! Let’s test it.


Step 10: Testing

Try all of the URLs, and hopefully, if everything went according to plan, the results should be as follows:

  • nettutsapp.com → Front End Page
  • user1.nettutsapp.com → Dashboard (John Doe)
  • user2.nettutsapp.com → Dashboard (Steve Smith)
  • user3.nettutsapp.com → Error Page
finalresult

Controller and View Code

Here’s the complete cote used for our controllers and views:

Dashboard Controller

<?php

class Dashboard extends Controller {

	function Dashboard()
	{
		parent::Controller();

		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];

		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();

		if($query->num_rows() < 1)
		{
		redirect ('error');
		}

	}

	function index()
	{
		$subdomain_arr = explode('.', $_SERVER['HTTP_HOST'], 2);
		$subdomain_name = $subdomain_arr[0];

		$this->db->from('nt_subdomains')->where('subdomain_name', $subdomain_name);
		$query = $this->db->get();

		$subdomain_info = $query->row();
		$data['fname'] = $subdomain_info->user_fname;
		$data['sname'] = $subdomain_info->user_sname;
		$this->load->view('dashboard', $data);
	}
}

Error Controller

<?php

class Error extends Controller {

	function Error()
	{
		parent::Controller();
	}

	function index()
	{
		$this->load->view('error');
	}
}

Dashboard View

<html>
<head>
	<title>Dashboard : Nettuts App</title>
</head>
<body>

	<h1>Nettuts Dashboard</h1>

	<p>Welcome to your dashboard
	<b><?php echo $fname; ?> <?php echo $sname ?></b>
	</p>

</body>
</html>

Error View

<html>
<head>
	<title>Application Error : Nettuts App</title>
</head>
<body>

	<h1>Application Error</h1>

	<p>Subdomain Not Registered</p>

</body>
</html>

Conclusion

Of course, this tutorial describes only one way of obtaining this nifty functionality. I’m sure there are many more; so feel free to chime in with your thoughts and opinions in the comments section below.

November 02 2010

04:41

ASP.NET From Scratch: Controllers and Simple Model Validation


This latest episode continues to delve into the ASP.NET MVC framework by looking at controllers and their role in MVC applications. You also learn how to perform model validation by implementing the IDataErrorInfo interface.


The Complete Series


Controllers and Simple Model Validation

Press the HD button for a clearer video.
Premium Members: Download this Video ( Must be logged in)

Sell ASP.NET Components on CodeCanyon

Did you know that you can sell your ASP.NET scripts and components on CodeCanyon? Simply sign-up for a free author account, and start selling!

May 18 2010

15:56

HVMC: an Introduction and Application


This tutorial is an introduction to the Hierarchical Model View Controller(HMVC) pattern, and how it applies to web application development. For this tutorial, I will use examples provided from the CodeIgniter from Scratch series and demonstrate how HMVC can be a valuable modification to your development process. This introduction assumes you have an understanding of the Model View Controller (MVC) pattern. We suggest you read our introduction to MVC to get acquainted with the topic before tackling this tutorial.


What is HMVC?

HVMC is an evolution of the MVC pattern used for most web applications today. It came about as an answer to the salability problems apparent within applications which used MVC. The solution presented in the JavaWorld web site, July 2000, proposed that the standard Model, View, and Controller triad become layered into a “hierarchy of parent-child MCV layers“. The image below illustrates how this works:

Each triad functions independently from one another. A triad can request access to another triad via their controllers. Both of these points allow the application to be distributed over multiple locations, if needed. In addition, the layering of MVC triads allows for a more in depth and robust application development. This leads to several advantages which brings us to our next point.


Why should I use HMVC?

Key advantages to implementing the HMVC pattern in your development cycle:

  • Modularization: Reduction of dependencies between the disparate parts of the application.
  • Organization: Having a folder for each of the relevant triads makes for a lighter work load.
  • Reusability: By nature of the design it is easy to reuse nearly every piece of code.
  • Extendibility: Makes the application more extensible without sacrificing ease of maintenance.

These advantages will allow you to get M.O.R.E out of your application with less headaches.


Setting up HMVC in CodeIgniter

To add extra depth to the CodeIgniter from Scratch series, we will be viewing today’s examples in CodeIgniter. I will lead us though the steps needed to get CodeIgniter working with HMVC. Once we’re done with that, I’ll provide a couple of examples. Let’s begin!

Preface

To run web applications, you need a web server on your computer if you are not working remotely. Here are recommendations with links to installation instructions:


Step 1. Download and Install CodeIgniter

Go to codeigniter.com and click the “Download CodeIgniter” link. If you know how to install it and want to skip past this step click here

Extract the contents of the zip file to your web server’s document root.

Rename the “CodeIgniter_1.7.2” folder to “hmvcExample“.

Move the “hmvcExample/system/application” folder to “hmvcExample/application“. This is common practice with CodeIgniter. The purpose of doing this is to separate the application from the core of the framework. We should now have a directory that looks like the image below:

Open “hmvcExample/application/config/config.php” in your editor of choice.

Edit the site base url to match the location of your install. In my case I would change

$config['base_url'] = "http://example.com/";

into

$config['base_url'] = "http://localhost/hmvcExample/";

Save your changes and close “hmvcExample/application/config/config.php

Test that we have a working version of CodeIgniter. Open your browser and check your “http://yourhost/hmvcExample/”.
You should be greeted with the “Welcome to CodeIgniter” screen below:

That’s it! You have successfully downloaded and installed CodeIgniter. Now we will move on to making it work with the HMVC extension.


Step 2. Download and Install HMVC Extension

Download version 5.2 of the modular extension from the CodeIgniter Wiki.

In the contents of the zip file are three php files:

Move these three files into the “hmvcExample/application/libraries/” folder.

Recheck your browser. You should still see the Welcome to CodeIgniter screen.

It’s time to add the modules. Create the following directory structure “application/modules/welcome/controllers/“.

Move the “application/controllers/welcome.php” to “application/modules/welcome/controllers/welcome.php“.

Recheck your browser. You should still see the Welcome to CodeIgniter screen.

Create the folder “application/modules/welcome/views/

Move the “application/views/welcome_message.php” to “application/modules/welcome/views/welcome_message.php“.

Do a final check on your browser. You should still see the Welcome to CodeIgniter screen.

That’s it! Modular Extensions is installed correctly.


Login Module Example

Now that we have our HMVC enabled instance of CodeIgniter, I will demonstrate some short examples. For our first example I will show how you can apply user access restrictions to pages or entire modules.

Download and unzip CodeIgniter from Scratch Day 6 source files into your web server. You should end up with a folder called “ci_day6/” alongside our “hmvcExample/

Create the “login” module in our “hmvcExample/application” directory. It should end up looking like this

	hmvcExample/application/modules/login/controllers/
	hmvcExample/application/modules/login/models/
	hmvcExample/application/modules/login/views/

Create the “site” module in our “hmvcExample/application” directory. It should end up looking like this

	hmvcExample/application/modules/site/controllers/
	hmvcExample/application/modules/site/models/
	hmvcExample/application/modules/site/views/

TIP: When working with modules I keep a folder named RENAME with the three empty folders controllers, models and views. This saves me a little bit of time anytime I wish to create a new model.

Now we copy over the login module files from “ci_day6/” to our “hmvcExample/“.

	ci_day6/application/controllers/login.php
	ci_day6/application/models/membership_model.php
	ci_day6/application/views/login_form.php
	ci_day6/application/views/signup_form.php
	ci_day6/application/views/signup_successful.php

Copy/Move each of the above files over as listed below

	hmvcExample/application/modules/login/controllers/login.php
	hmvcExample/application/modules/login/models/membership_model.php
	hmvcExample/application/modules/login/views/login_form.php
	hmvcExample/application/modules/login/views/signup_form.php
	hmvcExample/application/modules/login/views/signup_successful.php

Next we copy over the site module files from “ci_day6/” to our “hmvcExample/“.

	ci_day6/application/controllers/site.php
	ci_day6/application/views/logged_in_area.php

Copy/Move each of the above files over as listed below

	hmvcExample/application/modules/site/controllers/site.php
	hmvcExample/application/modules/site/views/logged_in_area.php

The last files to copy over are the global views and CSS and image files. The asterisk (*) denotes folder and all its contents including sub folders

ci_day6/css/*
ci_day6/img/*
ci_day6/application/views/includes/*

Copy each of the above folders and all their content over as listed below

hmvcExample/css/*
hmvcExample/img/*
hmvcExample/application/views/includes/*

Open “hmvcExample/application/config/autoload.php” and edit it to look like the this:

$autoload['libraries'] = array('database', 'session');	// Need to Autoload DB and Session

/*
| -------------------------------------------------------------------
|  Auto-load Helper Files
| -------------------------------------------------------------------
| Prototype:
|
|	$autoload['helper'] = array('url', 'file');
*/

$autoload['helper'] = array('url', 'form');		// Need to autoload url and form.

If you have not already done so from step one, open “hmvcExample/application/config/config.php” and edit it so that the base url is set to your appropriate location.

$config['base_url'] = "http://localhost/hmvcExample/";	// web address. WARNING keep trailing /

Open “hmvcExample/application/config/database.php” and add the appropriate links to your database.

$db['default']['hostname'] = "localhost";		// location of DB server
$db['default']['username'] = "YOUR USERNAME HERE";	// username you use to connect
$db['default']['password'] = "YOUR PASSWORD HERE";	// associated password
$db['default']['database'] = "ci_series";		// The database you want to use

Open your browser to test that the login page displays “http://localhost/hmvcExample/index.php/login

Now to make this login function, we need to create the membership database table. For this, we need to create a table in your PHPMyAdmin.

Select or create your “ci_series” database.

In the sQL tab, paste the code below into the textarea and click go

CREATE TABLE  `ci_series`.`membership` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`first_name` VARCHAR( 32 ) NOT NULL ,
`last_name` VARCHAR( 32 ) NOT NULL ,
`email_address` VARCHAR( 64 ) NOT NULL ,
`username` VARCHAR( 32 ) NOT NULL ,
`password` VARCHAR( 32 ) NOT NULL
) ENGINE = MYISAM ;

With the membership table created, we click on the create account link on the login page and add a user to the database.

Login in as the user and confirm that you are now in the “site/members_area” of the site. It should look similar to the image below:

Click “logoff” link and try to manually go back to the members area. you will see that you no longer have permission to do so.

So we have our triads grouped, but we are still not quite in HMVC mode yet. In the site controller we find a function called is_logged_in().

	function is_logged_in()
	{
		$is_logged_in = $this->session->userdata('is_logged_in');
		if(!isset($is_logged_in) || $is_logged_in != true)
		{
			echo 'You don\'t have permission to access this page. Login';
			die();
		}
	}

This is a login related function. In MVC mode, this is required because site cannot access login. With HMVC we can fix this.

Cut the is_logged_in() function out of “applications/modules/site/controllers/site.php

Save site.php without the is_logged_in() function.

Open “applications/modules/login/controllers/login.php“.

Paste the is_logged_in() function into the class.

Save login.php

Open “applications/modules/site/controllers/site.php“.

	function __construct()
	{
		parent::Controller();
        $this->is_logged_in();
	}

In the __Construct() function, we make the HMVC call to login’s is_logged_in() function, as seen below:

	function __construct()
	{
		parent::Controller();
        // Format: modules::run('module/controller/action', $param1, $param2, .., $paramN);
        modules::run('login/is_logged_in');
	}

MVC 101 Complete

There you have it! We have successfully altered day six code into HMVC format. The site module now requests the login check instead of having to use its own. While outwardly we observe no difference, the site design has fundamentally been changed. All login functions are now where they belong: inside the login triad. This may seem like a lot of work with small reward but it is not so. Any login changes can be made once. The internal structure of the triad can be edited without having to change the entire application in response. Code replication for other controllers is no longer required. Last but not least, all the related code is in one handy location. This tiny step may not WOW you but when we delve deeper into bigger, complex applications, the M.O.R.E. apparent it will become how effective the HMVC pattern is.


Members Section Example

We are now going to uncover more of HMVC’s power. We just demonstrated how to call a module from a controller. There are other places you can do that as well. HMVC was build with the User Interface (UI) in mind. We get to call modules from our views as a result. This is where the power of HMVC can really shine.

When calling HMVC from a view you will use the same modules::run(). There is only one requirement when doing this. The resulting output from the call must be a html snippet and not a complete view. This is because we are already inside a view at the time we call the run function. We will see this in action down the page as we edit the site module views.


Step 1. Edit Login Controller

We are going to create a block which appears on the top of every page with our user’s name, important links, and logout option. Widgets like this are commonplace on sites today. The image below illustrates the end result.

Open “applications/modules/login/controllers/login.php“.

    function cp()
    {
        if( $this->session->userdata('username') )
        {
            // load the model for this controller
            $this->load->model('membership_model');
            // Get User Details from Database
            $user = $this->membership_model->get_member_details();
            if( !$user )
            {
                // No user found
                return false;
            }
            else
            {
                // display our widget
                $this->load->view('user_widget', $user);
            }
        }
        else
        {
            // There is no session so we return nothing
            return false;
        }
    }

Paste/Write the code above into the login controller.

cp() receives information from the membership_model function, get_member_details(), which we create in the next step. If a user is found we will display the view snippet detailed in step three. From there we should get the desired block illustrated above.

Save the changes you made to login.php


Step 2. Edit Membership Model

You will notice that we called a get_member_details() from the membership_model. This function gets our user information from the database and will be accessed from a few different sources. We are going to work on that now.

Open “applications/modules/login/models/membership_model.php“.

	function get_member_details($id=false)
	{
		if( !$id )
		{
			// Set Active Record where to the current session's username
			if( $this->session->userdata('username') )
			{
				$this->db->where('username', $this->session->userdata('username'));
			}
			else
			{
				// Return a non logged in person from accessing member profile dashboard
				return false;
			}
		}
		else
		{
			// get the user by id
			$this->db->where('id', $id);
		}
		// Find all records that match this query
		$query = $this->db->get('membership');
		// In this case because we don't have a check set for unique username
		// we will return the last user created with selected username.
		if($query->num_rows() > 0)
		{
			// Get the last row if there are more than one
			$row = $query->last_row();
			// Assign the row to our return array
			$data['id'] = $row->id;
			$data['first_name'] = $row->first_name;
			$data['last_name'] = $row->last_name;
			// Return the user found
			return $data;
		}
		else
		{
			// No results found
			return false;
		}

Comment your code! It’s a best practice and will help others understand what you wrote.

Line 01: The function call has a default variable $id. This allows us an option of finding a user by ID rather than by username. This made optional by setting it to false in the declaration.

The rest of the function is straight forward and well commented. We query the membership table for a user via username or ID. The result is saved to the $data array and returned. All other outcomes return false.

Save the changes you made to membership_model.php


Step 3. Create User Widget View

The third and final piece to the widget we are creating is the xhtml snippet, which we can put into any other view. This is called by the login controller’s cp() function which we just wrote.

Open “applications/modules/login/views/user_widget.php“.

<code style="font-family: Monaco, Verdana, Sans-serif;
                 font-size: 12px;
                 background-color: #f9f9f9;
                 border: 1px solid #D0D0D0;
                 color: #002166;
                 display: block;
                 margin: 14px 0 14px 0;
                 padding: 12px 10px 12px 10px;">
	<?php echo $first_name.' '.$last_name; ?> &middot;
	<?php echo anchor('site/members_area', 'Dashboard'); ?> |
	<?php echo anchor('site/profile/'.$id, 'Profile'); ?> |
    <?php echo anchor('site/messages/'.$id, 'Messages'); ?> |
	<?php echo anchor('login/logout', 'Logout'); ?>
</code>

Note: It is not a good practice to use inline styling. I opted to put this one instance of inline style for the sake of remaining on topic.

This styled code block takes the information passed from the cp() function. We generate the links using CodeIgniter’s URL helper’s anchor() function. More information about the user guide can be found on codeigniter.com.

After working on those three files we will test the “login/cp” page. We should see something like the image below. Note: You need to be logged int to see it. Be sure to do so before checking the page or you will see nothing.


Step 4. Edit Site Controller

The links in the snippet to profile and messages will return an error for the moment. This is ok because we have not created those functions yet. Lets do that now.

Open “applications/modules/site/controllers/site.php“.

<?php
class Site extends Controller
{
	function __construct()
	{
		parent::Controller();
	}

	function members_area()
	{
		modules::run('login/is_logged_in');
		$this->load->view('logged_in_area');
	}

__construct()
For the purpose of this example we shall remove the…

modules::run('login/is_logged_in');

…from the function so that we can make specific parts private and have other parts public.

members_area()
We want only logged in users to access the members dashboard area. So we will use the modules:run HMVC function and call the is_logged_in check from the login controller. We then load the logged_in_area view file which will be edited further down the page.

	function messages()
	{
		modules::run('login/is_logged_in');
		$this->load->model('login/membership_model');
		$user = $this->membership_model->get_member_details($this->uri->segment(3));
		if( !$user )
		{
			// No user found
			return false;
		}
		else
		{
			// display our widget
			$this->load->view('member_messages', $user);
		}
	}

messages()
Like members_area(), we only want logged in users so we have included the is_logged_in check. We have already written the code on how to get user details from the database so we will load the login model, membership_model. This will allow us to get the user information via the get_member_details() function. The third URI segment being passed into that function is an id for the user we wish to get messages for. For example, if the url was:


http://localhost/hmvcExample/index.php/site/messages/43

Then our function get_member_details() would be receiving “43″ as an input variable. Depending on the result of get_member_details(), we are either shown the view: member_messages or we get nothing (as a result of a failed query).

	function profile()
	{
		$this->load->model('login/membership_model');
		$user = $this->membership_model->get_member_details($this->uri->segment(3));
		if( !$user )
		{
			// No user found
			$data['main_content'] = 'member_profile';
			$data['notice'] = 'you need to view a profile id';
			$this->load->view('includes/template', $data);
		}
		else
		{
			// display our widget
			$user['main_content'] = 'member_profile';
			$this->load->view('includes/template', $user);
		}
	}
}

profile()
Just like any social network; we want the profile pages to be public. So we have not included the is_logged_in check. Just like messages, we call the login triad’s membership_model and query the database for our desired user. In this case, if no user is found, we quit a bit more gracefully. We also notify the visitor that an id needs to be specified. With a successful result, we see the member’s profile.


Step 5 Edit Logged In Area View

Open “applications/modules/site/views/logged_in_area.php“.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>untitled</title>
</head>
<body>
	<?php echo modules::run('login/cp');?>
	<h2>Welcome Back, <?php echo $this->session->userdata('username'); ?>!</h2>
     <p>This section represents the area that only logged in members can access.</p>
</body>
</html>

Overwrite the contents of the file with the code above.

Line 08: HMVC is put into action here. Our view calls the “login/cp” function, and echoes out the html snippet exactly where we tell it. Notice how we didn’t have to prepare anything ourselves? It’s all handled internally by login for us. Handy isn’t it?

Save the changes you made to logged_in_area.php. Your finished page should display like:


Step 6. Create Member Messages View

Create a new view: “applications/modules/site/views/member_messages.php“.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>untitled</title>
</head>
<body>
	<?php echo modules::run('login/cp');?>
	<h2><?php echo $first_name; ?>'s Messages</h2>
     <p>This could be where the messaging system gets displayed</p>
</body>
</html>

Write or paste the code above into the newly created file.

This view is pretty much just a clone of the members area to test that login holds on multiple pages. There is one difference: we fished some information from the login module’s membership_model. This is shown as the $first_name variable.

The point of getting user information here would be to pass it on to a module which would return a snippet with the user’s messages.

Save the changes you made to member_messages.php. Your finished page should display like:


Step 7. Create Member Profile View

Create a new view: “applications/modules/site/views/member_profile.php“.

	<?php echo modules::run('login/cp');?>
    <?php if( isset($notice) ): ?>
    <h2>Member Profile Pages</h2>
    <p><?php echo $notice; ?></p>
    <?php else: ?>
	<h2><?php echo $first_name; ?>'s Profile</h2>
     <p>Put all the good wholesome profile info here!</p>
	<?php endif; ?>

Write or paste the code above into the newly created file.

We have an if statement which detects whether a user was found or not. If not, we get brought to an error page stating we need an ID to view a profile.

Again, we retrieve the user information. Just like messages we would use this to retrieve the user’s friend list, latest blog entry, and activity feed, etc.

Save the changes you made to member_profile.php. Your finished page should display like:

What Happens When We Logoff?

Because we want the profile pages to be public, it should still display. Minus the user widget of course.

When logged in, and we go to profile without a third uri segment we see our own profile. Logded off, we will be shown the error below.

We should not be able to view the message or dashboard. When we check the messages page we are greeted with this:

We’re Done

That’s it! We have added more depth to our initial example and demonstrated the different ways to use HMVC.

  • Call modules::run() from a controller.
  • Echo modules::run() from a view to display a HTML snippet.
  • Load a model from another module.

I hope this has been an enlightening experience. HMVC is an extraordinary pattern which makes applications more robust. It is well worth the investment. Give it a try. I promise you won’t ever want to go back to vanilla MVC!

March 24 2010

18:05

MVC for Noobs

Model-View-Controller (MVC) is probably one of the most quoted patterns in the web programming world in recent years. Anyone currently working in anything related to web application development will have heard or read the acronym hundreds of times. Today, we’ll clarify what MVC means, and why it has become so popular.



Ancient History…

MVC is not a design pattern, it is an Architectural pattern that describes a way to structure our application and the responsibilities and interactions for each part in that structure.

It was first described in 1979 and, obviously, the context was a little bit different. The concept of web application did not exist. Tim Berners Lee sowed the seeds of World Wide Web in the early nineties and changed the world forever. The pattern we use today for web development is an adaptation of the original pattern.

The wild popularization of this structure for web applications is due to its inclusion in two development frameworks that have become immensely popular: Struts and Ruby on Rails. These two environments marked the way for the hundreds of frameworks created later.


MVC for Web Applications

The idea behind the Model-View-Controller architectural pattern is simple: we must have the following responsibilities clearly separated in our application:

The application is divided into these three main components, each one in charge of different tasks. Let’s see a detailed explanation and an example.

Controller

The Controller manages the user requests (received as HTTP GET or POST requests when the user clicks on GUI elements to perform actions). Its main function is to call and coordinate the necessary resources/objects needed to perform the user action. Usually the controller will call the appropriate model for the task and then selects the proper view.

Model

The Model is the data and the rules applying to that data, which represent concepts that the application manages. In any software system, everything is modeled as data that we handle in a certain way. What is a user, a message or a book for an application? Only data that must be handled according to specific rules (date can not be in the future, e-mail must have a specific format, name cannot be more than x characters long, etc).

The model gives the controller a data representation of whatever the user requested (a message, a list of books, a photo album, etc). This data model will be the same no matter how we may want to present it to the user, that’s why we can choose any available view to render it.

The model contains the most important part of our application logic, the logic that applies to the problem we are dealing with (a forum, a shop, a bank, etc). The controller contains a more internal-organizational logic for the application itself (more like housekeeping).

View

The View provides different ways to present the data received from the model. They may be templates where that data is filled. There may be several different views and the controller has to decide which one to use.

A web application is usually composed of a set of controllers, models and views. The controller may be structured as a main controller that receives all requests and calls specific controllers that handles actions for each case.


Let’s See an Example

Suppose we’re developing an online book store. The user can perform actions such as: view books, register, buy, add items to current order, create or delete books (if he is an administrator, etc.). Let’s see what happens when the user clicks on the fantasy category to view the titles we have available.

We will have a particular controller to handle all books-related actions (view, edit, create, etc). Let’s call it books_controller.php for this example. We will also have a model, for example book_model.php, handling data and logic related to the items in the shop. Finally we will have a series of views to present, for example, a list of books, a page to edit books, etc.

The following figure shows how the user request to view the fantasy books list is handled:

The controller (books_controller.php) receives the user request [1] as an HTTP GET or POST request (we can also have a central controller, for example index.php receiving it and then calling books_controller.php).

The controller examines the request and the parameters and calls the model (book_model.php) asking him to return the list of available fantasy books [2].

The model is responsible for getting that information from the database (or wherever it is stored) [3], apply filters or logic if necessary, and return the data representing the list of books [4].

The controller will use the appropriate view [5] to present these data to the user [6-7]. If the request came from a mobile phone, a view for mobile phones will be used, if the user has a particular skin selected, the corresponding view will be chosen, and so on.


What are the Advantages?

The most obvious advantage we gain using MVC is a clear separation of presentation (the interface with the user) and application logic.

Support for different types of users using different types of devices is a common problem these days. The interface presented must be different if the request came from a desktop computer or from a cell phone. The model returns exactly the same data, the only difference is that the controller will choose a different view to render them (we can think of a different template).

Apart from isolating the view from the business logic, the M-V-C separation reduces the complexity when designing large applications. The code is much more structured and therefore easier maintain, test and reuse.


Ok, but Why a Framework?

When you use a framework, the basic structure for MVC is already prepared and you just have to extend that structure, placing your files in the appropriate directory, to comply with the Model-View-Controller pattern. Also you get a lot of functionality already written and thoroughly tested.

Take cakePHP as an example MVC framework. Once you have it installed, you’ll see three main directories:

  • app/
  • cake/
  • vendors/

The app folder is where you place your files. It is your place to develop your part of the application.

The cake folder is where cakePHP has its files and where they have developed their part (main framework functionality).

The vendors folder is for third-party PHP libraries if needed.

Your working place (app directory) has the following structure:

  • app/
    • config/
    • controllers/
    • locale/
    • models/
    • plugins/
    • tests/
    • tmp/
    • vendors/
    • views/
    • webroot/

Now you have to put your controllers in the controllers directory, your models in the models directory and your views in… the views directory!

Once you get used to your framework, you’ll be able to know where to look for almost any piece of code you need to modify or create. This organization alone makes maintainability a lot easier.


Let’s Framework our Example

Since this tutorial is not intended to show you how to create an application using cakePHP, we’ll use it only to show example code for the model, view and controller components and comment on the benefits of using an MVC framework. The code is oversimplified and not suitable for real applications.

Remember we had a book store and a curious user who wants to see the complete list of books in the fantasy category. We said that the controller will be the one receiving the request and coordinating the necessary actions.

So, when the user clicks, the browser will be requesting this url:

 www.ourstore.com/books/list/fantasy

CakePHP likes to format URLs in the form /controller/action/param1/param2 , where action is the function to call within the controller. In the old classic url format it would be:

 www.ourstore.com/books_controller.php?action=list&category=fantasy

Controller

With the help of cakePHP framework, our controller will look something like this:


<?php

class BooksController extends AppController {

 function list($category) {

 $this->set('books', $this->Book->findAllByCategory($category));

 }

 function add() { ... ... }

 function delete() { ... ... }

 ... ... } ?>

Simple, isn’t it?. This controller will be saved as books_controller.php and placed in /app/controllers. It contains the list function, to perform the action in our example, but also other functions to perform other book-related actions (add a new book, delete a new book, etc).

The framework provides a lot of things for us and only one line is necessary to list the books. We have base classes with the basic controller behavior already defined, so we inherit from them (AppController which inherits from Controller).

All it has to do in the list action is call the model to get the data and then choose a view to present it to the user. Let’s explain how this is done.

this->Book is our Model, and this part:

 $this->Book->findAllByCategory($category) 

is telling the model to return the list of books in the selected category (we’ll see the model later).

The set method in the line:

 $this->set('books', $this->Book->findAllByCategory($category)); 

Is the controller way to pass data to the view. It sets the books variable to the data returned by the model and makes it accessible to the view.

Now we just have to render the view, but this will be done automatically by cakePHP if we want the default view. If we need any other view we just have to call it explicitly using the render method.

Model

The model is even more simple:


<?php

class Book extends AppModel { 

}

?>

Why empty? Because it inherits from a base class that provides necessary functionality and we have followed the CakePHP name conventions to allow the framework to do other tasks automatically. For example, cakePHP knows, based on names, that this model is used in BooksController and that it will access a database table called books.

With this declaration only we have a book model capable of reading, deleting or saving data from the database

The code will will be saved as book.php and placed in /app/models.

View

All we have to do now is creating a view (at least one) for the list action. The view will have the HTML code and a few (as few as possible) PHP lines to loop through the books array provided by the model.


<table> <tr> <th>Title</th> <th>Author</th> <th>Price</th> </tr>

<?php foreach ($books as $book): ?> <tr> <td> <?php echo $book['Book']['title']; ?> </td> <td> <?php echo $book['Book']['author']; ?> </td> <td> <?php echo $book['Book']['price']; ?> </td> </tr> <?php endforeach; ?>

</table>

As we can see, the view doesn’t produce a complete page, just an HTML fragment (a table in this case). This is because CakePHP provides another way to define the layout of the page, and the views are inserted into that layout. The framework also provides us with some helper objects to make common task easy when creating these HTML excerpts (insert forms, links, Ajax or JavaScript).

We make this the default view saving it as list.ctp ( list is the name of the action and ctp means cake template) and placing it in /app/views/books (inside books because these are views for books controller actions).

And this completes the three components with the help of CakePHP framework!


Conclusion

We have learned what is probably the most commonly used architectural pattern today. We must be aware though that when we talk about patterns in the programming world, we are talking about flexible frames, to be tailored to the particular problem at hand. We will find implementations introducing variations on the structure we have seen, but the important thing is that, in the end, the pattern helps us gain a clear division between responsibilities and better maintainability, code-reuse, and testing.

We have also seen the advantages of using an MVC framework that provides us with a basic MVC skeleton and a lot of functionality, improving our productivity and making the development process easier. Thanks for reading!


Tags: Other basix mvc

November 06 2009

10:01

Book Review: Zend Framework 1.8 Web Application Development

If you are looking into buying a book to learn about Zend Framework, chances are you are already set on using Zend Framework to build your next project. Today, we will be looking at Zend Framework 1.8 Web Application Development by Keith Pope, published by Packt Publishing.

First of all, you’ll notice that this book is based on Zend Framework version 1.8, and as of writing this review, the latest stable release of Zend Framework is 1.9.4. This is not an issue, because 1.9, even though it brings new features such as PHP 5.3 compatibility and RESTful web services, does not change its structure or any part of the system that might have impact on your learning.

Flow of the Book

The flow of this book is heavily inspired by the famous Ruby on Rails book, Agile Web Development with Rails, where the author invites you to join the process of building a demo application, which in both cases is a shopping cart system. Judging by the feedback of the Rails book, most people feel quite comfortable learning a framework this way, some don’t. I guess if you are not a fan of following a defined learning structure, this book probably isn’t for you.

Short but Sweet

It is a relatively short book, with only around 350 pages. As a result, this book expects you to be comfortable with working with PHP 5 and have a solid grasp of Object-Oriented Programming. If you aren’t already familiar with PHP, or PHP 5’s OOP features, I highly recommend you to polish up the said skills.

MVC Still Rules

The first two chapters of the book focus on the MVC (Model-View-Controller) pattern. As the author mentions at the start of the book, Zend Framework is a loosely coupled framework; it does not enforce the MVC principle. However, given the popularity of MVC within the web development community, it is definitely worth while to learn how to write an application in MVC. Chapter one explains the basics of MVC whilst chapter two explains the request/route/dispatcher/response family. These two chapters will set up the foundation nicely for you and get you to understand the basic structure of a Zend Framework powered MVC application.

Adventure of the Store-Front App

Chapter three to nine contain the actual ‘adventure’ where you as the reader will be riding along with the author on the journey of creating a store-front/shopping-cart application. During the process, the author tells you not only what to do, but also why to do them. A good example is the ‘fat controller skinny model’ vs ’skinny controller vs fat model’ comparison, the book illustrates each and tells you why you should stick with the latter.

Chapter ten wraps up the store-front application with some more common tasks such as bootstrapping modules and sharing common application elements.

Code Optimization, Caching and Testing

Chapter eleven touches on a very practical topic: code optimization and caching. This is especially beneficial if you’re to run a large volume web application or if you have limited hardware resources. Pay special attention to the Zend_Cache section as the author tells you how to integrate it effectively in your application in order to achieve the best result.

The last chapter, chapter twelve, introduces you to Zend_Test, a testing framework that utilizes PHPUnit.

Verdict

To wrap the review up, I think this is an excellent book on Zend Framework provided you:

  • already have a good understanding of PHP;
  • already have a good understanding of OOP;
  • can follow the rather forceful learning flow;
  • know how to learn with initiative (e.g. do your own research!).

This book sits well in the market, as it aims primarily at web professionals who most likely are already experienced with PHP and perhaps some other PHP frameworks, and don’t have time to read books with 1000’s of pages.

You may purchase this book via Packt Publishing’s website.



Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.
(PRO)
No Soup for you

Don't be the product, buy the product!

close
YES, I want to SOUP ●UP for ...