Angular HttpClient の POST 処理を使用して PHP 経由で MySQL のデータを取得する

[前回](https://qiita.com/koronpo/items/12f7a9cf0783fe523f66) まででとりあえず環境整備が終わったのでアプリ作成を検討、の前に ~~`HttpClientModule` で [404 が取れない](https://qiita.com/koronpo/items/12f7a9cf0783fe523f66#3-%E3%83%93%E3%83%AB%E3%83%89%E9%80%9A%E3%82%89%E3%81%AA%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%A7%E6%96%B0%E8%A6%8F%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BB%95%E6%96%B9%E3%81%AA%E3%81%8F%E4%BD%9C%E3%82%8B)~~ 検証と手順整理も兼ねてゼロベースでの制作手順をつらつらメモします。

2019/9 追記: Angular で予定調整サービス [adfit](https://adfit.app/) を作成しました！ 

<img width="710" alt="sc5.png" src="https://qiita-image-store.s3.amazonaws.com/0/322617/e88d2458-e457-c300-b72e-febcc603e1b8.png">

# 処理概要

HttpClient の POST 処理を使用して PHP 経由で MySQL のデータを取得して wijmo のグリッドで表示させる処理。

## 環境と手順

環境は以下。

- Anglar
- MAMP
- PHP
- MySQL

`ng new` で新規プロジェクト作成した後に以下の流れを実施。

- テストテーブル・データ作成
- テーブルデータを取得・返却してくれる PHP 作成
- wijmo のパッケージ追加
- wijmo の CSS を追加して angular.json を編集
- app.component.ts の編集
- app.component.html の編集

# 実装方法

## テストテーブル・データ作成

```SQL
CREATE TABLE `test` (
  `user_no` varchar(20) NOT NULL,
  `user_name` varchar(30) DEFAULT NULL,
  `user_info` text NULL,
  PRIMARY KEY (`user_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

```SQL
INSERT INTO
  `test` (`user_no`, `user_name`, `user_info`)
VALUES
  ('1', 'ユーザー1', 'ユーザ1のインフォメーション'),
  ('2', 'ユーザー2', 'ユーザ2のインフォメーション'),
  ('3', 'ユーザー3', 'ユーザ3のインフォメーション');

```

## テーブルデータを取得・返却してくれる PHP 作成

色々と書き方忘れているのでちょっと怪しい箇所があるけど通信は出来ているので良しとする。

```php
<?php
define('DSN','mysql:host=localhost;dbname=angular_test');
define('DB_USER','root');
define('DB_PASSWORD','root');
error_reporting(E_ALL & ~E_NOTICE);

function connectDb() {
    try {
        return new PDO(DSN, DB_USER, DB_PASSWORD);
    } catch (PDOException $e) {
        echo $e->getMessage();
        exit;
    }
}

mb_language("uni");
mb_internal_encoding("utf-8"); //内部文字コードを変更
mb_http_input("auto");
mb_http_output("utf-8");

$dbh = connectDb();

$sth = $dbh->query("SELECT * FROM test");

$userData = $sth->fetchAll();

//jsonとして出力
header('Content-type: application/json');
echo json_encode($userData, JSON_UNESCAPED_UNICODE);
```

## wijmo のパッケージ追加
今回は DB データをグリッド表示させるので

```
npm install wijmo --save
```

でパッケージ追加。

## wijmo の CSS を追加して angular.json を編集

wijmo.min.css をコピーして angular.json でパス指定。具体的な手順は [Angular ライブラリとして Wijmo を利用する の 「wijmo 用の style.css と言語ファイルの読み込み」](https://qiita.com/koronpo/items/0e982da69182694741b8#wijmo-%E7%94%A8%E3%81%AE-stylecss-%E3%81%A8%E8%A8%80%E8%AA%9E%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF) を参照。

## app.module.ts の編集

```ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { WjGridModule } from 'wijmo/wijmo.angular2.grid';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
    , HttpClientModule
    , WjGridModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

## app.component.ts の編集

```ts
import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { timeout, catchError} from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';

const HTTP_OPTIONS = {
  headers: new HttpHeaders({
    'Content-Type':  'application/json'
  })
};

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit  {
  public girdData: any;

  /**
   * コンストラクタ
   */
  constructor(
    private _http: HttpClient) {
    let postUrl;
    postUrl = 'works/angular_test/test.php';
    this.http(postUrl, '').subscribe(
      res  => {
        this.girdData = res;
      }
      , error => {
        console.log(error);
      }
      , () => {
        console.log('complete');
      }
    );
  }

  /**
 * 初期化処理（デフォルト）
 * @param 無し
 * @return 無し
 */
  public ngOnInit() {
  }

  /**
 * httpポスト処理
 * @param {string} _postUrl - 送信URL
 * @param {any} _trans_data - 送信データ
 * @return {Observable<any>} http.post処理
 */
 public http(_postUrl: string, _trans_data: any): Observable<any> {
    let ret;
    ret = this._http.post(_postUrl, _trans_data, HTTP_OPTIONS)
    .pipe(
      timeout(5000),
      catchError(this.handleError())
    );
    return ret;
  }

  /**
   * Observable のエラーを返却します
   * @param 無し
   * @return {Observable<any>}
   */
  private handleError() {
    return (error: any): Observable<any> => {
      return throwError(error.message);
    };
  }
}
```

## app.component.html の編集

```html
<h1>
  データ取得テスト
</h1>
<wj-flex-grid  [itemsSource]="girdData" [isReadOnly]="true" [selectionMode]="3"
[headersVisibility]="'Column'">
  <wj-flex-grid-column
    [header]="'ユーザーNo'"
    [binding]="'user_no'"
    [width]="100">
  </wj-flex-grid-column>
  <wj-flex-grid-column
    [header]="'ユーザー名'"
    [binding]="'user_name'"
    [width]="200">
  </wj-flex-grid-column>
  <wj-flex-grid-column
    [header]="'ユーザー情報'"
    [binding]="'user_info'"
    [width]="300">
  </wj-flex-grid-column>
</wj-flex-grid>
```

## proxy.conf.json 作成

デフォルトの設定でビルドすると URL が `http://localhost:4200/` になって php が稼働しているサーバー URL に post 処理しようとすると `Access-Control-Allow-Origin` や `404 (Not Found)` が発生するので proxy 経由でアクセスするビルド設定に。手順はプロジェクトルートに `proxy.conf.json` を作成し中身を

```json
{
  "/works/angular_test/*": {
    "target": "http://localhost:80",
    "secure": false
  }
}
```

的な感じで php のサーバー設定に合わせて記述。その後 `package.json` を

```json
≈ 省略 ≈
"scripts": {
  "ng": "ng",
  "start": "ng serve --proxy-config proxy.conf.json",
  "build": "ng build",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e"
},
≈ 省略 ≈
```

と書き換え。`proxy.conf.json`　に関しては片言の日本語だけど [ここ](https://code.i-harness.com/ja/q/23736c0) にざっくりとまとまっている。

# 出来上がり

```
npm start
```

して画面が表示されたら出来上がり。接続先 URL を存在しないものに変えると `404 Not Found` がちゃんと取れるので HttpClient の実装方法としては間違っていなさそう。となればやはりサーバーのほうが怪しいか...。