Phalcon は普段から使っているけれど、まだ 3.0.0 を触ってなかったので触ってみることにした。ついでに、view として HTML を返すエンドポイント群と js から叩かれる API エンドポイント群の切り分けを意識した multi module な構成の雛形をつくってみる。
PHP と Phalcon をインストールする
もともと brew で php56 を入れていたので、とりあえず unlink しておく。もとに戻したいときの手順は後述。
$ brew unlink php56
brew で php70 と php70-phalcon をインストール。
$ brew install php70
$ brew install php70-phalcon
php のバージョンを確認。
$ php --version
PHP 7.0.10 (cli) (built: Aug 21 2016 19:14:33) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
Phalcon については、以下のように /usr/local/etc/php/7.0/conf.d/ext-phalcon.ini
が読み込まれている。
$ php -i | grep ext-phalcon.ini
Additional .ini files parsed => /usr/local/etc/php/7.0/conf.d/ext-phalcon.ini
中身を確認する。
$ cat /usr/local/etc/php/7.0/conf.d/ext-phalcon.ini
[phalcon]
extension="/usr/local/opt/php70-phalcon/phalcon.so"
以下のように、/usr/local/opt/php70-phalcon
は ../Cellar/php70-phalcon/3.0.0
への symlink なので、Phalcon のバージョンも 3.0.0 ということで大丈夫そう。
$ ll /usr/local/opt | grep php70-phalcon
lrwxr-xr-x 1 m0t0k1ch1 admin 29 9 1 10:23 php70-phalcon -> ../Cellar/php70-phalcon/3.0.0
ちなみに、php56 に戻したい場合は以下のようにする。逆も然り。
$ brew unlink php70
$ brew link php56
phpenv はなんかうまいこと動かなかったし、この 2 バージョン以外は触る予定ないし、そんなに頻繁に切り替えることはないので、これでいいかという感じ。
phalcon-devtools をインストールする
自分は ここ に書いてあるように git で落としてきてパスを通した。
こちらのバージョンも 3.0.0 であることを確認。
$ phalcon
Phalcon DevTools (3.0.0)
Available commands:
commands (alias of: list, enumerate)
controller (alias of: create-controller)
module (alias of: create-module)
model (alias of: create-model)
all-models (alias of: create-all-models)
project (alias of: create-project)
scaffold (alias of: create-scaffold)
migration (alias of: create-migration)
webtools (alias of: create-webtools)
プロジェクトの雛形をつくる
$ phalcon create-project multi-module-phalcon
サーバーを立ち上げる。
$ cd multi-module-phalcon
$ php -S 127.0.0.1:8000 -t public .htrouter.php
PHP 7.0.10 Development Server started at Tue Sep 6 01:02:42 2016
Listening on http://127.0.0.1:8000
Document root is /Users/m0t0k1ch1/.ghq/src/github.com/m0t0k1ch1/multi-module-phalcon/public
Press Ctrl-C to quit.
ブラウザで http://127.0.0.1:8000 にアクセス。
大丈夫そう。
multi module な感じにする
公式の ドキュメント や GitHub repo を参考に、えいやっと最低限な状態をつくってみる。
できあがったのがこちら。
apps
以下はこんな感じ。
apps
├── backend
│ ├── Module.php
│ ├── config
│ │ └── config.php
│ └── controllers
│ ├── ControllerBase.php
│ └── UserController.php
├── frontend
│ ├── Module.php
│ ├── config
│ │ └── config.php
│ ├── controllers
│ │ ├── ControllerBase.php
│ │ └── IndexController.php
│ └── views
│ ├── index
│ │ └── index.volt
│ ├── index.volt
│ └── layouts
└── routes.php
apps/routes.php
で以下のようにルーティングしている。
<?php
$router = new \Phalcon\Mvc\Router;
$router->setDefaultModule('frontend');
/*
* View
*/
$router->add('/', [
'module' => 'frontend',
'controller' => 'index',
'action' => 'index',
]);
/*
* API
*/
$router->addGet('/user', [
'module' => 'backend',
'controller' => 'user',
'action' => 'get',
]);
return $router;
これを先ほどと同じように立ち上げて http://127.0.0.1:8000 にアクセスすると、同じ画面が表示されるはず。内部的には frontend module に流れている。
で、http://127.0.0.1:8000/user を GET で叩くと、以下のようなレスポンスが返ってくる。
$ curl -s http://127.0.0.1:8000/user | jq .
{
"name": "m0t0k1ch1"
}
こちらは backend module に流れている。
ちなみに、public/index.php
は以下のようになっている。Phalcon\Mvc\Application
を使っていないのは、backend module(JSON 返すだけ)で view を DI コンテナに突っ込みたくなかったから。処理のフローが明示的になるので、エラーハンドリングもやりやすくなるといいなという想いもある。
<?php
use \Phalcon\Di\FactoryDefault;
use \Phalcon\Loader;
use \Phalcon\Mvc\Router;
error_reporting(E_ALL);
define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/apps');
$di = new FactoryDefault;
$di->set('router', function() {
return include APP_PATH . '/routes.php';
});
try {
$router = $di['router'];
$router->handle();
$moduleName = $router->getModuleName();
switch ($moduleName) {
case 'frontend':
require_once APP_PATH . '/frontend/Module.php';
$module = new \Multi\Frontend\Module;
break;
case 'backend':
require_once APP_PATH . '/backend/Module.php';
$module = new \Multi\Backend\Module;
break;
default:
throw new \RuntimeException('unknown module');
}
$module->registerAutoloaders($di);
$module->registerServices($di);
$dispatcher = $di['dispatcher'];
$dispatcher->setModuleName($moduleName);
$dispatcher->setControllerName($router->getControllerName());
$dispatcher->setActionName($router->getActionName());
$dispatcher->setParams($router->getParams());
$dispatcher->dispatch();
if ($moduleName == 'frontend') {
$view = $di['view'];
$view->start();
$view->render(
$dispatcher->getControllerName(),
$dispatcher->getActionName(),
$dispatcher->getParams()
);
$view->finish();
$response = $di['response'];
$response->setContent($view->getContent());
$response->send();
}
}
catch (\Exception $e) {
echo $e;
}