インストール
まずは本体のインストール。
sudo composer create-project --prefer-dist cakephp/app myApp
無事終了したら、パーミッションを変えておく(OSXのみ)
sudo chown -R mymac:staff myApp
ここで一旦 .gitignore を編集して、 コミットしておく。
tmpとlogsをコメントアウトして、自分の環境でよくあるやつを入れておく。
cd myApp
vim .gitignore
/vendor/*
/config/app.php
#/tmp/*
#/logs/*
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
*.swp
*.un~
*~
*BAK
あとはいつものgit処理で。
git init
git add .
git commit -m "Initialize repository"
git remote add origin https://github.com/xxxxxxx/myApp.git
git push -u origin master
pushしたらtmpとlogsのコメントアウトを外しておく。
/tmp/*
/logs/*
一旦サーバー起動してみて動作確認。
bin/cake server
Composerの設定
composer.jsonを編集する。
suggest に入っている phpunit と codesniffer を require-dev に移す。
ついでに heroku も設定しておく。
あと、PDF生成もするかもしれないので tcpdf も一応いれておく。
"require": {
"tecnick.com/tcpdf": "*"
},
"require-dev": {
"phpunit/phpunit": "*",
"cakephp/cakephp-codesniffer": "*",
"heroku/heroku-buildpack-php": "*"
},
composerのアップデートをかける
sudo composer update
無事入ったら、phpunitの動作確認。
vendor/bin/phpunit
PHPUnit 4.8.6 by Sebastian Bergmann and contributors.
Time: 297 ms, Memory: 7.25Mb
No tests executed!
データベース設定
この時点で(もっとそれより早くて構わないが)データベースを準備しておく。
テスト用のDBも作っておく。
CREATE DATABASE myapp_db DEFAULT CHARACTER SET utf8;
CREATE DATABASE test_myapp_db DEFAULT CHARACTER SET utf8;
config/app.php を編集してDB接続情報を入れておく。
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'root',
'password' => 'password',
'database' => 'myapp_db',
'encoding' => 'utf8',
//'timezone' => 'UTC',
'cacheMetadata' => true,
],
/**
* The test connection is used during the test suite.
*/
'test' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'root',
'password' => 'password',
'database' => 'test_myapp_db',
'encoding' => 'utf8',
//'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
],
],
migration
migration を使って、一つのテーブルを軽く作る。(ここでは例としてArticlesテーブルを作っている)
bin/cake bake migration CreateArticles name:string created modified
config/Migrations 以下に migrationファイルが生成されるので、編集して、その他のカラム設定を追加し、テーブル定義を完成させる。
vim config/Migrations/20150826024512_create_articles.php
以下のURLを参考に。
http://book.cakephp.org/3.0/en/migrations.html
<?php
use Phinx\Migration\AbstractMigration;
class CreateArticles extends AbstractMigration
{
/**
* Change Method.
*
* More information on this method is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-change-method
* @return void
*/
public function change()
{
$table = $this->table('articles');
$table->addColumn('name', 'string', [
'default' => null,
'limit' => 255,
'null' => false,
]);
$table->addColumn('age', 'integer', [
'default' => null,
'limit' => 11,
'null' => true,
]);
$table->addColumn('posted_date', 'date', [
'default' => null,
'limit' => null,
'null' => true,
]);
$table->addColumn('created', 'datetime', [
'default' => null,
'null' => false,
]);
$table->addColumn('modified', 'datetime', [
'default' => null,
'null' => false,
]);
$table->create();
}
}
ファイルを保存したら、以下のコマンドでDBにテーブルを生成。
bin/cake migrations migrate
注)このやり方だと例えばmysql のview tableなんかを使っているとうまくいかない。
結局はMySQLに接続して直接操作した方がよいのかもしれない。
参考:http://qiita.com/yutaono/items/34bdc9383ce5870e7b8b#3-3
terminalから直接mysql接続できる。
続いて、以下のコマンドで、articlesテーブルのモデルをbakeコマンドで自動生成。
(するとtestsディレクトリ以下にテストケースとフィクスチャーも自動生成される)
bin/cake bake model Articles
再びテストしてみる。(以下でテスト結果が出るはず)
vendor/bin/phpunit
PHPUnit 4.8.6 by Sebastian Bergmann and contributors.
II
Time: 425 ms, Memory: 9.75Mb
OK, but incomplete, skipped, or risky tests!
Tests: 2, Assertions: 0, Incomplete: 2.
コーディング規約
さらにコードスニッッファーの設定をする。
以下のコマンドを打つ。
sudo vendor/bin/phpcs --config-set installed_paths vendor/cakephp/cakephp-codesniffer
試してみる。
vendor/bin/phpcs --standard=CakePHP src/
エラーが出る(^^;
FILE: .../myApp/src/Model/Table/ArticlesTable.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
33 | ERROR | Expected 0 blank lines before closing function brace; 1
| | found
----------------------------------------------------------------------
Time: 398ms; Memory: 7.25Mb
直したきゃ直す。
vimの人は.vimrcを直しておくとよい。
set autoindent
set expandtab
set ts=4
set sw=4
npm install
npmを使ってjs関係の設定をする。
npm init
いろいろ質問されるのでエンターキーを押す。
引き続き、以下をだーっとインストールする。
npm install jquery jquery-ui --save-dev
npm install bootstrap --save-dev
npm install grunt --save-dev
npm install grunt-phpunit --save-dev
npm install grunt-phpcs --save-dev
npm install time-grunt --save-dev
npm install grunt-browserify --save-dev
npm install grunt-contrib-watch --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-notify --save-dev
直下にpackage.jsonが作られるので編集して
vim package.json
以下を追加。
"browser": {
"jquery": "./node_modules/jquery/dist/jquery.js",
"bootstrap": "./node_modules/bootstrap/dist/js/bootstrap.js",
"jquery-ui": "./node_modules/jquery-ui/jquery-ui.js"
}
gruntの設定
自分で直下にGruntfile.jsを作成する。
vim Gruntfile.js
module.exports = function(grunt) {
require('time-grunt')(grunt);
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
phpunit: {
classes: {
dir: 'tests/TestCase/'
},
options: {
bin: 'vendor/bin/phpunit',
bootstrap: 'tests/bootstrap.php',
colors: true
}
},
phpcs: {
application: {
src: ['src/**/*.php']
},
options: {
bin: 'vendor/bin/phpcs',
standard: 'CakePHP'
}
},
browserify : {
dist : {
src : 'src/Scripts/main.js',
dest : 'webroot/js/build.js'
}
},
uglify: {
my_target: {
options: {
sourceMap: true
},
files: {
'webroot/js/build.min.js': ['webroot/js/build.js']
}
}
},
watch: {
phpcs: {
files: ['src/**/*.php'],
tasks: ['phpcs'],
options: {
spawn: false,
},
},
browserify: {
files: ['src/Scripts/**/*.js'],
tasks: ['browserify', 'notify:browserify'],
options: {
spawn: false,
},
},
uglify: {
files: ['src/Scripts/**/*.js'],
tasks: ['uglify', 'notify:uglify'],
options: {
spawn: false,
},
},
},
notify: {
browserify: {
options: {
message: 'Browserify finished running',
}
},
uglify: {
options: {
message: 'Uglify finished running'
}
}
}
});
grunt.loadNpmTasks('grunt-notify');
grunt.loadNpmTasks('grunt-phpunit');
grunt.loadNpmTasks('grunt-phpcs');
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['watch']);
grunt.registerTask('js', ['browserify', 'uglify']);
};
notify とかは完全に好みなので通知なんていらないって人は入れる必要ない。何をwatchするのかもその人の自由。
ちょっとここで動くかどうか確認。
grunt phpunit
jsの雛形
src/Scripts というフォルダーを作って、その中にメインのjsを作成する。
jqueryとbootstrapとdatepickerを読み込む。
mkdir src/Scripts
vim src/Scripts/main.js
(function(){
'use strict';
window.jQuery = window.$ = require('jquery');
require('bootstrap');
require('jquery-ui/datepicker');
var message = 'Hello App';
console.log(message);
$(".datepicker").datepicker({
dateFormat: "yy-mm-dd"
});
$("#myModal").on('shown.bs.modal', function (e) {
$(".datepicker").datepicker({
dateFormat: "yy-mm-dd"
});
})
$("#myModal").on('hidden.bs.modal', function (e) {
$(this).removeData();
});
})();
grunt が動くかどうか確認する。
grunt js
webroot/js/build.min.js が出来ているはずなので、レイアウトから読み込むようにしておく。
とりあえず /body の直上。
<?= $this->Html->script('build.min') ?>
</body>
</html>
ついでにjquery-uiのcssを webroot/css 以下にコピーしておく。
cssは node_modules/jquery-ui/themes 以下にテーマ別においてあるので好きな物を選んでコピー。
レイアウトに以下追加。
<?= $this->Html->css('jquery-ui.min.css') ?>
コミット、他のメンバーの設定
.gitignoreに追加する。
/node_modules/*
/webroot/files/*
add して commit して pushする。
git add .
git commit -m "Improve project file"
git push origin master
他の開発メンバーは、
git clone https://github.com/xxxxxxxxx/myApp.git
cd myApp/
sudo composer install
sudo vendor/bin/phpcs --config-set installed_paths vendor/cakephp/cakephp-codesniffer
npm install
データベースの設定も忘れずに。
vim config/app.php
bakeで画面作り
見る画面がないのも寂しいのでbakeで作っておく。
bin/cake bake controller Articles
ビューも
bin/cake bake template Articles
一応確認。
bin/cake server
heroku設定
で、herokuの準備。
直下にProcfileを作る。
web: vendor/bin/heroku-php-apache2 webroot/
bootstrap.phpを編集。76行目あたりに以下を追加。
if (isset($_ENV['CAKE_ENV'])) {
Configure::load('app_' . $_ENV['CAKE_ENV'], 'default');
}
さらに、DebugKitのところを編集
if (Configure::read('debug') && !isset($_ENV['CAKE_ENV'])) {
Plugin::load('DebugKit', ['bootstrap' => true]);
}
app_heroku.phpを作成する。
<?php
$db = parse_url(env('CLEARDB_DATABASE_URL'));
return [
'debug' => false,
'Security' => [
'salt' => env('SALT'),
],
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => $db['host'],
'username' => $db['user'],
'password' => $db['pass'],
'database' => substr($db['path'], 1),
'encoding' => 'utf8',
//'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
],
],
'EmailTransport' => [
'default' => [
'className' => 'Smtp',
// The following keys are used in SMTP transports
'host' => 'ssl://' . $smtp['host'],
'port' => $smtp['port'],
'timeout' => 30,
'username' => $smtp['user'],
'password' => $smtp['pass'],
'client' => null,
'tls' => null,
],
],
'Log' => [
'debug' => [
'className' => 'Cake\Log\Engine\ConsoleLog',
'stream' => 'php://stdout',
'levels' => ['notice', 'info', 'debug'],
],
'error' => [
'className' => 'Cake\Log\Engine\ConsoleLog',
'stream' => 'php://stderr',
'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
],
],
];
heroku操作
で、heroku で作業。
heroku login
メールアドレスとパスワードを入れると、
Authentication successful.
になるはず。
引き続き、
heroku create
で、新しくアプリが作られる。
さらに、CakePHP用の環境変数設定。
heroku config:add CAKE_ENV="heroku"
SALT設定
heroku config:add SALT="123456789123456"
SMTPサーバーの設定
heroku config:add SMTP_SERVER="smtp://username:password@smtp.mail.hoge.jp:465"
ビルドパックをphpに設定。(これをやらないとnodejsになってしまう)
heroku buildpacks:set https://github.com/heroku/heroku-buildpack-php
herokuにプッシュ。
git push heroku master
データベースを使う。
heroku addons:create cleardb
シェルを起動して、
heroku run bash
マイグレ
bin/cake migrations migrate
マイグレを使わない場合は、
heroku config
と打つと、環境変数と共に、以下のような、
CLEARDB_DATABASE_URL: mysql://b1234567890abc:12345678@aa-bbbb-cccc-dddd-01.cleardb.net/heroku_b123456789abcde?reconnect=true
接続情報が出るので、これを分解してmysqlで接続する。いや、別にそのまんまです。
mysql -u b1234567890abc -p -h aa-bbbb-cccc-dddd-01.cleardb.net heroku_b123456789abcde
接続できたら、普通に、create database して、create table して、とやる。
DBは以上。
ブラウザ起動!
heroku open
これで動くはず。
BASIC認証
とりあえずBASIC認証かけといてって必ず言われるので、以下をAppController.phpに仕込む。
use Cake\Event\Event;
class AppController extends Controller
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->autoRender = false;
$loginId = 'admin';
$password = 'pass';
if (isset($_SERVER['PHP_AUTH_USER'])) {
if (! ($_SERVER['PHP_AUTH_USER'] === $loginId && $_SERVER['PHP_AUTH_PW'] === $password)) {
$this->_basicUnauthorized();
}
} else {
$this->_basicUnauthorized();
}
$this->autoRender = true;
}
protected function _basicUnauthorized()
{
header('WWW-Authenticate: Basic realm="Please enter your ID and password"');
header('HTTP/1.0 401 Unauthorized');
die("Authorization Required");
}
}
bootstrap設定
とりあえずプラグインでテーマ設定する。
bin/cake bake plugin bootstrap
(ここでbootstrapというのは自分で決めたプラグインの名前である)
フォルダー plugins/Bootstrap/src が作成されるので、そこにさらに自分でフォルダーを作る。
mkdir -p plugins/Bootstrap/src/Template/Bake/Template/
mkdir -p plugins/Bootstrap/src/Template/Bake/Element/
オリジナルのbake用のテンプレをコピーする。
cp vendor/cakephp/bake/src/Template/Bake/Template/* plugins/Bootstrap/src/Template/Bake/Template/
cp vendor/cakephp/bake/src/Template/Bake/Element/form.ctp plugins/Bootstrap/src/Template/Bake/Element/form.ctp
メニュー部分の高さ用のcssを作ってwebroot/css以下に保存する。
body {
padding-top: 50px;
padding-bottom: 20px;
}
bootstrap.min.css もコピーしておく。
cp node_modules/bootstrap/dist/css/bootstrap.min.css webroot/css/bootstrap.min.css
レイアウトに追加
<?= $this->Html->css('bootstrap.min.css') ?>
<?= $this->Html->css('menu.css') ?>
formhelper の生成するタグを変える。
src/View/AppView.php の initialize のところに以下を追加する。
public function initialize()
{
$this->loadHelper('Form', [
'templates' => 'app_form',
]);
}
で、config 直下に自分で app_form.php というファイルを作る。
<?php
return [
'inputContainer' => '<div class="form-control">{{content}}</div>',
'label' => '<label{{attrs}} class="control-label">{{text}}</label>',
'input' => '<input type="{{type}}" name="{{name}}"{{attrs}} class="form-control">'
];
自分がいじりたい部分だけ、配列に書いて、修正を入れる。
オリジナルは
vendor/cakephp/cakephp/src/View/Helper/FormHelper.php
にだーっと書いてある。
あとはbake する時に、
bin/cake bake template Users -t Bootstrap
とする。
最新版にする
sudo composer update
npm update
テストを書く
とりあえずコントローラの方のbakeで自動生成されているテストに何も考えずに書く。
use Cake\ORM\TableRegistry;
public function testIndex()
{
$this->get('/articles?page=1');
$this->assertResponseOk();
}
public function testView()
{
$this->get('/articles/view/1');
$this->assertResponseOk();
}
public function testAdd()
{
$data = [
'name' => '記事',
'age' => 19,
'posted_date' => '2015-08-12'
];
$this->post('/articles/add', $data);
$this->assertResponseSuccess();
$articles = TableRegistry::get('Articles');
$query = $articles->find()->where(['name' => $data['name']]);
$this->assertEquals(1, $query->count());
}
public function testEdit()
{
$this->get('/articles/edit/1');
$this->assertResponseOk();
}
削除はステータス302で移動するのでassertResponseSuccessにしている。
public function testDelete()
{
$this->post('/articles/delete/1');
$this->assertResponseSuccess();
}
ちなみにBASIC認証をかけてしまった場合は、以下を追加
public function setUp()
{
parent::setUp();
$_SERVER['PHP_AUTH_USER'] = 'admin';
$_SERVER['PHP_AUTH_PW'] = 'pass';
}
file upload
jquery-file-upload を使うことにする。composer にあるので、composer.json に追記。
{
"require": {
"blueimp/jquery-file-upload": "*"
},
"autoload": {
"psr-4": {
"UploadHandler\\": "./vendor/blueimp/jquery-file-upload/server/php"
},
"classmap": ["./vendor/blueimp/jquery-file-upload/server/php/UploadHandler.php"]
},
}
composer をアップデートかける。
sudo composer update
新規にUploadsController.php を作る。
<?php
namespace App\Controller;
use App\Controller\AppController;
use UploadHandler;
/**
* Uploads Controller
*
*/
class UploadsController extends AppController
{
/**
* initialize method
*
* @return void
*/
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
}
/**
* index method
*
* @return void
*/
public function index()
{
$this->autoRender = false;
$uploadHandler = new UploadHandler();
}
}
あとはビューにファイル参照ボタンを追加して、
<style type="text/css">
.bar {
height: 18px;
background: green;
}
</style>
<?= $this->Form->create($article, ['type' => 'file']) ?>
<input id="fileupload" type="file" name="files[]" data-url="/uploads/index" multiple>
<div id="progress">
<div class="bar" style="width: 0%;"></div>
</div>
<div id="files"></div>
JavaScriptも適当に追加
$('#fileupload').fileupload({
dataType: 'json',
done: function (e, data) {
$.each(data.result.files, function (index, file) {
$('<p/>').text(file.name).appendTo('#files');
});
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .bar').css(
'width',
progress + '%'
);
}
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
webrootの下にアップロードするファイル用のフォルダーを作っておく。
mkdir webroot/files
とりあえず動いたってところまで。
JSON出力
routes.php に以下を追記。
Router::extensions(['json', 'xml']);
これで、単に今までのコントローラのURLに .json
を付けるだけで結果がJSONになる。
やってみてびびったのだが、http://book.cakephp.org/3.0/en/views/json-and-xml-views.html#creating-json-views にあるように、
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
}
を追加する必要はない。
bakeで作った素のコントローラ、
public function view($id = null)
{
$article = $this->Articles->get($id, [
'contain' => []
]);
$this->set('article', $article);
$this->set('_serialize', ['article']);
}
これそのまんまでいいのだ。呼ぶ時に .json
をつければJSONになり、つけなければビューが呼ばれる。
まあ、なんかちょっと気味が悪いが、これでよしとしてテストを追加する。
public function testJson()
{
$this->configRequest([
'headers' => ['Accept' => 'application/json']
]);
$result = $this->get('/articles/view/1.json');
$this->assertResponseOk();
$expected = [
'article' =>
['id' => 1, 'name' => '山田太郎', 'age' => '18', 'posted_date' => '2015-10-15', ・・・],
];
$expected = json_encode($expected, JSON_PRETTY_PRINT);
$this->assertEquals($expected, $this->_response->body());
}
expectedにはfixtureの値を入れておく。