taisablog

taisa's engineer blog

PHP

PHPライブラリをPackagistに登録する方法

投稿日:


PHPのライブラリをPackagistに登録する方法を書いておきます。PackagistはPHPのパッケージリポジトリで、登録しておくとcomposerを使ってプロジェクトへインストールすることができます。ここではとあるプロジェクトをPackagistに登録する前提の流れで進めていきます。

Packagistに登録するプロジェクトを作成する

新規でプロジェクトを作成しcomposer initを実行します。

mkdir amazon-photo-formatter
cd amazon-photo-formatter
composer init

composer initを実行すると色々と聞かれるので順番に進めていきます。まずはパッケージ名が聞かれます。<vendor>にはGitHubのアカウント名を指定し、<name>にはライブラリ名を記載します。ここではtaisa831/amazon-photo-formatterと記載しました。

Package name (/) [taisa831/packagist]:

Descriptionはライブラリについての説明文なので、Format amazon photo file name to amazon photo's format.と書きました。その他についてもサジェストされている内容とするか必要な内容を決めて進めていきます。

Description []:
Author [Masaki Sato , n to skip]:
Minimum Stability []:
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: MIT

次にこのライブラリが依存しているものがあればこの時点で指定することができます(後から手動で記載することも可能)。ここではphpunitを利用するのでrequire-devphpunitを指定しました。

Would you like to define your dependencies (require) interactively [yes]? no
Would you like to define your dev dependencies (require-dev) interactively [yes]?
Search for a package: phpunit
Found 15 packages matching phpunit
   [0] phpunit/phpunit
   [1] phpunit/phpunit-mock-objects Abandoned. Use  instead.
   [2] phpunit/php-token-stream
   [3] phpunit/php-timer
   [4] phpunit/php-text-template
   [5] phpunit/php-file-iterator
   [6] phpunit/php-code-coverage
   [7] symfony/phpunit-bridge
   [8] phpunit/phpunit-selenium
   [9] johnkary/phpunit-speedtrap
  [10] codedungeon/phpunit-result-printer
  [11] jean85/pretty-package-versions
  [12] brianium/paratest
  [13] codeception/stub
  [14] spatie/phpunit-snapshot-assertions
Enter package # to add, or the complete package name if it is not listed: 0
Enter the version constraint to require (or leave blank to use the latest version):
Using version ^7.5 for phpunit/phpunit

そうすることで次のようなcomposer.jsonファイルができあがり、このままgenerateするか、composer installするかを聞かれるのでyesとして進めていきます。実行が終わったらプロジェクト直下にsrctestsディレクトリを作成しておきます。

{
    "name": "taisa831/amazon-photo-formatter",
    "description": "Format amazon photo file name to amazon photo format.",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "taisa",
            "email": "g5.taisa831@gmail.com"
        }
    ],
    "require": {},
    "require-dev": {
        "phpunit/phpunit": "^7.5"
    }
}
Do you confirm generation [yes]? yes
Would you like to install dependencies now [yes]? yes
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 28 installs, 0 updates, 0 removals
  - Installing sebastian/version (2.0.1): Loading from cache
  - Installing sebastian/resource-operations (2.0.1): Loading from cache
  - Installing sebastian/recursion-context (3.0.0): Loading from cache
  - Installing sebastian/object-reflector (1.1.1): Loading from cache
  - Installing sebastian/object-enumerator (3.0.3): Loading from cache
  - Installing sebastian/global-state (2.0.0): Loading from cache
  - Installing sebastian/exporter (3.1.0): Loading from cache
  - Installing sebastian/environment (4.1.0): Loading from cache
  - Installing sebastian/diff (3.0.2): Loading from cache
  - Installing sebastian/comparator (3.0.2): Loading from cache
  - Installing phpunit/php-timer (2.1.1): Loading from cache
  - Installing phpunit/php-text-template (1.2.1): Loading from cache
  - Installing phpunit/php-file-iterator (2.0.2): Loading from cache
  - Installing theseer/tokenizer (1.1.0): Loading from cache
  - Installing sebastian/code-unit-reverse-lookup (1.0.1): Loading from cache
  - Installing phpunit/php-token-stream (3.0.1): Loading from cache
  - Installing phpunit/php-code-coverage (6.1.4): Loading from cache
  - Installing doctrine/instantiator (1.1.0): Loading from cache
  - Installing symfony/polyfill-ctype (v1.10.0): Loading from cache
  - Installing webmozart/assert (1.4.0): Loading from cache
  - Installing phpdocumentor/reflection-common (1.0.1): Loading from cache
  - Installing phpdocumentor/type-resolver (0.4.0): Loading from cache
  - Installing phpdocumentor/reflection-docblock (4.3.0): Loading from cache
  - Installing phpspec/prophecy (1.8.0): Loading from cache
  - Installing phar-io/version (2.0.1): Loading from cache
  - Installing phar-io/manifest (1.0.3): Loading from cache
  - Installing myclabs/deep-copy (1.8.1): Loading from cache
  - Installing phpunit/phpunit (7.5.7): Downloading (100%)
sebastian/global-state suggests installing ext-uopz (*)
phpunit/php-code-coverage suggests installing ext-xdebug (^2.6.0)
phpunit/phpunit suggests installing phpunit/php-invoker (^2.0)
phpunit/phpunit suggests installing ext-xdebug (*)
Writing lock file
Generating autoload files

登録するライブラリを作成する

ここまででプロジェクトの形ができあがったのでsrc配下にソースファイルを作成します。今回は簡単なサンプルプログラムとしています。

.
├── composer.json
├── composer.lock
├── package-lock.json
├── vendor
├── src
└── tests
setCurrentDir($currentDir);
    }
    public function format()
    {
        $this->createFormatDir();
        $this->formatPictures();
    }
    public function createFormatDir()
    {
        if (file_exists('format') === false) {
            mkdir('format');
        }
    }
    /**
     * @throws \Exception
     */
    public function formatPictures()
    {
        foreach(glob($this->getCurrentDir() . '/{*.jpeg,*.jpg}', GLOB_BRACE) as $fileName) {
            if (is_file($fileName) === false) continue;
            $photoImg = file_get_contents($fileName);
            $ext = substr($fileName, strrpos($fileName, '.') + 1);
            $exif = @exif_read_data($fileName);
            $dateTime = new \DateTime($exif['DateTimeOriginal']);
            $formatFileName = $dateTime->format('Y-m-d_H-i-s');
            file_put_contents('./format/' . $formatFileName . '.' . $ext, $photoImg);
        }
    }
    /**
     * @return mixed
     */
    public function getCurrentDir()
    {
        return $this->currentDir;
    }
    /**
     * @param mixed $currentDir
     */
    public function setCurrentDir($currentDir)
    {
        $this->currentDir = $currentDir;
    }
}

unittestを作成する

続いて、`src`配下に先程作成したソースのテストを書いていきます。他の依存ライブラリを利用している場合は`bootstrap.php`ファイルも作成しておきます。

getMockBuilder(AmazonPhotoFormatter::class)
            ->setConstructorArgs([$dir])
            ->setMethods(null)
            ->getMock();
        $currentDir = $amazonPhotoFormatter->getCurrentDir();
        $this->assertEquals($dir, $currentDir);
    }
    public function test_format()
    {
        $amazonPhotoFormatter = $this->createPartialMock(AmazonPhotoFormatter::class, ['createFormatDir', 'formatPictures']);
        $amazonPhotoFormatter->expects($this->once())->method('createFormatDir');
        $amazonPhotoFormatter->expects($this->once())->method('formatPictures');
        $amazonPhotoFormatter->format();
    }
}

`bootstrap.php`を作成する場合はこんな感じ

<?php
error_reporting(E_ALL | E_STRICT);
require_once __DIR__ . '/../vendor/autoload.php';

これで`tests`配下で以下のコマンドを実行するとテストがいくつか実行されます。

../vendor/bin/phpunit AmazonPhotoFormatterTest.php
PHPUnit 7.5.7 by Sebastian Bergmann and contributors.
...                                                                 3 / 3 (100%)
Time: 51 ms, Memory: 4.00 MB
OK (3 tests, 3 assertions)

`phpunit.xml.dist`ファイルをプロジェクト直下に置いておくとプロジェクト直下で次のコマンドでも実行可能になります。

vendor/bin/phpunit
PHPUnit 7.5.7 by Sebastian Bergmann and contributors.
...                                                                 3 / 3 (100%)
Time: 25 ms, Memory: 4.00 MB
OK (3 tests, 3 assertions)


    
        
            ./tests/
        
    
    
        
            ./src/
        
    

Travis CIと連携する

Travis CIとGitHubのリポジトリを連携させ、以下のような.travis.ymlを作成しプロジェクト直下に配置することでgit pushした際にテストが実行されるようになります。

language: php
php:
  - 7.3
before_script:
  - composer self-update
  - composer install
script:
  - vendor/bin/phpunit

Packagistに登録する

作成したプロジェクトを自分のGitHubへアップしたら、Packagistへ登録をします。packagistにGitHubアカウントでログインした後、Submit 画面へ進み、登録したいリポジトリのURLを入力すると登録することができます。

GitHubとPackagistを連携する

最後にGitHubにプッシュしたらPackagistも自動的に更新するように連携しておきます。連携は、GitHubリポジトリのSettings>Webhooksから行うことができます。PackagistのプロフィールからAPI Tokenを取得しておき、GitHubのWebhooksへ次のように登録します。

  • Payload URL:https://packagist.org/api/github?username=[GitHubのユーザ名]
  • Content type:application/json
  • Secret:PackagistのAPI Token

ライブラリを使ってプロジェクトを作成してみる

ここまでで一通りの登録が完了したので、実際にプロジェクトから呼び出してみます。新規でプロジェクトを作成するには以下のコマンドを実行します。プロジェクト名の後ろにdev-master(masterブランチ)やGitHubのタグを指定することでバージョンを指定することが可能です。また、composer.jsonにライブラリ名とバージョンを記載してcomposer installして利用することも可能です。

composer create-project taisa831/amazon-photo-formatter project-name dev-master
composer create-project taisa831/amazon-photo-formatter project-name v1.0.0
{
    "name": "masakisato/testprj",
    "authors": [
        {
            "name": "taisa",
            "email": "g5.taisa831@gmail.com"
        }
    ],
    "require": {
            "taisa831/amazon-photo-formatter": "1.0.0"
    }
}
$ composer install
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing taisa831/amazon-photo-formatter (v1.0.0): Loading from cache
Writing lock file
Generating autoload files

参考

Packagistに登録するのはもう怖くない

-PHP

執筆者:

関連記事

PHPUnitのモックオブジェクトの使い方を仕組みから理解する

前回はPHPUnitのメイン処理を確認しました。今回はPHPUnitデフォルトのモックオブジェクトの仕組みを確認してみます。公式ドキュメントでは、第9章 テストダブルが該当箇所となります。 PHPUnitのモックオブジェクトについて PHPUnitは以下のような構成ですが、その中の「phpunit-mock-objects」がPHPUnitデフォルトのモックライブラリとなります。 phpunitphp-code-coveragephp-file-iteratorphp-text-templatephp-timerphp-token-streamphpunitphpunit-mock-objects ← これ 構成 PHPUnitモックオブジェクトのファイル構成は以下の通りです。 ├── Builder │   ├── Identity.php │   ├── InvocationMocker.php │   ├── Match.php │   ├── MethodNameMatch.php │   ├── Namespace.php │   ├── ParametersMatch.php │   └── Stub.php ├── Exception │   ├── BadMethodCallException.php │   ├── Exception.php │   └── RuntimeException.php ├── Generator │   ├── deprecation.tpl.dist │   ├── 省略… ├── Generator.php ├── Invocation │   ├── Object.php │   └── Static.php ├── Invocation.php ├── InvocationMocker.php ├── Invokable.php ├── Matcher │   ├── AnyInvokedCount.php │   ├── AnyParameters.php │   ├── ConsecutiveParameters.php │   ├── Invocation.php │   ├── InvokedAtIndex.php │   ├── InvokedAtLeastCount.php │   ├── InvokedAtLeastOnce.php │   ├── InvokedAtMostCount.php │   ├── InvokedCount.php │   ├── InvokedRecorder.php │   …

PHPUnitの使い方を仕組みから理解する

ここ数年仕事ではPHPを使って開発をしていますが、最近品質について考える機会が増えたこともあり、これを機にPHPUnitと周辺のモジュールの仕組みを理解してより楽にテストができるようにしたいと思います。 PHPUnitは? Sebastian Bergmann Created PHPUnit. Co-Founded thePHP.cc. Helps PHP developers build better software. PHPUnitの作者は、Sebastian Bergmannという方でthePHP.ccのファウンダーのようです。関連情報は以下にて確認してみてください。 TwitterアカウントPHPUnit GithubPHPUnitマニュアル PHPUnitの構成 PHPUnitは以下のような構成になっています。 phpunit php-code-coverage php-file-iterator php-text-template php-timer php-token-stream phpunit phpunit-mock-objects これらはGitHub上ではそれぞれ別々のリポジトリに分かれていますが、phpunitが本体でそれ以外はデフォルトの関連ライブラリという位置づけになるかと思います。 PHPUnitのsrc構成 モックオブジェクトなどを除いたphpunitだけのパッケージとクラス構成を見てみるとこんな感じになります。 ├── Exception.php ├── Extensions │   ├── GroupTestSuite.php │   ├── PhptTestCase.php │   ├── PhptTestSuite.php │   ├── RepeatedTest.php │   ├── TestDecorator.php │   └── TicketListener.php ├── ForwardCompatibility │   └── TestCase.php ├── Framework │   ├── Assert │   │   └── Functions.php │   ├── Assert.php │   ├── AssertionFailedError.php │   ├── BaseTestListener.php │   ├── CodeCoverageException.php │   ├── Constraint │   │   ├── And.php │   │   ├── ArrayHasKey.php │   │   ├── ArraySubset.php │   │   ├── Attribute.php │   │   …

PHPの empty, isset, is_null の違いをしっかり理解する

PHPの isset、empty、is_null をしっかり理解して使おうと思い整理してみました。既にこのような記事「PHP isset, empty, is_null の違い早見表」もあるのでここではこれより少し踏み込んだところまで書いてみます。 empty, isset, is_nullの違い早見表 値 if ($var) empty isset is_null $var = 1 true false true false $var = array(1) true false true false $var = “” false true true false $var = “0” false true true false $var = 0 false true true false $var = array() false true true false $var = false false true true false $var = NULL; false true false true $var false true false true まず表ですが、順番を理解しやすい形に変えてみました。下記のように赤と青のグループで分けて考えておくと理解しやすいです。これをみると「if ($var)とempty」、「issetとis_null」が対になっているのがわかります。 感覚的には、if ($var)は値がありそうだなと思うものがtrueになり、emptyも値がなさそうだな思うものがtrueになる感じがします。issetは、何かしら値がセットされてばtrue(つまり値がfalseでも結果はtrue)、is_nullは値がnullであればtrueということになります。 実際の挙動の動作確認についてはPHPUnitを使ってテストしたものをGitHubにあげているので合わせて確認してみてください。https://github.com/taisa831/AimaiPHP empty, isset, is_null の Notice や Error 出力早見表 次に、PHPのerror_reportingをE_ALLにした場合に、indexのない配列にアクセスした場合やオブジェクトが空の変数や関数にアクセスした場合の挙動をまとめてみました。 値 if ($var) empty isset is_null $var = []; …

GitLabのprivateなPHPライブラリをcomposer installするには

社内ツールでprivateなリポジトリに置いておきたいけど、いろんなプロジェクトでcomposer installしたいというケースは以外とあるんじゃないかと思います。そういう時は、composer.jsonにrepositoriesを追加して、GitLab(ここではGitLabとしています)のURLを指定するとインストールが可能になります。しかしそのままだとpublicなリポジトリしかだめですが、privateなリポジトリであれば、GitLabからPersonal AcessTokenを取得して、composer config –global –auth gitlab-token.gitlab.com [ACESS_TOKEN]を実行すればcomposer installが可能になります。 { “name”: “taisa831/sample-framework-app”, “license”: “MIT”, “authors”: [ { “name”: “taisa”, “email”: “g5.taisa831@gmail.com” } ], “require”: { “taisa831/sample-framework”: “dev-master” }, “repositories”: [ { “type”: “vcs”, “url”: “git@gitlab.com:taisa831/sample-framework.git” } ] } では、Webフレームワークをprivateなリポジトリに公開して利用するところまでをやってみます。 (今回は便宜上publicにしています) 事前準備 ここではサンプルのWebフレームワーク(実装なし)をプロジェクトにインストールできるようにすることにします。リポジトリは2つで、フレームワークの実態であるsample-frameworkとフレームワークの雛形となるsample-framework-appを用意しておきました。それぞれの構成は以下の通りです。 https://gitlab.com/taisa831/sample-framework.git # フレームワークの実体 . ├── README.md ├── composer.json ├── src ├── tests └── vendor https://gitlab.com/taisa831/sample-framework-app.git # フレームワークの雛形 . ├── README.md ├── composer.json ├── composer.lock ├── config ├── controllers ├── models ├── public │   └── index.php ├── routes ├── tests └── views このsample-framework-appのcomposer.jsonには上記でも記載した内容が書かれています。requireにtaisa831/sample-frameworkを指定し、repositoriesにGitLabのURLを指定することで探してくれるようになります。 { “name”: “taisa831/sample-framework-app”, “license”: “MIT”, “authors”: [ { “name”: “taisa”, “email”: “g5.taisa831@gmail.com” } ], “require”: { …

PHPによるDBUnit超入門

例えば簡単なWebサービスでMVCのフレームワークを使っていてビジネスロジックを書く用にコントローラとモデルの間にサービス層を追加して開発している場合、コントローラやサービスはモックを駆使しながらテストを書いていくことができます。ただ、例えばフレームワークをバージョンアップしたい、PHPをバージョンアップしたいなどの場合に既存のモデル層に影響がないかをテストで確認したいなんてことがあります。そのような場合には、DBUnitを導入してみてもいいかもしれません。ということで本記事ではPHPによるDBUnitの使い方を書いてみます。 事前情報 今phpunit/dbunitをインストールしようとすると以下の文言が出力されます。詳しくはこちらのissueに書いてありますが、どうもSebastianさんはdbunitのメンテナンスをやめるようです。ただそれを受けてforkしたプロジェクトが出てきているようなので大丈夫かと思います。今回はSebastianさんの純正dbunitを使っています。 Package phpunit/dbunit is abandoned, you should avoid using it. No replacement was suggested また、DBUnitに関する詳しい情報はマニュアルにありますのでご確認ください。https://phpunit.de/manual/6.5/ja/database.html#database.implementing-getdataset 作成したサンプルプロジェクト 今回は、dbunitの確認だけをしたいので、dietcakeのmessage-boardというサンプルプロジェクトを利用しました。今回作成したDBUnit用のサンプルプロジェクトは GitHub からダウンロードして確認できます。 git clone git@github.com:taisa831/phpunit-dbunit-sample.git cd phpunit-dbunit-sample composer install # mysqlサーバを立て`app/config/sql/board.sql`を実行する(SQLは下記に記載しています) # テスト実行 ./vendor/bin/phpunit PHPUnit 7.5.8 by Sebastian Bergmann and contributors. ….. 5 / 5 (100%) Time: 207 ms, Memory: 4.00 MB OK (5 tests, 14 assertions) アプリ用のDDLです。開発用DBとは違うのでboard_dbunitというテーブル名にしています。 — — — Create database — CREATE DATABASE IF NOT EXISTS board_dbunit; GRANT SELECT, INSERT, UPDATE, DELETE ON board.* TO board_root@localhost IDENTIFIED BY ‘board_root’; FLUSH PRIVILEGES; — — Create tables — USE board_dbunit; CREATE TABLE IF NOT EXISTS thread ( id INT UNSIGNED …