퍼블리셔
퍼블리셔 라이브러리는 강력한 감지 및 오류 검사를 사용하여 프로젝트 내에서 파일을 복사하는 수단을 제공합니다.
라이브러리 로드하기
퍼블리셔 인스턴스는 소스와 목적지에 특화되어 있으므로 이 라이브러리는 Services를 통해 사용할 수 없으며, 직접 인스턴스화하거나 확장해야 합니다. 예:
<?php
$publisher = new \CodeIgniter\Publisher\Publisher();
개념 및 사용법
Publisher는 백엔드 프레임워크 내에서 작업할 때 발생하는 몇 가지 일반적인 문제를 해결합니다.
버전 종속성이 있는 프로젝트 에셋을 어떻게 유지 관리하나요?
웹에서 접근 가능해야 하는 업로드 및 기타 “동적” 파일을 어떻게 관리하나요?
프레임워크나 모듈이 변경될 때 프로젝트를 어떻게 업데이트할 수 있나요?
컴포넌트가 기존 프로젝트에 새 콘텐츠를 어떻게 주입할 수 있나요?
가장 기본적으로 퍼블리싱은 파일을 프로젝트에 복사하는 것입니다. Publisher는 FileCollection을 확장하여 입력 파일을 읽고, 필터링하고, 처리하는 유창한 스타일의 명령 체이닝을 구현한 다음 대상 목적지에 복사하거나 병합합니다. 컨트롤러 또는 다른 컴포넌트에서 요청 시 Publisher를 사용하거나, 클래스를 확장하고 spark publish를 통한 자동 검색을 활용하여 퍼블리케이션을 준비할 수 있습니다.
온 디맨드
클래스의 새 인스턴스를 생성하여 Publisher에 직접 접근하세요.
<?php
$publisher = new \CodeIgniter\Publisher\Publisher();
기본적으로 소스와 목적지는 각각 ROOTPATH와 FCPATH로 설정되어 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($publisher::class . ' failed to publish!', 'red');
}
}
기본적으로 discover()는 모든 네임스페이스에서 “Publishers” 디렉토리를 검색하지만, 다른 디렉토리를 지정하면 발견된 모든 자식 클래스를 반환합니다.
<?php
use CodeIgniter\Publisher\Publisher;
$memePublishers = Publisher::discover('CatGIFs');
대부분의 경우 자체 검색을 처리할 필요가 없으며, 제공된 “publish” 명령을 사용하세요.
php spark publish
기본적으로 클래스 확장 시 publish()는 $source의 모든 파일을 추가하고 목적지에 병합하며, 충돌 시 덮어씁니다.
특정 네임스페이스에서의 검색
Added in version 4.6.0.
v4.6.0부터 특정 네임스페이스를 스캔할 수도 있습니다. 이는 스캔할 파일 수를 줄일 뿐만 아니라 퍼블리셔를 다시 실행해야 하는 필요성도 없애줍니다. discover() 메서드의 두 번째 매개변수에 원하는 루트 네임스페이스를 지정하기만 하면 됩니다.
<?php
use CodeIgniter\Publisher\Publisher;
$memePublishers = Publisher::discover('Publishers', 'Namespace\Vendor\Package');
지정된 네임스페이스는 CodeIgniter에서 알고 있어야 합니다. “spark namespaces” 명령을 사용하여 모든 네임스페이스 목록을 확인할 수 있습니다.
php spark namespaces
“publish” 명령은 라이브러리에서 오는 퍼블리셔를 검색할 때 네임스페이스를 정의하는 --namespace 옵션도 제공합니다.
php spark publish --namespace Namespace\Vendor\Package
보안
모듈이 프로젝트에 악성 코드를 주입하는 것을 방지하기 위해 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
모듈 배포 예제
인기 있는 인증 모듈을 사용하는 개발자들이 Migration, Controller, Model의 기본 동작을 확장할 수 있게 하고 싶습니다. 이러한 컴포넌트를 애플리케이션에 주입하기 위한 모듈 “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
라이브러리 레퍼런스
참고
Publisher는 FileCollection의 확장이므로 파일을 읽고 필터링하는 모든 메서드에 접근할 수 있습니다.
지원 메서드
[static] discover(string $directory = ‘Publishers’): Publisher[]
지정된 네임스페이스 디렉토리에서 모든 퍼블리셔를 검색하고 반환합니다. 예를 들어, app/Publishers/FrameworkPublisher.php와 myModule/src/Publishers/AssetPublisher.php 모두 존재하고 Publisher의 확장이라면 Publisher::discover()는 각각의 인스턴스를 반환합니다.
publish(): bool
전체 입력-처리-출력 체인을 처리합니다. 기본적으로 addPath($source) 및 merge(true)를 호출하는 것과 동일하지만 자식 클래스는 일반적으로 자체 구현을 제공합니다. spark publish를 실행할 때 발견된 모든 퍼블리셔에서 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()를 사용하세요. 중복 기본 이름 충돌에 주의하세요. 예:
<?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
Added in version 4.3.0.
$file 내용을 교체합니다. 두 번째 매개변수 $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
Added in version 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
Added in version 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
);