cakePHP2インストール

cakephp-2.8.4をgitでworkspaceにDLする。

$ cd workspace
$ git clone -b 2.x git://github.com/cakephp/cakephp.git
$ chmod 0777 -R ./cakephp/app/tmp/

今回apacheの公開ディレクトリが workspace/htdocs/なので以下の設定が必要。

$ mv ./cakephp/app/webroot ./htdocs

/cakephp/app/webroot/index.php

...
if (!defined('ROOT')) {
	//define('ROOT', dirname(dirname(dirname(__FILE__))));
	// ↓以下に変更↓
	define('ROOT', dirname(dirname(__FILE__)) . DS . 'cakephp');
}
...
if (!defined('APP_DIR')) {
	//define('APP_DIR', basename(dirname(dirname(__FILE__))));
	// ↓以下に変更↓
	define('APP_DIR', 'app');
}
...

SQLite3の設定

ここでは記事マスタ(mas_entries)とカテゴリ(met_categories)という2つのテーブルを想定する。
それぞれ主キー(entry_id, category_id)と登録日時(created), 更新日時(modified), 論理削除日時(deleted)をもつ。

$ cd workspace
$ mkdir sqlite3
$ vi sqlite3/create-table.sql

create-table.sql

CREATE TABLE `mas_entries` (
  `entry_id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `created` datetime NULL,
  `modified` datetime NULL,
  `deleted` datetime NULL,
  `title` VARCHAR(50),
  `content` VARCHAR(1000),
  `category_id` INTEGER
);

CREATE TABLE `met_categories` (
  `category_id` INTEGER PRIMARY KEY AUTOINCREMENT,
  `created` datetime NULL,
  `modified` datetime NULL,
  `deleted` datetime NULL,
  `name` VARCHAR(50),
  `display_order` INTEGER
);

BEGIN TRANSACTION;
INSERT INTO `met_categories` (`created`, `modified`, `name`, `display_order`) VALUES(datetime('now', 'localtime'), datetime('now', 'localtime'), 'ニュース', 1);
INSERT INTO `met_categories` (`created`, `modified`, `name`, `display_order`) VALUES(datetime('now', 'localtime'), datetime('now', 'localtime'), '商品情報', 2);
INSERT INTO `met_categories` (`created`, `modified`, `name`, `display_order`) VALUES(datetime('now', 'localtime'), datetime('now', 'localtime'), 'IR情報', 3);
COMMIT;
$ sqlite3 sqlite3/rest-test.sqlite3 < sqlite3/create-tables.sql
$ chmod 0777 sqlite3
$ chmod 0666 sqlite3/rest-test.sqlite3
$ mv cakephp/app/Config/database.php.default cakephp/app/Config/database.php
$ vi cakephp/app/Config/database.php

cakephp/app/Config/database.php DBの設定を以下のように変更。

...
	public $default = array(
		'datasource' => 'Database/Sqlite',
		'persistent' => false,
		'database' => '/home/test/workspace/sqlite3/rest-test.sqlite3',
		'prefix' => '',
		'encoding' => 'utf8',
	);
...

RESTの設定

cakephp/app/Config/routes.php の require CAKE . 'Config' . DS . 'routes.php'; より前にRESTの設定を記述する。

/**
 * REST config
 */
	Router::mapResources('entries');
	Router::mapResources('categories');
	Router::parseExtensions();

cakephp/app/Model にモデルファイル追加。
cakephp/app/Model/Entry.php

<?php
class Entry extends AppModel {
	/**
	 * モデル名
	 */
	public $name = 'Entry';
	/**
	 * 使用テーブル
	 */
	public $useTable = 'mas_entries';
	/**
	 * 主キー
	 */
	public $primaryKey = 'entry_id';
	/**
	 * list取得時表示フィールド
	 */
	public $displayField = 'title';
	/**
	 * リレーション
	 */
	public $belongsTo = [
		'Category' => [
			'className' => 'Category',
			'foreignKey' => 'category_id',
		],
	];
}

cakephp/app/Model/Category.php

<?php
class Category extends AppModel {
	/**
	 * モデル名
	 */
	public $name = 'Category';
	/**
	 * 使用テーブル
	 */
	public $useTable = 'met_categories';
	/**
	 * 主キー
	 */
	public $primaryKey = 'category_id';
	/**
	 * list取得時表示フィールド
	 */
	public $displayField = 'name';
}

cakephp/app/Controller にコントローラファイル追加。
cakephp/app/Controller/RestController.php

<?php
class RestController extends AppController {
	/**
	 * コンポーネント
	 */
	public $components = ['RequestHandler'];
	/**
	 * メインモデル
	 */
	public $mainModel;
	/**
	 * 一覧表示
	 */
	public function index() {
		$mainModel = $this->mainModel;
		$all = $this->$mainModel->find('all');
		$this->set([
			'all' => $all,
			'_serialize' => ['all']
		]);
	}
	/**
	 * 詳細表示
	 */
	public function view($id) {
		$mainModel = $this->mainModel;
		$conditions = [
			[$this->$mainModel->name . '.' . $this->$mainModel->primaryKey => $id]
		];
		$first = $this->$mainModel->find('first', compact('conditions'));
		$this->set([
			'first' => $first,
			'_serialize' => ['first']
		]);
	}
	/**
	 * 登録
	 */
	public function add() {
		$mainModel = $this->mainModel;
		$this->$mainModel->create();
		if ($this->$mainModel->save($this->request->data)) {
			$message = 'Saved';
		} else {
			$message = 'Error';
		}
		$this->set([
			'message' => $message,
			'_serialize' => ['message']
		]);
	}
	/**
	 * 更新
	 */
	public function edit($id) {
		$mainModel = $this->mainModel;
		$this->$mainModel->id = $id;
		if ($this->$mainModel->save($this->request->data)) {
			$message = 'Saved';
		} else {
			$message = 'Error';
		}
		$this->set([
			'message' => $message,
			'_serialize' => ['message']
		]);
	}
	/**
	 * 論理削除
	 */
	public function delete($id) {
		$mainModel = $this->mainModel;
		$conditions = [
			[$this->$mainModel->name . '.' . $this->$mainModel->primaryKey => $id]
		];
		$message = 'Error';
		if ($first = $this->$mainModel->find('first', compact('conditions'))) {
			$first[$this->$mainModel->name]['deleted'] = date("Y-m-d H:i:s");
			if ($this->$mainModel->save($first)) {
				$message = 'Deleted';
			}
		}
		$this->set([
			'message' => $message,
			'_serialize' => ['message']
		]);
	}
}

cakephp/app/Controller/EntriesController.php

<?php
App::uses('RestController', 'Controller');
class EntriesController extends RestController {
	/**
	 * 使用モデル
	 */
	public $uses = ['Entry'];
	/**
	 * メインモデル
	 */
	public $mainModel = 'Entry';
}

cakephp/app/Controller/CategoriesController.php

<?php
App::uses('RestController', 'Controller');
class CategoriesController extends RestController {
	/**
	 * 使用モデル
	 */
	public $uses = ['Category'];
	/**
	 * メインモデル
	 */
	public $mainModel = 'Category';
}

Backboneのインストール

workspace/htdocs/js/lib/ を作成し,
・backbone-min.js
・jquery.min.js
・require.js
・text.js
・underscore-min.js
を設置。それぞれのファイルはWEB上から取得。
workspace/htdocs/app を作成し,以下のディレクトリ構造を作成する。
app/
├ Collection/
├ Config/
├ Model/
├ Template/
└ View/
次に設定ファイルを作成。
workspace/htdocs/app/Config/require_config.js

var require = {
	baseUrl: '/app/',
	paths: {
		'jquery': '/js/lib/jquery.min',
		'underscore': '/js/lib/underscore-min',
		'backbone': '/js/lib/backbone-min',
		'text': '/js/lib/text',
	},
	shim: {
		'backbone': {
			deps: ['jquery', 'underscore'],
			exports: 'Backbone'
		},
		'text': {
			deps: ['backbone'],
			exports: 'Text'
		}
	}
};

メインスクリプトを設置。
workspace/htdocs/app/main.js

define(function(require){
	// ライブラリ
	var $ = require('jquery');
	var _ = require('underscore');
	var Backbone = require('backbone');

});

htmlファイルを設置。
workspace/htdocs/entries.html



最低限のインストールは終了。

BackboneのModel,Collectionの作成

workspace/htdocs/app/Model/AppModel.js

define(function(require){
	var Backbone = require('backbone');
	return Backbone.Model.extend({
		/**
		 * URL
		 */
		url: function() {
			if (this.id) {
				return this.urlRoot + '/' + this.id + '.json';
			} else {
				return this.urlRoot + '.json';
			}
		},
		/**
		 * parse
		 */
		parse: function(response) {
			var data = response;
			if (typeof(data.first) !== 'undefined') {
				for (var i in data.first) {
					data[i] = data.first[i];
				}
				delete(data.first);
			}
			if (typeof(data[this.name]) !== 'undefined') {
				for (var i in data[this.name]) {
					data[i] = data[this.name][i];
				}
				delete(data[this.name]);
			}
			return data;
		}
	});
});

workspace/htdocs/app/Model/Entry.js

define(function(require){
	var Backbone = require('backbone');
	var AppModel = require('Model/AppModel');
	return AppModel.extend({
		/**
		 * モデル名
		 */
		name: 'Entry',
		/**
		 * URL ROOT
		 */
		urlRoot : '/entries',
		/**
		 * idAttribute
		 */
		idAttribute: 'entry_id'
	});
});

workspace/htdocs/app/Model/Category.js

define(function(require){
	var Backbone = require('backbone');
	var AppModel = require('Model/AppModel');
	return AppModel.extend({
		/**
		 * モデル名
		 */
		name: 'Category',
		/**
		 * URL ROOT
		 */
		urlRoot : '/categories',
		/**
		 * idAttribute
		 */
		idAttribute: 'category_id'
	});
});

workspace/htdocs/app/Collection/AppCollection.js

define(function(require){
	var Backbone = require('backbone');
	return Backbone.Collection.extend({
		/**
		 * parse
		 */
		parse: function(response) {
			if (typeof(response.all) !== 'undefined') {
				return response.all;
			} else {
				return response;
			}
		}
	});
});

workspace/htdocs/app/Collection/Entries.js

define(function(require){
	var Backbone = require('backbone');
	var AppCollection = require('Collection/AppCollection');
	var Entry = require('Model/Entry');
	return AppCollection.extend({
		/**
		 * コレクション名
		 */
		name: 'Entries',
		/**
		 * モデル
		 */
		model: Entry,
		/**
		 * URL
		 */
		url: '/entries.json'
	});
});

workspace/htdocs/app/Collection/Categories.js

define(function(require){
	var Backbone = require('backbone');
	var AppCollection = require('Collection/AppCollection');
	var Category = require('Model/Category');
	return AppCollection.extend({
		/**
		 * コレクション名
		 */
		name: 'Categories',
		/**
		 * モデル
		 */
		model: Category,
		/**
		 * URL
		 */
		url: '/categories.json'
	});
});

準備完了。

BackboneでRESTテスト

先ほど作ったworkspace/htdocs/app/main.jsを修正しながらテスト

1. 一覧取得テスト

	var Categories = require('Collection/Categories');
	var categories = new Categories();
	categories.fetch({
		success: function(categories) {
			console.log(categories);
		}
	});

2. 登録テスト

	var Entry = require('Model/Entry');
	var entry = new Entry();
	entry.set({
		title: 'ニューステスト',
		content: 'これは初めての投稿です。',
		category_id: 1
	});
	entry.save();

3. 1件取得テスト

	var Entry = require('Model/Entry');
	var entry = new Entry();
	entry.id = 1;
	entry.fetch({
		success: function() {
			console.log(entry);
		}
	});

4. 更新テスト

	var Entry = require('Model/Entry');
	var entry = new Entry();
	entry.set({
		entry_id: 1,
		title: 'これは書き換えテスト'
	});
	entry.save();

5. 削除テスト

	var Entry = require('Model/Entry');
	var entry = new Entry();
	entry.id = 1;
	entry.fetch({success: function(){
		entry.destroy();
	}});