Создание Laravel пакета в локальной среде

Источник: «Create a Laravel package on your local environment»
Как настроить локальную среду разработки для тестирования классов или утилит пакета в рамках локального проекта Laravel.

Вас не должно удивлять, что в процессе разработки веб-инструментов мы используем сотни пакетов. Чтобы получить их, достаточно посетить менеджер пакетов, например Packagist, который в октябре 2023 года насчитывал 382 000 таких пакетов.

Если вы хотите разработать свой пакет, то вполне резонно задаться вопросом, как протестировать его в реальных условиях. Публикация пакета на Packagist во время разработки — не вариант. Другой подход заключается в том, чтобы интегрировать его в новый проект без использования Composer. Метод, описанный в этой статье, в значительной степени имитирует реальный сценарий, но требует некоторых настроек среды.

Создайте папку, которая станет основой для вашего пакета.

mkdir package

Создайте файл composer.json, являющийся важнейшей основой пакета.

{
"name": "capsulescodes/package",
"description": "Capsules Codes Package",
"type": "library",
"autoload": { "psr-4" : { "CapsulesCodes\\Package\\" : "src/" } }
}

Желательно, чтобы информация о name соответствовала namespace. Кроме того, в качестве имени папки в корне проекта рекомендуется использовать src.

Кроме того, если запустить composer init в папке, не содержащей файла composer.json, при помощи помощника будет выполнен процесс создания файла composer.json.

Создайте папку src внутри папки с пакетом.

cd package
mkdir src

Создайте PHP-класс с именем Greeter, содержащий функцию greet, возвращающую фразу Hello world!

<?php

namespace CapsulesCodes\Package;

class Greeter
{
public function greet() : string
{
return "Hello world!";
}
}

Теперь можно протестировать этот пакет. Для этого необходимо создать тестовую среду, используя шаблонный проект Laravel.

Вернитесь в родительский каталог пакета и создайте шаблонный Laravel-проект, выполняющий роль теста.

cd ../../
composer create-project laravel/laravel template

Чтобы сообщить template (нашему Laravel проекту), что наш пакет находится в той же родительской папке, необходимо добавить в файл composer.json два фрагмента информации.

template/composer.json

...
"minimum-stability": "dev",
"repositories": [ { "type" : "path", "url" : "../package" } ]
...

Настало время установить наш новый пакет.

composer require capsulescodes/package

Теперь он указан в списке зависимостей require.

package/composer.json

"require": {
...
"capsulescodes/package": "dev-main",
...
}

Протестируйте с помощью php artisan tinker

php artisan tinker

> CapsulesCodes\Package\Greeter::greet()
= "Hello world!"

Вы можете модифицировать файл web.php для проверки статического класса Greeter.

package/routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use CapsulesCodes\Package\Greeter;

Route::get( '/', fn() => dd( Greeter::greet() ) );
"Hello world!" // routes/web.php:7`

Рабочая среда готова.

Было бы интересно добавить дополнительный метод say() для тестирования инструмента в реальном времени.

package/src/Greeter.php

<?php

namespace CapsulesCodes\Package;

class Greeter
{
public static function greet() : string
{
return "Hello world!";
}

public static function say( string $something ) : string
{
return $something;
}
}

Протестируйте с помощью php artisan tinker. Возможно, вам следует перезагрузить его.

php artisan tinker

> CapsulesCodes\Package\Greeter::say( "That's a quick way to develop and test a package!" )
= "That's a quick way to develop and test a package!"

Вы можете модифицировать файл web.php для проверки статического класса Greeter.

package/routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use CapsulesCodes\Package\Greeter;

Route::get( '/', fn() => dd( Greeter::say( "That's a quick way to develop and test a package!" ) ) );
"That's a quick way to develop and test a package!"  // routes/web.php:7

На данном этапе все готово для разработки PHP Framework пакета. Для создания пакета Laravel потребуются дополнительные шаги. В данной статье ставится задача реализовать команду php artisan greet, вызывающую статический класс Greeter.

При создании Laravel пакета рекомендуется придерживаться типовой структуры Laravel проекта. Это облегчает поиск информации для тех, кому она необходима.

Сначала необходимо создать команду GreetCommand, расширив команду Illuminate\Console\Command, специфичную для Laravel.

package/src/Commands/GreetCommand.php

<?php

namespace CapsulesCodes\Package\Console\Commands;

use Illuminate\Console\Command;
use CapsulesCodes\Package\Greeter;

class GreetCommand extends Command
{
protected $signature = "greet";

protected $description = "Greet people with a 'Hello world!'";

public function handle()
{
dump( Greeter::greet() );
}
}

Для того чтобы проект модели распознал эту команду, необходимо уведомить его об этом с помощью ServiceProvider.

package/src/Providers/PackageServiceProvider

<?php

namespace CapsulesCodes\Package\Providers;

use Illuminate\Support\ServiceProvider;
use CapsulesCodes\Package\Console\Commands\GreetCommand;

class PackageServiceProvider extends ServiceProvider
{
public function boot()
{
$this->commands( [ GreetCommand::class ] );
}
}

Теперь пакет должен сообщить проекту модели, что новый ServiceProvider доступен для обнаружения. Это избавляет от необходимости вручную добавлять его в список ServiceProviders в конфигурационном файле template app.php.

package/composer.json

...
"extra" : { "laravel" : { "providers" : [ "CapsulesCodes\\Package\\Providers\\PackageServiceProvider" ] } },
...

Протестируйте команду php artisan greet.

php artisan greet

"Hello world!" // ../package/src/Console/Commands/GreetCommand.php:17

При возникновении проблем рекомендуется выполнить команду composer update для перезагрузки нового пакета.

Для проверки команды greet через Artisan можно модифицировать файл web.php.

package/routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Artisan;

Route::get( '/', fn() => Artisan::call( 'greet' ) );
"Hello world!" // ../package/src/Console/Commands/GreetCommand.php:17

А если вы хотите, чтобы команда GreetCommand была доступна только в консольном режиме, добавьте в PackageServiceProvider следующее условие.

package/src/Providers/PackageServiceProvider.php

public function boot()
{
if( $this->app->runningInConsole() ) $this->commands( [ GreetCommand::class ] );
}

Также можно реализовать файл конфигурации, миграции, тесты, маршруты или представления. Возможно, об этом мы поговорим позже.

Дополнительные материалы

Предыдущая Статья

Что на самом деле происходит при выполнении команды 'Docker Run'

Следующая Статья

Очистите свой JavaScript: Трансформация условных операторов