Создание 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: Имя должно быть структурировано так, чтобы слева располагалась сущность, а справа — имя пакета. Настоятельно рекомендуется использовать описательное имя пакета, упрощающее поиск для пользователей.description: Описание пакета должно быть чётким и лаконичным.type: Существует четыре типа:library,project,metapackageиcomposer-plugin. Наиболее часто используется типlibrary.projectпредставляет проект, например, шаблон фреймворка.autoload: Это основной элемент нашего пакета, определяющий пространство имён для доступа к данным, расположенным в корне проекта. В PSR-4 определён протокол спецификации автозагрузки классов. Это очень важный шаг. Обязательно включите\\, особенно в конце выражения.
Желательно, чтобы информация о 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!";
}
}
- Не забудьте указать
namespace. В противном случае класс не будет найден.
Теперь можно протестировать этот пакет. Для этого необходимо создать тестовую среду, используя шаблонный проект Laravel.
Вернитесь в родительский каталог пакета и создайте шаблонный Laravel-проект, выполняющий роль теста.
cd ../../
composer create-project laravel/laravel template- Команда
composer create-project laravel/laravel templateформирует здесь'type': 'project'.
Чтобы сообщить template (нашему Laravel проекту), что наш пакет находится в той же родительской папке, необходимо добавить в файл composer.json два фрагмента информации.
template/composer.json
...
"minimum-stability": "dev",
"repositories": [ { "type" : "path", "url" : "../package" } ]
...minimum-stability: Эта опция позволяет установить пакет через composer без генерации исключения. Это необходимо, если пакет не являетсяstable, в данном случае наш пакет являетсяdev.repositories: Этот массив позволяет добавить пути к другим каталогам, к которым должен обратиться composer, чтобы найти пакет локально.type: В качестве типа каталога может быть указанcomposer,package,vcsилиpath. Опцияpathпозволяет использовать пакет локально, а опцияvcs— через систему контроля версий, например Github.
Настало время установить наш новый пакет.
composer require capsulescodes/packageТеперь он указан в списке зависимостей require.
package/composer.json
"require": {
...
"capsulescodes/package": "dev-main",
...
}- Поскольку пакет находится в стадии разработки, используется версия
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() );
}
}
- В качестве расширения используется базовый класс
Illuminate\Console\Commandиз Laravel. - В методе
handle()используется созданный ранее статический классGreeter. Однако для тестирования пакета можно просто заменитьreturn Greeter::greet()наreturn "Hello world!".
Для того чтобы проект модели распознал эту команду, необходимо уведомить его об этом с помощью 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 ] );
}
}
- В качестве расширения используется базовый класс
Illuminate\Support\ServiceProviderиз Laravel. - Вновь созданная команда
GreetCommandдобавляется в массив, запрашиваемый методомthis->commands, что позволяет проектуtemplateполучить доступ к этой команде.
Теперь пакет должен сообщить проекту модели, что новый 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 ] );
}Также можно реализовать файл конфигурации, миграции, тесты, маршруты или представления. Возможно, об этом мы поговорим позже.