発行元

Publisherライブラリは、堅牢な検出とエラーチェックを使用してプロジェクト内のファイルをコピーする手段を提供します。

ライブラリの読み込み

Publisherインスタンスは、そのソースと宛先に固有であるため、このライブラリはServices経由では使用できませんが、直接インスタンス化または拡張する必要があります。例:

<?php

$publisher = new \CodeIgniter\Publisher\Publisher();

概念と使用方法

Publisherは、バックエンドフレームワークで作業する場合のいくつかの一般的な問題を解決します。

  • バージョン依存関係を持つプロジェクトアセットをどのように維持しますか?

  • ウェブアクセスが必要なアップロードやその他の「動的」ファイルをどのように管理しますか?

  • フレームワークまたはモジュールが変更された場合、プロジェクトをどのように更新しますか?

  • コンポーネントが既存のプロジェクトに新しいコンテンツをどのように注入できますか?

最も基本的なレベルでは、公開はファイルまたはファイルをプロジェクトにコピーすることに相当します。PublisherFileCollectionを拡張して、流暢なスタイルのコマンドチェーンを使用して入力ファイルを読み取り、フィルタリング、処理し、次にそれらをターゲットの宛先にコピーまたはマージします。Publisherは、コントローラーまたはその他のコンポーネントでオンデマンドで使用できます。または、クラスを拡張し、spark publishを使用してその検出を活用することで、公開を準備できます。

オンデマンド

クラスの新しいインスタンスをインスタンス化することで、Publisherに直接アクセスします。

<?php

$publisher = new \CodeIgniter\Publisher\Publisher();

デフォルトでは、ソースと宛先はそれぞれROOTPATHFCPATHに設定され、Publisherはプロジェクトから任意のファイルを取得してウェブアクセス可能にすることができます。あるいは、コンストラクターに新しいソース、またはソースと宛先を渡すこともできます。

<?php

use CodeIgniter\Publisher\Publisher;

$vendorPublisher = new Publisher(ROOTPATH . 'vendor');
$filterPublisher = new Publisher('/path/to/module/Filters', APPPATH . 'Filters');

// Once the source and destination are set you may start adding relative input files
$frameworkPublisher = new Publisher(ROOTPATH . 'vendor/codeigniter4/codeigniter4');

// All "path" commands are relative to $source
$frameworkPublisher->addPath('app/Config/Cookie.php');

// You may also add from outside the source, but the files will not be merged into subdirectories
$frameworkPublisher->addFiles([
    '/opt/mail/susan',
    '/opt/mail/ubuntu',
]);
$frameworkPublisher->addDirectory(SUPPORTPATH . 'Images');

すべてのファイルが準備できたら、出力コマンド(**copy()**または**merge()**)のいずれかを使用して、準備されたファイルを宛先に処理します。

<?php

// Place all files into $destination
$frameworkPublisher->copy();

// Place all files into $destination, overwriting existing files
$frameworkPublisher->copy(true);

// Place files into their relative $destination directories, overwriting and saving the boolean result
$result = $frameworkPublisher->merge(true);

使用可能なメソッドの完全な説明については、ライブラリリファレンスを参照してください。

自動化と検出

アプリケーションのデプロイまたは保守の一部として、定期的な公開タスクを含めることができます。Publisherは強力なAutoloaderを活用して、公開のために準備された子クラスを探します。

<?php

use CodeIgniter\CLI\CLI;
use CodeIgniter\Publisher\Publisher;

foreach (Publisher::discover() as $publisher) {
    $result = $publisher->publish();

    if ($result === false) {
        CLI::error(get_class($publisher) . ' failed to publish!', 'red');
    }
}

デフォルトでは、discover()はすべての名前空間で「Publishers」ディレクトリを検索しますが、別のディレクトリを指定することもでき、その場合は見つかった子クラスを返します。

<?php

use CodeIgniter\Publisher\Publisher;

$memePublishers = Publisher::discover('CatGIFs');

ほとんどの場合、独自の検出を処理する必要はありません。提供されている「publish」コマンドを使用してください。

php spark publish

デフォルトでは、クラス拡張publish()$sourceからすべてのファイルを追加し、それらを宛先にマージし、衝突時には上書きします。

セキュリティ

モジュールがプロジェクトに悪意のあるコードを注入するのを防ぐために、Publisherには、宛先として許可されるディレクトリとファイルパターンを定義する設定ファイルが含まれています。デフォルトでは、ファイルはプロジェクトにのみ公開できます(ファイルシステムの残りの部分へのアクセスを防ぐため)、そして**public/**フォルダ(FCPATH)は次の拡張子を持つファイルのみを受け取ります。

  • ウェブアセット:css、scss、js、map

  • 実行不可のウェブファイル:htm、html、xml、json、webmanifest

  • フォント:ttf、eot、woff、woff2

  • 画像:gif、jpg、jpeg、tif、tiff、png、webp、bmp、ico、svg

プロジェクトのセキュリティを追加または調整する必要がある場合は、**app/Config/Publisher.php**内のConfig\Publisher$restrictionsプロパティを変更してください。

いくつか使用例とその実装を以下に示します。公開を開始するのに役立ちます。

ファイル同期例

ホームページに「今日の写真」画像を表示したいとします。毎日の写真フィードがありますが、プロジェクトの参照可能な場所にある**public/images/daily_photo.jpg**に実際のファイルを取得する必要があります。カスタムコマンドを設定して、毎日実行することで、これを処理できます。

<?php

namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\Publisher\Publisher;
use Throwable;

class DailyPhoto extends BaseCommand
{
    protected $group       = 'Publication';
    protected $name        = 'publish:daily';
    protected $description = 'Publishes the latest daily photo to the homepage.';

    public function run(array $params)
    {
        $publisher = new Publisher('/path/to/photos/', FCPATH . 'assets/images');

        try {
            $publisher->addPath('daily_photo.jpg')->copy(true); // `true` to enable overwrites
        } catch (Throwable $e) {
            $this->showError($e);
        }
    }
}

これでspark publish:dailyを実行すると、ホームページの画像が最新の状態に保たれます。写真が外部APIから取得されている場合はどうでしょうか?addPath()の代わりにaddUri()を使用して、リモートリソースをダウンロードして公開することができます。

<?php

$publisher->addUri('https://example.com/feeds/daily_photo.jpg')->copy(true);

アセット依存関係の例

フロントエンドライブラリ「Bootstrap」をプロジェクトに統合したいが、頻繁なアップデートのために最新の状態を維持するのが面倒です。プロジェクトでPublisherを拡張して、プロジェクトに公開定義を作成することで、フロントエンドアセットを同期できます。そのため、**app/Publishers/BootstrapPublisher.php**は次のようになるかもしれません。

<?php

namespace App\Publishers;

use CodeIgniter\Publisher\Publisher;

class BootstrapPublisher extends Publisher
{
    /**
     * Tell Publisher where to get the files.
     * Since we will use Composer to download
     * them we point to the "vendor" directory.
     *
     * @var string
     */
    protected $source = VENDORPATH . 'twbs/bootstrap/';

    /**
     * FCPATH is always the default destination,
     * but we may want them to go in a sub-folder
     * to keep things organized.
     *
     * @var string
     */
    protected $destination = FCPATH . 'bootstrap';

    /**
     * Use the "publish" method to indicate that this
     * class is ready to be discovered and automated.
     */
    public function publish(): bool
    {
        return $this
            // Add all the files relative to $source
            ->addPath('dist')

            // Indicate we only want the minimized versions
            ->retainPattern('*.min.*')

            // Merge-and-replace to retain the original directory structure
            ->merge(true);
    }
}

注記

ディレクトリ$destinationは、コマンドを実行する前に作成する必要があります。

Composer経由で依存関係を追加し、spark publishを呼び出して公開を実行します。

composer require twbs/bootstrap
php spark publish

…すると、次のようになります。

public/.htaccess
public/favicon.ico
public/index.php
public/robots.txt
public/
    bootstrap/
        css/
            bootstrap.min.css
            bootstrap-utilities.min.css.map
            bootstrap-grid.min.css
            bootstrap.rtl.min.css
            bootstrap.min.css.map
            bootstrap-reboot.min.css
            bootstrap-utilities.min.css
            bootstrap-reboot.rtl.min.css
            bootstrap-grid.min.css.map
        js/
            bootstrap.esm.min.js
            bootstrap.bundle.min.js.map
            bootstrap.bundle.min.js
            bootstrap.min.js
            bootstrap.esm.min.js.map
            bootstrap.min.js.map

モジュール展開例

人気の認証モジュールを使用する開発者が、マイグレーション、コントローラー、モデルのデフォルト動作を拡張できるようにしたいとします。アプリケーションで使用するためにこれらのコンポーネントを注入する独自のモジュール「publish」コマンドを作成できます。

<?php

namespace Math\Auth\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\Publisher\Publisher;
use Throwable;

class AuthPublish extends BaseCommand
{
    protected $group       = 'Auth';
    protected $name        = 'auth:publish';
    protected $description = 'Publish Auth components into the current application.';

    public function run(array $params)
    {
        // Use the Autoloader to figure out the module path
        $source = service('autoloader')->getNamespace('Math\\Auth')[0];

        $publisher = new Publisher($source, APPPATH);

        try {
            // Add only the desired components
            $publisher->addPaths([
                'Controllers',
                'Database/Migrations',
                'Models',
            ])->merge(false); // Be careful not to overwrite anything
        } catch (Throwable $e) {
            $this->showError($e);

            return;
        }

        // If publication succeeded then update namespaces
        foreach ($publisher->getPublished() as $file) {
            // Replace the namespace
            $contents = file_get_contents($file);
            $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, $contents);
            file_put_contents($file, $contents);
        }
    }
}

これで、モジュールユーザーがphp spark auth:publishを実行すると、プロジェクトに以下が追加されます。

app/Controllers/AuthController.php
app/Database/Migrations/2017-11-20-223112_create_auth_tables.php.php
app/Models/LoginModel.php
app/Models/UserModel.php

ライブラリリファレンス

注記

PublisherFileCollectionの拡張なので、ファイルの読み取りとフィルタリングのためのすべてのメソッドにアクセスできます。

サポートメソッド

[static] discover(string $directory = ‘Publishers’): Publisher[]

指定された名前空間ディレクトリ内のすべてのPublisherを検出し、返します。たとえば、**app/Publishers/FrameworkPublisher.php**と**myModule/src/Publishers/AssetPublisher.php**の両方が存在し、Publisherを拡張している場合、Publisher::discover()はそれぞれのインスタンスを返します。

publish(): bool

完全な入力-処理-出力チェーンを処理します。デフォルトでは、addPath($source)merge(true)を呼び出すことと同等ですが、子クラスでは通常、独自のインプリメンテーションを提供します。spark publishを実行すると、検出されたすべてのPublisherでpublish()が呼び出されます。成功または失敗を返します。

getScratch(): string

一時ワークスペースを返し、必要に応じて作成します。一部の操作では、ファイルをステージングし、変更するために中間ストレージを使用します。これは、一時的な書き込み可能なディレクトリのパスを提供し、必要に応じて使用できます。

getErrors(): array<string, Throwable>

最後の書き込み操作からのエラーを返します。配列のキーはエラーの原因となったファイルであり、値はキャッチされたThrowableです。Throwableに対してgetMessage()を使用すると、エラーメッセージを取得できます。

addPath(string $path, bool $recursive = true)

相対パスで示されたすべてのファイルを追加します。パスは、$sourceに対する実際のファイルまたはディレクトリへの参照です。相対パスがディレクトリを解決する場合、$recursiveにはサブディレクトリが含まれます。

addPaths(array $paths, bool $recursive = true)

相対パスで示されたすべてのファイルを追加します。パスは、$sourceに対する実際のファイルまたはディレクトリへの参照です。相対パスがディレクトリを解決する場合、$recursiveにはサブディレクトリが含まれます。

addUri(string $uri)

CURLRequestを使用してURIの内容をスクラッチワークスペースにダウンロードし、結果のファイルをリストに追加します。

addUris(array $uris)

CURLRequestを使用してURIの内容をスクラッチワークスペースにダウンロードし、結果のファイルをリストに追加します。

注記

行われるCURLリクエストは単純なGETであり、ファイルの内容にはレスポンスボディが使用されます。一部のリモートファイルは、適切に処理するためにカスタムリクエストが必要になる場合があります。

ファイルの出力

wipe()

$destinationからすべてのファイル、ディレクトリ、およびサブディレクトリを削除します。

重要

賢く使いましょう。

copy(bool $replace = true): bool

すべてのファイルを$destinationにコピーします。ディレクトリ構造は再作成されません。そのため、現在のリストのすべてのファイルは同じ宛先ディレクトリに配置されます。$replaceを使用すると、既に存在するファイルがある場合にファイルが上書きされます。成功または失敗を返します。getPublished()getErrors()を使用して、失敗のトラブルシューティングを行います。重複したbasenameの衝突(例:同じ名前のファイルが複数ある場合)に注意してください。

<?php

use CodeIgniter\Publisher\Publisher;

$publisher = new Publisher('/home/source', '/home/destination');
$publisher->addPaths([
    'pencil/lead.png',
    'metal/lead.png',
]);

// This is bad! Only one file will remain at /home/destination/lead.png
$publisher->copy(true);

merge(bool $replace = true): bool

すべてのファイルを適切な相対サブディレクトリ内の$destinationにコピーします。$sourceと一致するファイルは、$destinationの同等のディレクトリに配置され、「ミラー」または「rsync」操作が効果的に作成されます。$replaceを使用すると、既に存在するファイルがある場合にファイルが上書きされます。ディレクトリがマージされるため、これは宛先内の他のファイルには影響しません。成功または失敗を返します。getPublished()getErrors()を使用して、失敗のトラブルシューティングを行います。

<?php

use CodeIgniter\Publisher\Publisher;

$publisher = new Publisher('/home/source', '/home/destination');
$publisher->addPaths([
    'pencil/lead.png',
    'metal/lead.png',
]);

// Results in "/home/destination/pencil/lead.png" and "/home/destination/metal/lead.png"
$publisher->merge();

ファイルの修正

replace(string $file, array $replaces): bool

バージョン4.3.0の新機能。

$fileの内容を置き換えます。2番目のパラメーター$replaces配列は、検索文字列をキーとして、置換文字列を値として指定します。

<?php

use CodeIgniter\Publisher\Publisher;

$source    = service('autoloader')->getNamespace('CodeIgniter\\Shield')[0];
$publisher = new Publisher($source, APPPATH);

$file = APPPATH . 'Config/Auth.php';

$publisher->replace(
    $file,
    [
        'use CodeIgniter\Config\BaseConfig;' . "\n" => '',
        'class App extends BaseConfig'              => 'class App extends \Some\Package\SomeConfig',
    ]
);

addLineAfter(string $file, string $line, string $after): bool

バージョン4.3.0の新機能。

特定の文字列$afterを含む行の後に$lineを追加します。

<?php

use CodeIgniter\Publisher\Publisher;

$source    = service('autoloader')->getNamespace('CodeIgniter\\Shield')[0];
$publisher = new Publisher($source, APPPATH);

$file = APPPATH . 'Config/App.php';

$publisher->addLineAfter(
    $file,
    '    public int $myOwnConfig = 1000;', // Adds this line
    'public bool $CSPEnabled = false;'     // After this line
);

addLineBefore(string $file, string $line, string $after): bool

バージョン4.3.0の新機能。

特定の文字列$afterを含む行の前に$lineを追加します。

<?php

use CodeIgniter\Publisher\Publisher;

$source    = service('autoloader')->getNamespace('CodeIgniter\\Shield')[0];
$publisher = new Publisher($source, APPPATH);

$file = APPPATH . 'Config/App.php';

$publisher->addLineBefore(
    $file,
    '    public int $myOwnConfig = 1000;', // Add this line
    'public bool $CSPEnabled = false;'     // Before this line
);