Skip to content

Using Diamond : Website

Jacob Jensen edited this page May 22, 2016 · 10 revisions

To use Diamond for a website you must have dub installed.

If it's the first time you use Diamond, then it's recommended to follow the guide below.

If you're already familiar with Diamond then an empty project corresponding the below can be found here:

https://github.com/bausshf/DiamondEmptySite/

Just download the project as zip.

Create a new folder for your project. Ex. diamondproject

Create the following folders and files within it. (Don't worry about content right now.)

  • \diamondproject
    • \config
      • web-build.json
    • \controllers
      • package.d
      • homecontroller.d
    • \core
      • web.d
    • \models
      • package.d
      • home.d
    • \public
    • \views
      • layout.dd
      • errors.dd
      • home.dd
    • dub.json
    • web-runtime.json

Below is all the content for the files. Just copy-paste it into the files. Explanations of them are right below.

dub.json

{
	"name": "diamondproject",
	"description": "A diamond website project",
	"authors": ["Jacob Jensen"],
	"homepage": "http://mydiamondwebsiteproject.com/",
	"license": "http://mydiamondwebsiteproject.com/license",
	"dependencies": {
		"vibe-d": "~>0.7.28",
		"diamond": "~>0.2.32"
	},
	"versions": ["VibeDefaultMain", "WebServer"],
	"sourcePaths": ["core", "models", "controllers"],
	"stringImportPaths": ["views", "config"],
	"targetType": "executable"
}

name is the name of the project.

description is the description of the project.

authors is the authors of the project.

homepage is the homepage of the project.

license is the license of the project.

dependencies is the dependencies of the project. A webserver using Diamond has a dependency to vibe.d

versions are all versions to compile with. For a webserver you must compile with "WebServer"

sourcePaths are all paths that dub will look for code. By defualt Diamond only uses core, models and controllers.

stringImportPaths are all paths dub will look for string imports. By default Diamond only uses views and config.

targetType are the type of the output. For a Diamond project, it'll typically be executable.

web-runtime.json

{
  "bindAddresses": [
	"::1",
	"127.0.0.1"
  ],
  "port": 8080,
  "defaultHeaders": {
	"Content-Type": "text/html; charset=UTF-8",
	"Server": "vibe.d - Diamond MVC/Template Framework"
  }
}

bindAddresses are all addresses that should bound to.

port is the port that should be bound to.

defaultHeaders are all default headers to append to the responses headers. (Note these are not appended to the static files headers.)

The web-runtime.json file must be placed in the same folder as the compiled executable.

config\web-build.json

{
  "name": "diamondproject",
  "views":{
	"layout": "layout.dd",
	"errors": "errors.dd",
	"home": "home.dd"
  },
  "homeRoute": "home",
  "staticFileRoute": "public"
}

name is the name of the project.

views are all the views associated with the project. Note: the final class of a view can be retrieved with the type view_VIEWNAMEHERE

homeRoute is the route used to get to the home page. It's an alternative route to "/"

staticFileRoute is a route used to get to the static files. (The public folder)

controllers\package.d

module controllers;

public {
  import controllers.homecontroller;
}

You must import all controller modules within this file. Otherwise Diamond will be unable to locate your controllers.

controllers\homecontroller.d

/**
* Module for the home controller.
*/
module controllers.homecontroller;

import vibe.d;

import diamond.controllers;

import models.home;

/// The controller for the home view.
final class HomeController(TView) : Controller!TView {
  public:
  final:
  /**
  * Creates a new instance of the home controller.
  * Params:
  *   view =  The view assocaited with the controller.
  */
  this(TView view) {
	super(view);

	mapDefault(&home);
  }

  private:
  /// Route: / | /home
  Status home() {
	view.model = new Home("Home");

	return Status.success;
  }
}

The constructor of a controller should be used to map actions. For more information view the Diamond documentation.

All controller methods must return "Status" which indicates the status of the call.

Controllers are automatically instantiated internally by Diamond. A controller can be used by multiple views, however template constraints can be placed upon the TView template argument. TView will always correspond to the view implementing the controller.

core\web.d

module web;

import vibe.d;

import diamondapp; // To retrieve views ...

import diamond.configurations.websettings;

class DiamondProjectSettings : WebSettings {
	public:
	this() {
		super();
	}
	
	override bool onBeforeRequest(HTTPServerRequest request, HTTPServerResponse response) {
		return true;
	}
	
	override void onAfterRequest(HTTPServerRequest request, HTTPServerResponse response) {
		// ...
	}
	
	override void onHttpError(HTTPServerRequest request, HTTPServerResponse response, HTTPServerErrorInfo error) {
		auto page = cast(view_errors)getView(request, response, ["errors"], false);

		foreach (headerKey,headerValue; serverSettings.defaultHeaders) {
			response.headers[headerKey] = headerValue;
		}

		response.statusCode = error.code;
		response.bodyWriter.write(page.generate(error));
	}
}

shared static this() {
	WebSettings.initialize(new DiamondProjectSettings);
}

The web module should be used to declare internal configurations or handle specific "events".

You can use onBeforeRequest to process requests before they start handling stuff such as views etc.

You can use onAfterRequest to process sucessfully handled requests before the response is sent.

You can use onHttpError to handle errors. This is typically used to generate the error view.

models\package.d

module models;

public {
  import models.home;
}

Just like controllers, you must declare all models in this file. Otherwise Diamond won't be able to locate the models. This only counts for models that views use.

models\home.d

/**
* Module for the home model.
*/
module models.home;

/// The model for the home view.
class Home {
  private:
  /// The title.
  string _title;

  public:
  /**
  * Creates a new instance of the home model.
  * Params:
  *   title = The title of the home view.
  */
  this(string title) {
	_title = title;
  }

  @property {
	/// Gets the title.
	auto title() { return _title; }
  }
}

public

The public folder is the folder where static files are placed. Static files are files such as images, css, javascript etc. that the browser should always be able to retrieve directly.

views\layout.dd

@<doctype>
<html>
<head>
  <title>@<title></title>
</head>
<body>
  @<view>
</body>
</html>

doctype is a default placeholder for the default document-type provided by Diamond.

title is the placeholder for the title.

view is the placeholder for the view that uses this page as a layout page.

views\errors.dd

@[
  layout:
	layout
---
  model:
	HTTPServerErrorInfo
---
  placeHolders:
	["title" : "Error - " ~ to!string(model.code)]
]
<b>Message:</b> @=model.code;

@:if (model.message && model.message.length) {
	&nbsp;- @=model.message;
}

@:if (model.code != 404 && model.code > 299 && model.exception) {
	<br>
	<b>Exception:</b> @=model.exception.toString()
		.replace("\r", "")
		.replace("\n", "<br>")
		.replace(" at ", " at<br>")
		.replace(" in ", " in<br>");
}

views\home.dd

@*The home view*
@[
  layout:
	layout
---
  model:
	Home
---
  controller:
	HomeController
---
  route:
	home
---
  placeHolders:
	["title" : model.title]
]
<p> Hello World!</p>

Notice for views

The first block you encounter is the metadata block. The metadata block is used to declare metadata configurations for the view. It's entirely optional to have a metadata block and usually not declared for partial views. Unless they need static place holders. All members of the metadata block are optional. Each member must be separated by a line of "---"

layout is the name of the view to use as a layout page.

model is the name of the model to use for the view.

controller is the name of the controller to use for the view.

route is the name of the route to use for the view.

placeHolders is an associative array of place-holders. It supports the full associative array syntax in D as it translates it directly as such.

Building

To compile the project simply use the following dub command

dub build