web-dev-qa-db-ja.com

サードパーティのベストプラクティスPHPクラスベースのライブラリ

私は現在、サードパーティのPHPライブラリを必要とするモジュールに取り組んでいます。これは、本質的に単一のPHPクラスです。通常は、 include /サブディレクトリと追加

_files[] = includes/Foo.php
_

私の.infoファイルに、Drupal 7クラスのオートローダーに$foo = new Foo()を実行させるとその機能を実行させます。

ただし、私はこのモジュールを公開する許可があり、モジュールにライブラリを含めないでください。ライセンスに関する複雑さについてはよく承知していますが、この質問のために無視します。

同様の質問 PHPライブラリを含めるにはどうすればよいですか? ですが、これが私のジレンマに答えるとは本当に思えません。

これはこの質問への答えは基本的に Libraries API を使用すると言いますが、これを使用するすべての単一のモジュールは、alibraries_get_path()を実行してベースパスを取得します(そして、それは利用できません)、その後、いくつかのエラーチェックを使用してrequireまたはincludeを実行します(または実行しません)。すべては次のようなものです:

_if (!class_exists('Foo')) {
  $path = function_exists('libraries_get_path') ?
    libraries_get_path('foo') : 'sites/all/libraries/foo';
  if (!include($path . '/Foo.php')) {
      // handle this error
  }
}
_

この場合、ライブラリAPIは実際には何も実行していません。これを使用する利点は、ユーザーにコピーをダウンロードしてモジュールフォルダー自体に配置するよう求める従来の方法よりもわかりません。そして、モジュール開発者still手動でinclude /でロードを実行する必要があるという問題がまだありますrequire。たとえば、Facebookモジュールは_hook_init_にライブラリをロードするだけで、HTML Purifierモジュールには、ライブラリが必要になるたびにチェックしてロードする内部関数があります。

これは広範囲のプラクティスかもしれませんが、ベストプラクティスのようには見えません。

私のモジュールがイニシアチブを取り、_hook_libraries_info_を宣言して、libraries_load('foo')を使用できるようにする必要がありますか?これも奇妙に見えます。

16
mpdonadio

ライブラリAPIモジュールのブランチ2.xを使用すると、開発者は hook_libraries_info() またはライブラリの.infoファイルを使用して、次の情報を定義できます( libraries.api )を参照してください:

  • ライブラリの依存関係
  • 各依存関係について、ライブラリと互換性のあるバージョン
  • ロードする必要があるファイルのリスト(CSS、JavaScript、またはPHP files)]

ライブラリが必要な場合、ロードする必要のあるファイルのリストを使用して、それらのファイルをロードします。これは、モジュールがCSS、およびdrupal_add_css()またはdrupal_add_js()を使用してJavaScriptファイルをロードする必要がないことを意味します。これは、ライブラリAPIモジュールからすでに行われているためです。依存関係の読み込みは、呼び出し元のモジュールが何もせずに、ライブラリAPIモジュールから実行されるタスクです。

モジュールが行うことはすべて、ライブラリをロードするために次のコードを使用することです。 ( ライブラリAPI 2.xの使用(モジュール開発者として) を参照してください。)

_// Try to load the library and check if that worked.
if (($library = libraries_load($name)) && !empty($library['loaded'])) {
  // Do something with the library here.
}
_

ライブラリが存在するかどうかを検出する必要があるだけの場合、モジュールは次のようなコードを使用する必要があります。

_if (($library = libraries_detect($name)) && !empty($library['installed'])) {
  // The library is installed.
}
else {
  $error = $library['error'];
  $error_message = $library['error message'];
}
_

hook_libraries_info()が返すことができるプロパティの間には、実際には使用されない_'download url'_もあります。ブランチ3.xでも使用されません。おそらくそれは将来的に使用されるか、サードパーティのモジュールがライブラリAPIモジュールにフックして、要求されたが見つからないライブラリをダウンロードする可能性があります。

7
kiamlaluno

適切な量​​の掘り下げを行った後、私はまだベストプラクティスが何であるかについて確信が持てません。 PHPMailer モジュールに触発されて、これをクラスベースのPHPライブラリに提供します:

function foo_registry_files_alter (&$files, $modules)
{
  if (!class_exists('Foo')) {
    $library_path = function_exists('libraries_get_path') ?
      libraries_get_path('foo') : 'sites/all/libraries/foo';

    $files[$library_path . '/Foo.php'] = array(
      'module' => 'foo',
      'weight' => 0,
    );
  }
}

これは hook_registry_files_alter を使用してクラスの存在を確認し、見つからない場合はクラスレジストリにファイルを追加します(files[] = ...モジュールの.infoファイルの行)。すると、foo.phpで定義されたクラスがオートローダーで使用できるようになるため、クラスを使用する前にファイルを明示的にロードする必要はありません。

これは、ライブラリAPIにもソフト要件を作成し、可能な場合はそれを使用します。それ以外の場合は、妥当なデフォルトを使用します。

hook_requirements を介していくつかのチェックを追加して、ファイルが存在すること、オートローダーがクラスを検出すること、バージョンチェックなどを確認することもお勧めします。

Libraries APIのオートロードアプローチが 議論中 が問題キューにあることも注目に値します。

5
mpdonadio

要するに:モジュールを公開する予定で、(サードパーティ)ライブラリがGPLされていない場合は、ライブラリを次のように使用する必要があります。依存関係またはこれらのファイルを手動でダウンロードするようにユーザーに要求します(ただし、.infoファイルからファイルを自動ロードすることはできません)

少し長く:

ライブラリモジュールが必要な理由は、基本的にライセンスです。そのモジュールを使用するかどうかに関係なく、何らかの方法でそのファイルを含めます。

まあ、私はあなたが-module-with-the-moduleのケースのような良い例を見つけられなかったと思います。 SMTP module を確認してください。GPLと同様に、必要なクラスが付属しています。 ( 。info file blob )。

simplehtmldom モジュールも参照してください。モジュールにはファイルのみが含まれ、その他は含まれません。

ライブラリモジュールが便利なのは、必要な場所にファイルをアップロードするようにユーザーに要求できる場合です。ユーザーがそれをsites/all/librariesフォルダーにアップロードするかどうかは明らかではありません。これは、sites/example.com/librariesなどのようになります。ライブラリモジュールは、ディレクトリの検出を行うことで、実際の作業に集中するのに役立ちます。

クライアント用に開発したカスタムモジュールの場合、通常はモジュールフォルダーにファイルを含め、ライブラリの使用に応じてrequire_onceまたは.infoファイルエントリを使用します。

また、ライセンスの問題がライブラリモジュールを使用する唯一の理由ではありません。サードパーティライブラリのリリースサイクルが速く、モジュールの開発が最小限の場合はどうなりますか?モジュールに含める場合は、毎回新しいリリースを作成する必要があります。 7.x-1.0によく似たリリース7.x-1.99は欲しくないでしょう。

2
AyeshK

大きな問題はオートロードにあるようです。

libraries module plus xautoload moduleを使用できます。

次に、独自のモジュールで、

function mymodule_libraries_info() {

  return array(
    'mymodule-test-lib' => array(
      'name' => 'My test library',
      ..
      'xautoload' => function($api) {
        // Register a namespace with PSR-0 root in <library dir>/lib/
        // Note: $api already knows the library directory.
        // Note: We could omit the 'lib', as this is the default value.
        $api->namespaceRoot('XALib\TestNamespace', 'lib');
      },
    ),
  );
}

これについては、ここで詳しく説明します。
xautoload.api.php
$ api引数の詳細

注:独自の「ハンドラー」を作成して、PSR-0またはPEARを超えたエキゾチックなオールドスクールパターンを実装することもできます。それに関して助けが必要な場合は、xautoloadキューに問題を投稿してください。

注:ライブラリの名前空間を登録する方法は複数あります。すべてのリクエストで名前空間を登録する場合は、これが最も簡単です。

2
donquixote