自作Composerのパッケージの基本的な構成

# ●はじめに
以下の記事は当時の自分の検索スキルが足らず、該当する内容を見つけられず仕方なく自分で考察・実装した時のメモです。

コメントで教えて頂いた[https://github.com/php-pds/skeleton](https://github.com/php-pds/skeleton)の方がより洗練されて美しいので、こちらを参考にしてもらった方が良いと思います。

以上ご了承の上で敢えて読みたい方は以下から本編です。

# ●概要
経緯として複数のWebアプリケーションで使用するモデルとビジネスロジックや、コマンドラインで使用するモジュールをコピペで再利用していた。
当然、追加機能の開発やらバグ対応やら運用がツライ　→　爆死。

本当にありがとうございました。

これじゃーイカンなと、Composerパッケージとして開発・運用する必要があるなと痛感した次第であります。
「ではどうするか？」となった時に調査して考えた内容で、ある程度土台(テンプレートともいう)は共通化する必要があるのでまとめた。

要するにcomposerでパッケージ作る時の土台部分の話。

# ●目的
土台を共通化することで

* 開発効率を上げる
* 属人化しない。(未来の自分に優しく)
* 再利用しやすい
* 開発・バグ対応が簡単


# ●方針
個人・自社のみの使用を想定。 ← クローズドな環境で使用するの意味。
再利用する単位(モジュール)でパッケージにする。
基本的にはWebアプリケーションでは無い。

* 複数のWebアプリケーションで利用するモデルやビジネスロジック
* コマンドラインで使用する

などなど

Webフレームワークを使用する場合はそれに合わせる。ほとんどのWebフレームワークには以下の構成・運用に大体なっていると思うが。

## ■使用パッケージ
Composerが親の仇っていう人は帰ってどうぞ。
それ以外の人はComposerを使ってパッケージを入れる。最低限これだけは入れとけってヤツ。

* monolog
* .env
* phpunit
* psysh

## ■基本的な運用
必要なパッケージをcomposerで追加。
　→車輪の再発明はイヤだ。
composerの自作パッケージとして再利用出来るようにする。
　→自分が作ったからと言ってもコピペはツライ。
当然gitも使用する。
　→composerのパッケージとして利用出来るように、gitのtagとcomposer.jsonのバージョンを合わせる

# ●パッケージ名の命名規則
全て小文字でダッシュを挟む。

```
my-package
```

[Composer ドキュメント日本語訳 → 全てのプロジェクトはパッケージである → 注意](https://kohkimakimoto.github.io/getcomposer.org_doc_jp/doc/02-libraries.html)

今後この記事では説明の為に```my-package```をパッケージ名として作る。

# ●ディレクトリ構成とファイル
いろんなパッケージを参考にしている。

## ■最低限必要だよねっていうディレクトリ
* logs：ログファイルを置き場
* src/MyPackage/Exception：ソースファル置き場
* tests：テストファイル置き場

「MyPackage」のところは、作るパッケージ名合わせて変える。

## ■必要に応じて入れればいいんじゃないかっていうディレクトリ
* docs：readme.mdで収まり切らない場合の説明を入れる
* example：readme.mdで収まり切らない場合の使用例
* bin：バイナリファイル

## ■諸々の設定ファイルとか
* .gitignore：２箇所。git無視ファイル
* composer.json：パッケージの依存性とかのファイル
* phpunit.xml：phpunit設定ファイル
* psysh.php：psyshの実行を簡単にするファイル
* readme.md：目的と使い方ぐらいは書きたい

## ■composerが作成するファイル
* composer.lock：```composer install```とかを実行すると自動で作られる
* vendor/autoload.php：クラスのオートロードファイル
* vendor/bin/phpunit：phpunitバイナリファイル
* vendor/bin/psysh：psyshバイナリファイル


## ■最終的な構成例
```
my-package
├── .gitignore
├── bin
├── composer.json
├── composer.lock
├── docs
├── example
├── logs
│   └── .gitignore
├── phpunit.xml
├── psysh.php
├── readme.md
├── src
│   └── MyPackage
│       └── Exception
├── tests
└── vendor
    ├── autoload.php
    ├── bin
    │   ├── php-parse -> ../nikic/php-parser/bin/php-parse
    │   ├── phpunit -> ../phpunit/phpunit/phpunit
    │   └── psysh -> ../psy/psysh/bin/psysh
    ├── composer
    ...
```



# ●作り方
パッケージのvendor(所属)をきめておく。
個人ならgithubのアカウント。会社なら会社名とか。

composerをいれる。ここはググればいくらでも検索が出るので省く


## ■composer.jsonの作成

```
$ mkdir my-package
$ cd ./my-package/
$ composer init


  Welcome to the Composer config generator



This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [busyoumono/my-package]: busyoumono99/my-package
Description []:
Author [busyoumono99 <xxxx@xxxxxx.com>, n to skip]
Minimum Stability []: stable
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: MIT

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]?
Search for a package:
Would you like to define your dev dependencies (require-dev) interactively [yes]?
Search for a package:

{
    "name": "busyoumono99/my-package",
    "type": "library",
    "license": "MIT",
    "minimum-stability": "stable",
    "require": {}
}

Do you confirm generation [yes]?
$ composer require vlucas/phpdotenv
$ composer require monolog/monolog
$ composer require phpunit/phpunit --dev
$ composer require psy/psysh:@stable --dev
```

## ■各ディレクトリの作成

```
$ mkdir -p src/MyPackage/Exception
$ mkdir logs
$ mkdir tests
$ mkdir docs
$ mkdir example
$ mkdir bin
```

## ■オートロード
composer.jsonにオートロードの設定を追加する。

```
"autoload": {
    "psr-4": {
        "busyoumono99\\MyPackage\\": "src/MyPackage/"
    }
},
```


autoloadの設定を反映させる

```
$ composer dump-autoload
```
　
## ■.envを作成

```
$ vi .env

TEST_NAME=hoge
```

## ■gitignore
```
vi .gitignore

/vendor
.env

vi logs/.gitignore

*
!.gitignore
```

## ■psysh用のシェルスクリプト作成
デバッグ時にphpを対話方式で実行する。autoload等毎回設定するのは面倒なので、決まりきった処理を書いて楽をする。


```
$ vi psysh.php
```


```
#!/usr/bin/env php
<?php
// ↓名前空間を利用するプロジェクトでは記述しておく
namespace busyoumono99\MyPackage;

// Composerのオートローダーを読み込む
require_once __DIR__ . '/vendor/autoload.php';
// ほかに初期化用のPHPファイルがあれば読み込んでおく
// require_once …

// .envの読込。.envが必要ない、使用しない場合はコメントアウトする
$dotenv = new \Dotenv\Dotenv(__DIR__.'/');
$dotenv->load();

echo __NAMESPACE__ . " shell\n";

$sh = new \Psy\Shell();

// シェル起動直後にプロジェクトのnamespaceを設定する
// 名前空間を利用しないプロジェクトでは↓の行は不要
$sh->addCode(sprintf("namespace %s;", __NAMESPACE__));

$sh->run();

// 終了時に表示するメッセージ
echo "Bye.\n";
```


```
# 実行権限を追加する
$ chmod +x ./psysh.php
```

## ■phpunit.xml
phpunitの設定ファイル。

```
<?xml version="1.0" encoding="utf-8" ?>
<phpunit colors="true" bootstrap="vendor/autoload.php">
    <testsuites>
        <testsuite name="All tests">
            <directory>tests/</directory>
        </testsuite>
    </testsuites>
</phpunit>
```

bootstrapは基本的にautoloadしか設定しないのでこうした。

もしbootstrapに.envの読込やタイムゾーンの設定が必要になったらtests直下にbootstrap.phpを作って、その中でゴニョゴニョする。
それに合わせて```bootstrap="tests/bootstrap.php"```に変更する。







# ●使い方(開発時)
## ■monolog
ログの簡単な使い方。

```
<?php

namespace busyoumono99\MyPackage;

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;

class LogSample
{

    public static function write($message){
      $log = new Logger('my-package');
      // ログのパスを設定する
      $log_path = __DIR__. '/../../logs/test.log';
      //ログレベルをDEBUG（最も低い）に設定
      $handler = new StreamHandler($log_path,Logger::DEBUG);
      $log->pushHandler($handler);
      // ログローテーションのハンドラーを使う
      $rotating_handler = new RotatingFileHandler($log_path, 30, Logger::DEBUG, true);
      $log->pushHandler($rotating_handler);

      // 書き込む
      return $log->addDebug($message);
    }
}

```

解説

* ```Logger```クラスと必要なハンドラークラスを読み込む。
* ハンドラーは複数設定出来る。
* ハンドラーを複数設定した場合は同時に書き込む。
* ログレベルの設定で開発・本番等の切り替えが出来る。

他にも色々と機能等があるので詳細は別途ググると良い。以下大きいところ。

* ハンドラーにはファイルの書き込み以外に、DBに書き込み、メール送信、Slack等の外部サービスと連携とかがある。
* フォーマットの機能もある

## ■.env
利用前の設定。bootstrap.php的なライブラリのセットアップ時に読込処理をしておく。

```
// Composerのオートローダーを読み込む
require_once __DIR__ . '/vendor/autoload.php';
// .envの読込。
$dotenv = new \Dotenv\Dotenv(__DIR__.'/');
$dotenv->load();
```

実際に値を取得する。

```
<?php

namespace busyoumono99\MyPackage;

class EnvSample
{
    /**
     * .envの使用例
     * @return string
     */
    public static function getTestName()
    {
        return getenv('TEST_NAME');
    }

}

```


## ■phpunit
### ○クラス
例えば四則演算のクラス

src/MyPackage/Arithmetic.php

```
<?php

namespace busyoumono99\MyPackage;


class Arithmetic
{
    /**
     * 足し算
     */
    public function add($x, $y) {
        return($x + $y);
    }

    /**
     * 引き算
     */
    public function subtract($x, $y) {
        return($x - $y);
    }

    /**
     * 掛け算
     */
    public function multiply($x, $y) {
        return($x * $y);
    }

    /**
     * 割り算
     */
    public function divide($x, $y) {
        return($x / $y);
    }
}
```

### ○テストケース
tests/ArithmeticTest.php

```
<?php
use PHPUnit\Framework\TestCase;
use busyoumono99\MyPackage\Arithmetic;

class ArithmeticTest extends TestCase
{
  /**
     * @var Arithmetic
     */
    protected $object;

    /**
     * setUpは各テストメソッドが実行される前に実行する
     */
    protected function setUp() {
        // テストするオブジェクトを生成する
        $this->object = new Arithmetic();
    }

    /**
     * 足し算関数の検証
     * @test
     */
    public function ３足す５は８() {
        $this->assertEquals(8, $this->object->add(3, 5));
    }

    /**
     * @test
     */
    public function １５足す３０は４５() {
        $this->assertEquals(45, $this->object->add(15, 30));
    }

    /**
     * 引き算関数の検証
     * @test
     */
    public function １０引く３は７() {
        $this->assertEquals(7, $this->object->subtract(10, 3));
    }

    /**
     * @test
     */
    public function ３引く９はー６() {
        $this->assertEquals(-6, $this->object->subtract(3, 9));
    }

    /**
     * 掛け算関数の検証
     * @test
     */
    public function ４かける６は２４() {
        $this->assertEquals(24, $this->object->multiply(4, 6));
    }

    /**
     * @test
     */
    public function ４かけるー５はー２０() {
        $this->assertEquals(-20, $this->object->multiply(4, -5));
    }

    /**
     * 割り算関数の検証
     */
    public function testDivide() {
        // 引数に6,2を渡すと3が返ってくることを確認する
        $this->assertEquals(3, $this->object->divide(6, 2));
        // 引数に6,6を渡すと1が返ってくることを確認する
        $this->assertEquals(1, $this->object->divide(6, 6));
    }
}
```

* ```setUp```に各テスト前に実行する共通処理を書く
* ドキュメントに```@test```が含まれているとテストする
* メソッドのプレフィックスが```test```ならテストする
* ```assertEquals```は値が等しい事をテストする。
* ```assertEquals```で結構いける
* 他にもアサートはある。
* 時間がかかる時は```@group```を検討する

### ○テスト実行
ターミナルで以下実行

```
$ ./vendor/bin/phpunit
PHPUnit 6.0.8 by Sebastian Bergmann and contributors.

.......                                                             7 / 7 (100%)

Time: 188 ms, Memory: 4.00MB

OK (7 tests, 8 assertions)
```


## ■psysh
psyshでデバッグ実行する

### ○シェルスクリプトを使用する

```
$ cd /path/to/my-package
$ ./psysh.php
busyoumono99\MyPackage shell
Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman
>>> $ar = new Arithmetic()
=> busyoumono99\MyPackage\Arithmetic {#162}
>>> show $ar
  >  6| class Arithmetic
     7| {
     8|     /**
     9|      * 足し算
    10|      */
    11|     public function add($x, $y) {
    12|         // eval(\Psy\sh());
    13|         return($x + $y);
    14|     }
    15|
    16|     /**
    17|      * 引き算
    18|      */
    19|     public function subtract($x, $y) {
    20|         return($x - $y);
    21|     }
    22|
    23|     /**
    24|      * 掛け算
    25|      */
    26|     public function multiply($x, $y) {
    27|         return($x * $y);
    28|     }
    29|
    30|     /**
    31|      * 割り算
    32|      */
    33|     public function divide($x, $y) {
    34|         return($x / $y);
    35|     }
    36| }

>>> ls $ar
Class Methods: add, divide, multiply, subtract
>>> $ar->add(5,9)
=> 14
>>> dump $ar
busyoumono99\MyPackage\Arithmetic {#162}
>>> q
Exit:  Goodbye.
Bye.
```

### ○簡単に試す時とか
```
$ ./vendor/bin/psysh
Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman
>>> $a = ["hoge"=>"piyo", "fuga"=>"poyo"]
=> [
     "hoge" => "piyo",
     "fuga" => "poyo",
   ]
>>> json_encode($a)
=> "{"hoge":"piyo","fuga":"poyo"}"
>>> q
Exit:  Goodbye.
```

### ○ブレイクポイントとして利用

以下をブレイクしたい箇所に追加。例えば足し算メソッドに仕込む。

```
eval(\Psy\sh());
```



```
...
    /**
     * 足し算
     */
    public function add($x, $y) {
        eval(\Psy\sh());
        return($x + $y);
    }
...
```

シェルスクリプトで起動してブレイクポイントを発生させる

```
$ ./psysh.php
busyoumono99\MyPackage shell
Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman
>>> $ar = new Arithmetic()
=> busyoumono99\MyPackage\Arithmetic {#162}
>>> $ar->add(5, 13)

Psy Shell v0.8.2 (PHP 7.0.15 — cli) by Justin Hileman  ←　ここで2重にpsyshが実行されている。
>>> ls
Variables: $this, $x, $y
>>> dump $x
5
>>> dump $y
13
>>> ls $this
Class Methods: add, divide, multiply, subtract
>>> dump $this
busyoumono99\MyPackage\Arithmetic {#162}
>>> q
Exit:  Goodbye.
=> 18
>>> q
Exit:  Goodbye.
Bye.
```

```./psysh.php```で無くても```$ php -f index.php```やブラウザアクセス等でも良い。```eval(\Psy\sh());```の箇所まで処理が進めばターミナルが起動してpsyshが開始される。ただ、面倒なので```./psysh.php```がオススメ

### ○主に使うコマンド
自分が現在の所、主に使うコマンド３つ。

```
* ls ： 現在有効な変数の一覧
* ls $obj　：　オブジェクト変数のプロパティ、メソッドとか
* dump　$var　：　変数の中身を表示
* q　：　psyshの終了
```




## ■git
gitは通常にコミット。バージョンで区切るときはタグを```v1.0.0```等として追加する。プレフィックスの```v```は無くてもOKだが付けておく。
その他一般的なバージョンの規則は以下を参考。
[Composer ドキュメント日本語訳 → タグ](https://kohkimakimoto.github.io/getcomposer.org_doc_jp/doc/02-libraries.html)


# ●使い方(利用時)

パッケージを利用する側のcomposer.json

```
"repositories": [
    {
        "type": "vcs",
        "url": "/path/to/my-package",
        "//url": "https://hoge.org/busyoumono99/my-package.git"
    }
],
"require": {
	  "busyoumono99/my-package": "1.*"
}
```

設定後にターミナルでインストール

```
$ composer install
```

元パッケージ側をgitでコミットして、新しくタグ```v1.1.0```を追加すればアップデート出来る

```
$ composer update
```

# ●まとめ
以上で自作パッケージの基本的な部分の作り方、利用の仕方終わり。
何があれば、コメントか編集リクエストお願いします。


# ●参考
* [PackagistとComposerで自作パッケージを使う - きじとら](https://kijtra.com/article/original-library-using-composer-packagist/)
* [PHPのちょっとしたライブラリを作る時の構成やcomposer.jsonなど | kanonjiのブログ](http://kanonji.info/blog/2017/02/08/settings-and-directories-for-small-php-library/)
* [素のPHPでも最低限.envとmonologくらいは使う際の手順 - Qiita](http://qiita.com/zaburo/items/eacde522d36172d6d910)
* [Composer が PSR-4 に対応していた - ngの日記](http://ngyuki.hatenablog.com/entry/2014/01/09/203427)
* [Composerに自分の作ったクラスを追加してみる。 - Qiita](http://qiita.com/ukisoft/items/d89f5f30290556e9f7e6)
* [phpdotenvを使う - Qiita](http://qiita.com/zaburo/items/1dd2337c5f9281f7cc3a)
* [規模別PHPUnitでのテストの書き方いろいろ: Architect Note](http://blog.tojiru.net/article/253157654.html)
* [PHPUnit入門の入門 – Simple IT Life](https://simple-it-life.com/2016/02/25/phpunit/)
* [PHPを「シェル化」する [psy/psysh] - 超PHPerになろう](http://cho-phper.hateblo.jp/entry/2015/11/10/031000)
* [PsySH公式サイト日本語訳 - Qiita](http://qiita.com/rana_kualu/items/99b316f41143411f1385)
* [2015 12 16 PHPのREPL、PsySHのメモ - log](http://log.deprode.net/logs/2015-12-16/)