【ふくだ学習録】CakePHP3入門 part3【12日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

### 読了した本
[データベースエンジニア養成読本 [DBを自由自在に活用するための知識とノウハウ満載!]](https://www.amazon.co.jp/dp/4774158062/ref=cm_sw_r_tw_dp_U_x_FPphEbQFPPQRM )
[ゼロから作るDeepLearning](https://www.amazon.co.jp/dp/4873117585/ref=cm_sw_r_tw_dp_U_x_y3UiEbF3P6EG7)

# CakePHP3入門を読んで

### テーブルクラスの初期化設定

```php:BoardsTable.php

class BoardsTable extendsTable {
  public function initialize(array $config){
     parent::initialize($config);

     $this->table('books');
  }
}
```
上記の`initialize()`で、クラスの初期化設定を行なっている。
`$this->table('books')`と記載することによって、このBoardTableで利用するテーブルを「books」に変更している。

### プライマリキーの設定
プライマリキーをテーブルクラスから変更することができる。
（アプリケーション上で使えるだけで、データベース上のプライマリキーは変わらない）

```php:BoardsTable.php

class BoardsTable extendsTable {
  public function initialize(array $config){
     parent::initialize($config);

     $this->primaryKey('name');
  }
}
```

`$this->primaryKey('name')`とすることで、nameがプライマリキーとして設定される。
（データベース上のプライマリキーは、あくまでidのまま）

```php:BoardsController.php

  public function index($id = null){
    $data = $this->Boards->get('hanako'); 
    # 通常であればプライマリキーはidだが、nameに変更していることによってget()メソッドで名前検索できている。
  }
```

### リスト表示のフィールド指定
`find()`メソッドなどで、listを指定したとき、通常であればプライマリキーであるIDと、一番最初にある項目が一覧で表示される。
`displayField()`メソッドを使用すると、「listで取り出されるフィールド」を指定することができる。

```php:BoardsTable.php

class BoardsTable extendsTable {
  public function initialize(array $config){
     parent::initialize($config);

     $this->displayField('title');
  }
}
```

```php:BoardsController.php

  public function index($id = null){
    $data = $this->Boards->find('list')->toArray();
    $this->set('data', $data);
  }
```

上記のように指定すると、titleの値がリストとして表示される。

### エンティティクラスの指定
基本的には、テーブルとクラスとエンティティクラスはセットで使われる。（CakePHPが名前から1つのモデルとして認識するため）
`$this->entityClass()`を使用することで、どのエンティティクラスをテーブルクラスと結びつけるのかを変更することができる。

```php:BoardsTable.php

class BoardsTable extendsTable {
  public function initialize(array $config){
     parent::initialize($config);

     $this->entityClass('Book'); # エンティティクラスをBookに設定
  }
}
```

```php:BoardsController.php

  public function index($id = null){
    $data = $this->Boards->find('all')->toArray();
    $this->set('data', $data);
  }
```

この`$data`を表示させると、booksテーブルの一覧が表示される。
（取り出されたエンティティは、　Bookクラスのインスタンスになっている。）

### 使用するデータベースを変更したいとき。
config内にある`app.php`を書き換えることで実装できる。
アプリケーションが起動するとき、テーブルクラスの`defaultConnectionName()`と呼ばれるメソッドによって、データベース関連の設定に必要な情報が読み込まれる。
この`defaultConnectionName()`で得られる名前はデフォルトでは「default」になっているため、Datasources内のdefaultの設定が利用されるわけだから、環境によって「default」ではない名前が返ってくるようにすることで、違うデータベースを利用することができるようになる。

具体的には、下記の記述をテーブル内で記載する。

```php:BoardsTable.php

class BoardsTable extends Table {
  public static function defaultConnectionName(){ # これでdefaultConnectionNameメソッドをパッチする。
    return 'default2';
  }
}
```

### コールバックメソッド
テーブルクラスでは、各種操作時に自動的に呼び出されるコールバックメソッドが用意されている。
何かの操作を行う前や後に、処理を行いたい場合はコールバックメソッドをしようして実装する。

#### 検索の前処理
`beforeFind(Event $event)`メソッドを使用する。

```php:BoardsTable.php
// 以下のuse文を追加
// use Cake\Event\Event;

class BoardsTable extends Table {
  public function beforeFind(Event $event){
    # 検索の前に行いたい処理を記載する。 
  }
}
```

#### データ保存時の前後処理
保存前には、`beforeSave()`保存後には`afterSave()`を利用する。

#### データ削除時の前後処理
削除前には、`beforeDelete()`保存後には`afterDelete()`を利用する。

### QueryBuilder
QueryBuilderとは、データベース検索を行うために使用するCakePHPの仕組み。
基本的にはQueryクラスからQueryインスタンスを作成し、それに対してメソッドチェーンを行なっていく。


#### 検索条件を設定する「where」
`where();`を使用する。

```php:
$data = $this->Boards
  ->find()
  ->where(['name'=>'hanako']);
```

#### 検索条件をソートする「order」
`order();`を使う。

```php:
$data = $this->Boards
  ->find()
  ->where(['id >='=>１])
  ->order(['id'=>'DESC']);
```

#### 位置取得と範囲設定をする「offset」「limit」
`offset();``limit();`を使用する。

```php:
$data = $this->Boards
  ->find()
  ->order(['id'=>'DESC'])
  ->offset(5) # 5個目から
  ->limit(2); # 2つ
```

#### 複数のwhere条件
`andWhere();``orWhere();`を用いる。

```php:
$data = $this->Boards
  ->find()
  ->where(['id >='=>１])
  ->ordWhere(['name'=>'hanako'])
  ->orWhere(['id'=>3]);
```

#### 項目の設定「select」
`select();`で取り出すフィールドの項目設定ができる。

```php:
$data = $this->Boards
  ->find()
  ->select(['id','name']);
```

#### whereに関数を渡す

```php:
[Query]->where(
  function($exp, $q){
    return [Expression];
  }
)
```
という形で、whereに関数を渡せる。
`[Expression]`は条件などを評価する式を扱うためのクラス。

例えば下記のように使用する。

```php:
$data = $this->Boards
  ->find()
  ->where(function ($exp, $q) use($input) {
    return $exp->eq('id', $input);
  })
```
この時、

```php:
$exp->eq('id', $input);
```
では、$exp内にある`eq()`というメソッドを呼び出している。
このeqは等号による式を表すメソッドで、`id = $input`という条件式を作り出している。
$expには様々なメソッドがあるので、様々な条件を作れる。

### ConnectionManager
データベース接続に関する機能を提供するクラス。このConnectionManagerからメソッドを呼び出していくことで、SQLを直接発行することができるようになる。
ただしいくつかのクラスを組み合わせる必要がある。下記にその手順を簡単に記載していく。

#### ①Connectionインスタンスの取得

```php:
$変数１ = ConnectionManager::get( 設定名 ); 
```
上記することで、ConnectionManagerから、Connectionというクラスのインスタンスを取得する。引数はapp.phpのDatasourcesに用意した設定の名前を指定する。

返されるConnectionは、データベースとの接続を管理するクラスで、getでConnectionインスタンスを取得することができ、その設定でのデータベース接続をオブジェクトとして取り出すことができる。

#### ②executeでStatementを取得

```php:
$変数2 = $変数1->execute( テキスト );
```

Connectionの`execute`メソッドを実行する。これはSQLコマンドを発行するためのメソッド。
引数には、実行するSQLコマンドをテキストとして用意する。ただしこの段階ではSQLコマンドは発行されない。

このメソッドの返り値は、`Statement`と呼ばれるインスタンス。データベースによっても変わってくるが、一般的にはPDOStatmentという、PDOベースのStatementインスタンスになる。

#### ③fetchAllで結果を配列で取得

```php:
$変数3 = $変数2->fetchAll( 'num' | 'assoc' );
```
ステートメントを実行して、データベースから結果を受け取る。戻り値は配列になっていて、中にはレコード内容を連想配列にまとめたものが保管されている。


# 今日の一言
明日は７時１５分には始めれるように、早起きしていきたい！眠いけど！