oikynブログ

エンジニアの技術ブログ。主にWEB、iOS、サービス、ツールなどなど。

CentOSにHaskellをインストール

CentOSHaskellをインストール

http://justhub.org/download

インストール

sudo wget http://sherkin.justhub.org/el6/RPMS/x86_64/justhub-release-2.0-4.0.el6.x86_64.rpm
sudo rpm -ivh justhub-release-2.0-4.0.el6.x86_64.rpm
sudo yum install haskell

起動

$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> 

終了

Prelude> :q
Leaving GHCi.

インストール済みパッケージリスト

$ ghc-pkg list
/usr/local/lib/ghc-7.6.3/package.conf.d
   Cabal-1.16.0
   array-0.4.0.1
   base-4.6.0.1
   bin-package-db-0.0.0.0
   binary-0.5.1.1
   bytestring-0.10.0.2
   containers-0.5.0.0
   deepseq-1.3.0.1
   directory-1.2.0.1
   filepath-1.3.0.1
   ghc-7.6.3
   ghc-prim-0.3.0.0
   haskell2010-1.1.1.0
   haskell98-2.0.0.2
   hoopl-3.9.0.0
   hpc-0.6.0.0
   integer-gmp-0.5.0.0
   old-locale-1.0.0.5
   old-time-1.1.0.1
   pretty-1.1.1.0
   process-1.1.0.2
   rts-1.0
   template-haskell-2.8.0.0
   time-1.4.0.1
   unix-2.6.0.1
   HTTP-4000.2.10
   monads-tf-0.1.0.1
   mtl-2.1.2
   network-2.4.2.1
   parsec-3.1.4
   text-1.0.0.0
   transformers-0.3.0.0

パッケージのインストール

cabal update
cabal install パッケージ名

Git

Git

いまさら感ありますが、
時間があったのでGitについて基本を整理してたので、
メモ的な感覚で書きます。

・適当な場所にディレクトリを作成して『git init』 でリポジトリ作成

リポジトリを共有化する場合は、bare、sharedオプションを付与して『git init』

・gitの初期化が完了したら、gitユーザーを作成しておいて、
gitユーザーが書き込み可能な状態にグループを変更しておく

・gitプロトコルでアクセスする場合は、リモート側でgit-daemonをインストール&起動
※誰でもアクセスできちゃうので、セキュリティ的には良くない

・リモートへは基本、sshプロトコルでアクセスするほうが良い

・外部からsshできるようにするために、リモート側で「/home/git/.ssh/authorized_keys」(パーミッション600)を作成。
そのファイル内に、アクセス元の公開鍵を登録。

・ブランチ管理には「git flow」を利用する

・ローカルもしくはリモート側で『git flow init』しておく

・git管理ツールは、gitlabが良いかな。
FacebookのOSSの「Phabricator」はちょっと複雑なので、余計な機能がないgitlabがよいかと。

・ローカルでは、sourcetreeというツールがいいですね。(Win、Mac)

Phalcon 1.2.4 (PHP Framwork)::APIスケルトン その2

Phalcon

前回の記事に記述したディレクトリ構成に、
interfacesというディレクトリを追加してみました。

├─collections
│      UserCollection.php
│
├─config
│      config.php
│      loader.php
│      services.php
│
├─controllers
│      ControllerBase.php
│      UserController.php
│
├─interfaces
│  ├─request
│  │  ├─fields
│  │  │      CommonFields.php
│  │  │      UserFields.php
│  │  │
│  │  └─validation
│  │      │  UserValidation.php
│  │      │  ValidationBase.php
│  │      │
│  │      └─custom
│  │              Custom.php
│  │              Date.php
│  │              Type.php
│  │
│  └─response
│      │  ResponseBase.php
│      │  UserResponse.php
│      │
│      └─fields
│              UserFields.php
│
├─models
└─views

追加したinterfacesディレクトリには、
名前の通り、主に、request、responseに関するクラスを
入れました。

サンプルソース

controllers/UserController.php
require __DIR__ . '/../interfaces/request/validation/UserValidation.php';
require __DIR__ . '/../interfaces/response/UserResponse.php';

class UserController extends ControllerBase {

    public function getUser() {
        $req = $this->input();

        //バリデーション処理
        $uv = new UserValidation();
        $valid = $uv->getUserValidation($req);

        if ($valid->count()) {
            //Error
            $msg = $valid[0]->getMessage();
            $this->output(400, UserResponse::errorResponse(400, $msg));
            return;
        }

        //DB操作

        //レスポンス
        $this->output(200, UserResponse::getUserResponse({DB操作した結果の配列}));
    }

}

コントローラーでは、基本的に全て共通して、

リクエストを取得
↓
バリデーションチェック
↓
エラーの場合は、エラーレスポンスを返す
↓
エラーがない場合は、DB操作を何かする
↓
レスポンスデータを作成し、JSONを返す

といった感じですかね。

バリデーションチェックでは、
nullチェックや、型チェック、値チェック、長さチェックなど
基本的なことをやります。

また、リクエストフィールドに対するバリデーションチェックは、
APIの種類に関係なく、基本は同じはずだと思います。
(nullがOKの有無はAPIの種類によって異なる場合はあるかと思います。)

なので、APIで扱う全てのリクエストフィールド情報は、
interfaces/request/fields/CommonFields.php
に記述するようにしました。

内容としては、
フィールド名、フィールドに対して使用するバリデーションインスタンス
となります。

サンプルソース

interfaces/request/fields/CommonFields.php
<?php

use Phalcon\Validation\Validator\PresenceOf,
    Phalcon\Validation\Validator\InclusionIn,
    Phalcon\Validation\Validator\Email,
    Phalcon\Validation\Validator\Between,
    Phalcon\Validation\Validator\StringLength;

class CommonFields {

    //Request Fields
    protected $_fields;

    public function __construct() {
        $this->_fields = array(
            'sex' => array(
                'default' => array(
                    new PresenceOf(array(
                        'cancelOnFail' => TRUE,
                            )),
                    new InclusionIn(array(
                        'domain' => array('male', 'female'),
                        'cancelOnFail' => TRUE
                            )),
                ),
                'custom' => array(
                    new Type(array(
                        'type' => 'string'
                            )),
                ),
            ),
            'birthday' => array(
                'default' => array(
                    new PresenceOf(array(
                        'cancelOnFail' => TRUE,
                            )),
                ),
                'custom' => array(
                    new Type(array(
                        'type' => 'integer'
                            )),
                    new Date(array(
                        'format' => 'Ymd'
                            )),
                ),
            ),
            ~省略~
        );
    }

    public function getFields() {
        return $this->_fields;
    }

}

バリデーションの部分が
defaultとcustomに分かれているのは、
Phalconで用意されているバリデーションクラスと、
自前で用意したバリデーションクラスを区別するためです。

上記のクラスでは、APIの全てで扱うフィールドを設定したので、
interfaces/request/fields/UserFields.php
では、各APIで扱うフィールドを記述するようにしました。

サンプルソース

interfaces/request/fields/UserFields.php
namespace Interfaces\Request\Fields {

    class UserFields {
        static public function getUserFields() {
            return array(
                array('sex', TRUE),
                array('birthday', TRUE),
                ~省略~
            );
        }
    }
}

TRUEの部分は、NOT NULLのフラグとしています。
ここをFALSEにすると、バリデーションチェックで、
nullチェックは行わないようにします。

バリデーションチェックして、OKだったら、
何かDB操作して、レスポンスを返さなければいけません。

リクエストと同様にして、
APIごとにレスポンスのフィールドも設定するようにします。

サンプルソース

interfaces/response/fields/UserFields.php
<?php

namespace Interfaces\Response\Fields {

    class UserFields {
        static public function getUserFields() {
            return array(
                'sex',
                'birthday',
            );
        }
    }
}

DBから得られた結果から、上記で設定したフィールドをもとに
必要なものだけを取得して、レスポンスを作成し、クライアントに返します。

ここまで、ソースを抜粋しながら、簡単な説明を記載してきました。
DB操作以外の部分は、
API実装前に存在している仕様書から全て設定できる範囲なので、
実装の半分くらい?は簡単にできるのではないかなと感じてます。

Phalcon 1.2.4 (PHP Framwork)::APIスケルトン

Phalcon

Phalcon Frameworkを利用してAPIを実装したときのスケルトンを紹介します。

本家ドキュメントでは、
http://docs.phalconphp.com/en/latest/reference/micro.html
を参考にしました。

ディレクトリ・ファイル構成

基本構成は、Phalcon Developer Toolsを使用して作成しました。

phalcon-micro
│  .htaccess
│  app.php
│
├─.phalcon
├─app
│  ├─collections
│  │      UserCollection.php
│  │
│  ├─config
│  │      config.php
│  │      loader.php
│  │      services.php
│  │
│  ├─controllers
│  │      ControllerBase.php
│  │      UserController.php
│  │
│  ├─models
│  └─views
│
├─logs
│
└─public
    │  .htaccess
    │  index.php
    │
    ├─css
    ├─files
    ├─img
    └─js

API用に追加した部分

  1. コントローラー
    Developer Toolsで作成すると、MVしかない。

  2. コレクション
    http://docs.phalconphp.com/en/latest/reference/micro.html#using-controllers-as-handlers

サンプルソース

app.php

※ルーターの役割

<?php

//APIのバージョン
$version = "1.0";

//未定義のパスにアクセスした場合に実行される
$app->notFound(array(new ControllerBase(), "notFoundAction"));

//コレクションのインクルード
include __DIR__ . '/app/collections/UserCollection.php';
UserCollection.php
<?php

use Phalcon\Mvc\Micro\Collection as MicroCollection;

$userCollection = new MicroCollection();

//メインコントローラー
$userCollection->setHandler(new UserController());

//コレクション内での共通prefix
$userCollection->setPrefix("/{$version}/user");

/**
  * ユーザー情報取得
  *
  * http://api.sample.com/1.0/user/
  * に対して
  * GETでアクセスすると
  * UserControllerのgetUserメソッドが実行される
  */
$userCollection->get("/", "getUser");

/**
  * ユーザー登録
  *
  * http://api.sample.com/1.0/user/register/
  * に対して
  * POSTでアクセスすると
  * UserControllerのpostUserメソッドが実行される
  */
$userCollection->post("/register", "postUser");

$app->mount($userCollection);
UserController.php
<?php

class UserController extends ControllerBase {
    
    public function getUser() {

    }
    
    public function postUser() {

    }
}
ControllerBase.php

※全てのコントローラーのベース

<?php

use Phalcon\Mvc\Controller;

class ControllerBase extends Controller
{
    /**
     * 
     * @param int $code
     * @param array $content
     */
    protected function output($code, $content=array()) {
        //Header
        $this->response->setContentType('application/json')
                       ->setStatusCode($code, null)
                       ->sendHeaders();
        //Body
        $this->response->setJsonContent($content)
                       ->send();
    }
    
    public function notFoundAction() {
        $this->output(404);
    }
}

Phalcon 1.2.4 (PHP Framwork)::コントローラー

Phalcon Framework

コントローラー

http://docs.phalconphp.com/en/latest/reference/controllers.html

リクエスト

GET基本
http://localhost/blog/posts/show/2012/the-post-title/

※GETクエリには、パラメータの値だけで、変数名は不要。
以下のようにActionメソッド関数に引数を設定することで、取得できる。
URLに設定されているパラメータ値と、メソッドの引数は順序的1対1の関係にある。

<?php

class PostsController extends \Phalcon\Mvc\Controller
{

    public function indexAction()
    {

    }

    public function showAction($year, $postTitle)
    {
       /*
       $year に 2012
       $postTitle に the-post-title
       がアサインされる
       */
    }

}

GETパラメータにデフォルト値を設定する場合は、以下のようにする。

public function showAction($year=2012, $postTitle='some default title')
{

}

もし、URL形式を以下のようにしたい場合は、
http://localhost/blog/posts/show/?year=2012&title=the-post-title

以下のようにパラメータ値を取得できる。

public function showAction()
{
    $year = $this->request->getQuery('year');
    $title = $this->request->getQuery('title');
}

GET以外のPOSTなども上記と同じような理屈で対応できる。

リクエストに関するクラスは、 Phalcon\Http\Request

レスポンス

レスポンスに関するクラスは、 Phalcon\Http\Response

フォワード

$this->dispatcher->forward(array(
    "controller" => "users",
    "action" => "signin"
));

初期化メソッド

※ “__construct”は非推奨です。
※beforeExecuteRouteイベントが成功した場合のみ実行されます。

public function initialize()
{

}

登録サービスへのアクセス

Phalcon\Mvc\Controllerを継承したコントローラーであれば、
以下のようにしてDIにアクセスできます。

$this->di;

or

$this->getDI();

セッションデータ

セッションに関するクラスは、 Phalcon\Session\Bag

以下のようにして、値のセット、取得ができます。

<?php

class UserController extends Phalcon\Mvc\Controller
{

    public function indexAction()
    {
        $this->persistent->name = "Michael";
    }

    public function welcomeAction()
    {
        echo "Welcome, ", $this->persistent->name;
    }

}