• Czas czytania ~17 min
  • 10.08.2022

Udostępnianie kodu nigdy nie było bardziej dostępne, a instalowanie pakietów PHP stało się wygodne; jednak budowanie pakietów? W tym samouczku omówię, jak uruchomić i opublikować nowy pakiet Laravel. Przechodząc przez konfigurację i narzędzia, których możesz użyć, aby zapewnić jakość swojego pakietu i że jeśli coś zbudujesz i opublikujesz, zrobisz to dobrze.

Więc co zamierzamy budować?Jaki pakiet moglibyśmy stworzyć, który jest na tyle prosty, że łatwo jest nauczyć się procesu, ale zawiera wystarczająco dużo części, aby go zrozumieć. Zbudujemy pakiet z poleceniem artisan, który pozwoli nam tworzyć obiekty transferu danych w Laravel i PHP 8.1, mając nadzieję na aktualizację do PHP 8.2, gdy tylko będzie dostępna.Oprócz tego będziemy mieć również Fasada do uwadniania obiektów transferu danych, określanych tutaj jako DTO.

Więc od czego zacząć tworzenie nowego pakietu? Jaki powinien być nasz pierwszy krok? Po pierwsze, to, co lubię robić, gdy mam zamiar utworzyć pakiet, to wyszukiwarka pakietów, aby upewnić się, że nie tworzę czegoś już dostępnego lub wystarczająco bogatego w funkcje, aby zmarnować swój czas.Mimo wszystko nie chcemy odtwarzać koła.

Kiedy jestem już pewien, że buduję coś użytecznego, co nie istnieje, myślę o tym, czego potrzebuje mój pakiet. W naszym przypadku nasze wymagania są stosunkowo proste. Będziemy mieli 3-4 główne klasy, które chcemy stworzyć i tyle. Decydowanie o strukturze Twojego pakietu jest zwykle jednym z pierwszych kroków, które musisz pokonać.Jak stworzyć ten kod, aby udostępnić go innym w sposób, do którego ludzie są przyzwyczajeni? Na szczęście społeczność Laravel cię o tym poinformowała. Repozytoria szablonów są dostępne dla szkieletów pakietów; wystarczy ich poszukać. Firmy takie jak Spatie i Beyond Code mają jedne z najlepszych szkieletów pakietów, które są w pełni funkcjonalne i pozwalają zaoszczędzić dużo czasu.

Jednak w tym samouczku nie będę używał pakietu szkieletowego, ponieważ uważam, że konieczne jest nauczenie się, jak wykonać zadanie przed użyciem narzędzia do wykonania pracy za Ciebie. Więc zaczniemy od czystej karty. Najpierw musisz wymyślić nazwę swojego pakietu.Zamierzam nazwać moje "Narzędzia Laravel Data Object Tools", ponieważ ostatecznie chciałbym zbudować zestaw narzędzi, aby móc łatwiej pracować z DTO w mojej aplikacji. Mówi ludziom, jaki jest cel mojego pakietu i pozwala mi rozszerzać go w miarę upływu czasu.

Utwórz nowy katalog z nazwą swojego pakietu i otwórz go w wybranym przez Ciebie edytorze kodu, abyśmy mogli rozpocząć konfigurację.Pierwszą rzeczą, którą robię z każdym nowym pakietem, jest zainicjowanie go jako repozytorium git, więc uruchom następujące polecenie git:

git init

Teraz, gdy mamy repozytorium do pracy, wiemy, że będziemy w stanie przekazać rzeczy do kontroli źródeł i pozwolić nam na wersjonowanie naszego pakietu, gdy nadejdzie czas. Tworzenie pakietu PHP wymaga od razu jednej rzeczy, composer.jsonktóry powie Packagist, czym jest ten pakiet i czego potrzebuje do uruchomienia. Możesz użyć narzędzia kompozytora wiersza poleceń lub ręcznie utworzyć plik kompozytora. Zwykle używam wiersza poleceń init kompozytora, ponieważ jest to interaktywny sposób na ustawienie tego; jednak pokażę dane wyjściowe początku mojego pliku kompozytora, abyś mógł zobaczyć wynik:

{
  "name": "juststeveking/laravel-data-object-tools",
  "description": "A set of tools to make working with Data Transfer Objects easier in Laravel",
  "type": "library",
  "license": "MIT",
  "authors": [
    {
      "role": "Developer",
      "name": "Steve McDougall",
      "email": "[email protected]",
      "homepage": "https://www.juststeveking.uk/"
    }
  ],
  "autoload": {
    "psr-4": {
      "JustSteveKing\\DataObjects\\": "src/"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "JustSteveKing\\DataObjects\\Tests\\": "tests/"
    }
  },
  "require": {
    "php": "^8.1"
  },
  "require-dev": {},
  "minimum-stability": "dev",
  "prefer-stable": true,
  "config": {
    "sort-packages": true,
    "preferred-install": "dist",
    "optimize-autoloader": true
  }
}

To jest podstawa większości moich pakietów i niezależnie od tego, czy jest to pakiet Laravel, czy zwykły pakiet PHP, ustawia mnie w taki sposób, że wiem, że będę miał spójność. Aby rozpocząć, będziemy musieli dodać kilka plików pomocniczych do naszego pakietu. Najpierw musimy dodać nasz plik .gitignore, abyśmy mogli powiedzieć kontroli wersji, jakich plików i katalogów nie chcemy zatwierdzać:

/vendor/
/.idea
composer.lock

To jest początek plików, które chcemy zignorować. Używam PHPStorm, który doda meta-katalog o nazwie .idea, który będzie zawierał wszystkie informacje, których potrzebuje moje IDE, aby zrozumieć mój projekt - coś, czego nie chcę angażować w kontrolę wersji. Następnie musimy dodać kilka atrybutów git, aby kontrola wersji wiedziała, jak przetwarzać nasze repozytorium. Nazywa się to .gitattributes:

* text=auto

*.md diff=markdown
*.php diff=php

/.github export-ignore
/tests export-ignore
.editorconfig export-ignore
.gitattributes export-ignore
.gitignore export-ignore
CHANGELOG.md export-ignore
phpunit.xml export-ignore

Podczas tworzenia wydania mówimy naszemu dostawcy kontroli źródła, jakie pliki chcemy zignorować i jak radzić sobie z różnicami. Na koniec naszym ostatnim plikiem pomocniczym będzie nasz .editorconfig, który mówi naszemu edytorowi kodu, jak obsługiwać pliki, które piszemy:

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml,json}]
indent_size = 2
< p>Teraz, gdy mamy już pliki pomocnicze do kontroli wersji i nasz edytor, możemy zacząć myśleć o tym, czego potrzebuje nasz pakiet w zakresie zależności. Na jakich zależnościach będzie opierał się nasz pakiet i jakich wersji używamy? Zacznijmy.

Ponieważ budujemy pakiet Laravel, pierwszą rzeczą, której będziemy potrzebować, jest pakiet wsparcia Laravel, więc zainstaluj go za pomocą następującego polecenia kompozytora:

composer require illuminate/support

Teraz mamy coś do zrobienia zacznijmy od przyjrzenia się pierwszej ważnej części kodu, której będzie potrzebować nasz pakiet; Usługodawcy.Dostawca usług jest kluczową częścią każdego pakietu Laravel, ponieważ mówi Laravelowi, jak załadować pakiet i co jest dostępne. Na początek chcemy poinformować Laravel, że mamy komendę konsoli, której możemy użyć po zainstalowaniu. Zadzwoniłem do mojego dostawcy usług PackageServiceProvider, ponieważ nie mam wyobraźni i nazywanie rzeczy jest trudne.Jeśli chcesz, możesz zmienić własne nazewnictwo. Dodaję mojego dostawcę usług w src/Providers, ponieważ jest on zaznajomiony z aplikacją Laravel.

declare(strict_types=1);
 
namespace JustSteveKing\DataObjects\Providers;
 
use Illuminate\Support\ServiceProvider;
use JustSteveKing\DataObjects\Console\Commands\DataTransferObjectMakeCommand;
 
final class PackageServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->commands(
                commands: [
                    DataTransferObjectMakeCommand::class,
                ],
            );
        }
    }
}

Zazwyczaj tworzę klasy, o których wiem, że nie chcę być przedłużone, ponieważ zmieniłoby to sposób, w jaki chcę, aby pakiet działał. Nie musisz tego robić. To wezwanie do osądu, które musisz wykonać dla siebie.Więc mamy teraz zarejestrowaną komendę. Powinniśmy pomyśleć o stworzeniu tego. Jak widać po nazewnictwie, jest to polecenie, które wygeneruje dla nas inne klasy - trochę inne niż typowe polecenie rzemieślnika.

Utworzyłem klasę o nazwie DataTransferObjectMakeCommand, co jest bardzo rozwlekłe, ale wyjaśnia, co robi w src/Console/Commands.Jak widać, tworząc te klasy, staram się odzwierciedlić strukturę katalogów znaną programistom Laravela. Dzięki temu praca z pakietem jest znacznie łatwiejsza. Rzućmy okiem na kod tego polecenia:

declare(strict_types=1);
 
namespace JustSteveKing\DataObjects\Console\Commands;
 
use Illuminate\Console\GeneratorCommand;
use Illuminate\Support\Str;
 
final class DataTransferObjectMakeCommand extends GeneratorCommand
{
    protected $signature = "make:dto {name : The DTO Name}";
 
    protected $description = "Create a new DTO";
 
    protected $type = 'Data Transfer Object';
 
    protected function getStub(): string
    {
        $readonly = Str::contains(
            haystack: PHP_VERSION,
            needles: '8.2',
        );
 
        $file = $readonly ? 'dto-82.stub' : 'dto.stub';
 
        return __DIR__ . "/../../../stubs/{$file}";
    }
 
    protected function getDefaultNamespace($rootNamespace): string
    {
        return "{$rootNamespace}\\DataObjects";
    }
}

Przejrzyjmy to polecenie, aby zrozumieć, co tworzymy. Nasze polecenie chce rozszerzyć GeneratorCommand, ponieważ chcemy wygenerować nowy plik.Warto to zrozumieć, ponieważ istnieje niewiele dokumentacji, jak to zrobić. Jedyne, czego potrzebujemy do tego polecenia, to metoda o nazwie getStub - której potrzebuje polecenie, aby wiedzieć, jak załadować lokalizację pliku pośredniczącego, aby pomóc w generowaniu pliku. Utworzyłem katalog w katalogu głównym mojego pakietu o nazwie stubs, znane miejsce dla aplikacji Laravel. Zobaczysz tutaj, że sprawdzam zainstalowaną wersję PHP, aby zobaczyć, czy jesteśmy na PHP 8.2, a jeśli tak - chcemy załadować poprawną wersję stub, aby skorzystać z klas tylko do odczytu. Szanse na to w tej chwili są dość niskie - jednak nie jesteśmy tak daleko.Takie podejście pomaga generować pliki dla określonych wersji PHP, dzięki czemu możesz zapewnić obsługę każdej wersji, którą chcesz obsługiwać.

Na koniec ustawiłem domyślną przestrzeń nazw dla moich DTO , więc wiem, gdzie chcę, żeby mieszkały. Mimo wszystko nie chcę przepełniać głównej przestrzeni nazw.

Przyjrzyjmy się najpierw tym plikom pośredniczącym, domyślnemu skrótowi:

Nasz DTO wdroży umowę, aby zagwarantować spójność - coś, co lubię robić z jak największą liczbą klas. Również nasza klasa DTO jest ostateczna. Prawdopodobnie nie będziemy chcieli rozszerzać tej klasy, więc domyślne ustawienie ostatecznej wersji jest rozsądnym podejściem. Przyjrzyjmy się teraz wersji PHP 8.2:

<?php
 
declare(strict_types=1);
 
namespace {{ namespace }};
 
use JustSteveKing\DataObjects\Contracts\DataObjectContract;
 
final class {{ class }} implements DataObjectContract
{
    public function __construct(
        //
    ) {}
 
    public function toArray(): array
    {
        return [];
    }
}

Jedyna różnica polega na tym, że czynimy naszą klasę DTO tylko do odczytu, aby skorzystać z nowszych funkcji języka.

<?php
 
declare(strict_types=1);
 
namespace {{ namespace }};
 
use JustSteveKing\DataObjects\Contracts\DataObjectContract;
 
readonly class {{ class }} implements DataObjectContract
{
    public function __construct(
        //
    ) {}
 
    public function toArray(): array
    {
        return [];
    }
}

Jak możemy to przetestować? Po pierwsze, chcemy zainstalować pakiet testowy, aby upewnić się, że możemy pisać testy uruchamiania tego polecenia - będę używał pestPHP do to, ale użycie PHPUnit będzie działać w bardzo podobny sposób.

To polecenie poprosi Cię o zezwolenie szkodnikowi na używanie wtyczek kompozytora, więc upewnij się, że zgadzasz się na to, jeśli potrzebujesz wtyczek szkodnika do testów, takich jak testowanie równoległe . Następnie będziemy potrzebować pakietu, który pozwoli nam używać Laravela w naszych testach, aby upewnić się, że nasz pakiet działa skutecznie. Ten pakiet nazywa się Testbench i jest to ten, na który przysięgam, budując pakiety Laravel.

composer require pestphp/pest --dev --with-all-dependencies

Najłatwiejszym sposobem zainicjowania zestawu testów w naszym pakiecie jest użycie pestPHP do zainicjowania go za nas. Uruchom następujące polecenie konsoli:

composer require --dev orchestra/testbench

Wygeneruje to plik phpunit.xml i tests/Pest.php plik, którego używamy do kontrolowania i rozprzestrzeniania samego szkodnika. Po pierwsze chciałbym wprowadzić kilka zmian w pliku konfiguracyjnym PHPUnit, którego będzie używał szkodnik.Chciałbym dodać następujące opcje, aby ułatwić sobie testowanie:

./vendor/bin/pest --init

Robię to, ponieważ jeśli test się nie powiedzie, chcę o tym natychmiast wiedzieć. Wczesne zwroty i awarie to rzeczy, które pomagają nam zbudować coś, do czego mamy większe zaufanie. Wyniki buforowania przyspieszają testowanie Twojego pakietu.Jednak chciałbym się upewnić, że za każdym razem uruchamiam mój zestaw testów od zera, aby upewnić się, że działa zgodnie z oczekiwaniami.

stopOnFailure I set to true
cacheResults I set to false

Zwróćmy teraz naszą uwagę na domyślny test przypadku, w którym potrzebujemy wykonać nasze testy pakietów. Utwórz nowy plik w testy/PackageTestCase.php, abyśmy mogli łatwiej kontrolować nasze testy.

Nasz PackageTestCase rozszerza stanowisko probiercze TestCase, dzięki czemu możemy pożyczyć zachowanie z pakietu do zbudowania naszego zestawu testów. Następnie rejestrujemy naszego dostawcę usług pakietowych, aby upewnić się, że nasz pakiet zostanie załadowany do aplikacji testowej.

declare(strict_types=1);
 
namespace JustSteveKing\DataObjects\Tests;
 
use JustSteveKing\DataObjects\Providers\PackageServiceProvider;
use Orchestra\Testbench\TestCase;
 
class PackageTestCase extends TestCase
{
    protected function getPackageProviders($app): array
    {
        return [
            PackageServiceProvider::class,
        ];
    }
}

Teraz przyjrzyjmy się, jak możemy to przetestować. Zanim napiszemy nasze testy, chcemy się upewnić, że to, co testujemy, obejmuje bieżące zachowanie pakietu.Jak dotąd nasz test dostarcza tylko polecenia, które można uruchomić, aby utworzyć nowy plik. Nasza struktura katalogów testów będzie odzwierciedlać naszą strukturę pakietów, więc utwórz nasz pierwszy plik testowy pod tests/Console/Commands/DataTransferObjectMakeCommandTest.php i zacznijmy nasz pierwszy test.

Zanim napiszemy nasz pierwszy test, musimy edytować testy/Pest.phpplik, aby upewnić się, że nasz zestaw testów prawidłowo używa naszego PackageTestCase.

Na początek chcemy się upewnić, że możemy uruchomić nasze polecenie i że działa pomyślnie. Dodaj więc następujący test:

Sprawdzamy, że kiedy wywołamy to polecenie, działa ono bezbłędnie. Jeden z najbardziej krytycznych testów, jeśli zapytasz mnie, czy wystąpił błąd, oznacza to, że coś poszło nie tak.

declare(strict_types=1);
 
use JustSteveKing\DataObjects\Tests\PackageTestCase;
 
uses(PackageTestCase::class)->in(__DIR__);

Teraz, gdy wiemy, że nasz test może działać, chcemy również upewnić się, że klasy są tworzone. Napiszmy więc teraz ten test:

declare(strict_types=1);
 
use JustSteveKing\DataObjects\Console\Commands\DataTransferObjectMakeCommand;
 
use function PHPUnit\Framework\assertTrue;
 
it('can run the command successfully', function () {
    $this
        ->artisan(DataTransferObjectMakeCommand::class, ['name' => 'Test'])
        ->assertSuccessful();
});

Tutaj używamy zestawu danych szkodników do uruchamiania niektórych opcji, trochę jak dostawca danych PHPUnit. Zapętlamy każdą opcję i wywołujemy nasze polecenie, potwierdzając, że plik istnieje.Teraz wiemy, że możemy przekazać nazwę naszemu poleceniu rzemieślnika i utworzyć DTO, którego będziemy używać w naszej aplikacji.

Na koniec chcemy zbudować fasadę dla nasz pakiet, aby umożliwić łatwe nawodnienie naszych DTO. Posiadanie DTO często to tylko połowa sukcesu, i tak, moglibyśmy dodać metodę do naszego samego DTO, aby wywołać statycznie - ale możemy ten proces znacznie uprościć.Ułatwimy to, korzystając z naprawdę przydatnego pakietu autorstwa Franka de Jonge w jego Pakiet Eventsauce, zwany „hydratorem obiektów”. Aby to zainstalować, uruchom następujące polecenie kompozytora:

declare(strict_types=1);
 
use Illuminate\Support\Facades\File;
use JustSteveKing\DataObjects\Console\Commands\DataTransferObjectMakeCommand;
 
use function PHPUnit\Framework\assertTrue;
 
it('create the data transfer object when called', function (string $class) {
    $this->artisan(
        DataTransferObjectMakeCommand::class,
        ['name' => $class],
    )->assertSuccessful();
 
    assertTrue(
        File::exists(
            path: app_path("DataObjects/$class.php"),
        ),
    );
})->with('classes');

Nadszedł czas, aby zbudować wrapper wokół tego pakietu, abyśmy mogli go ładnie używać, więc stwórzmy nową klasę w src/Hydrator/Hydrate.php. chcesz zmienić implementację w dowolnym momencie. Będzie to src/Contracts/HydratorContract.php. Zacznijmy od umowy, aby zrozumieć, co chcemy zrobić.

Wszystko, czego potrzebujemy, to sposób uwodnienia obiektu, więc bierzemy nazwę klasy obiektu i tablicę właściwości, aby zwrócić obiekt danych. Przyjrzyjmy się teraz implementacji:

composer require eventsauce/object-hydrator

Mamy obiekt mapujący przekazany do konstruktora lub utworzony w konstruktorze - którego następnie używamy wewnątrz metody fill. Metoda wypełnienia używa następnie mapera do nawodnienia obiektu.Jest prosty i czysty w użyciu i można go łatwo odtworzyć, jeśli w przyszłości zdecydujemy się użyć innego nawilżacza. Korzystając z tego, chcemy jednak związać hydrator z kontenerem, aby umożliwić nam rozwiązanie go za pomocą wstrzykiwania zależności. Dodaj następujące elementy u góry swojego PackageServiceProvider:

declare(strict_types=1);
 
namespace JustSteveKing\DataObjects\Contracts;
 
interface HydratorContract
{
    /**
     * @param class-string<DataObjectContract> $class
     * @param array $properties
     * @return DataObjectContract
     */
    public function fill(string $class, array $properties): DataObjectContract;
}

Teraz, gdy mamy nasz hydrator, musimy stworzyć fasadę, abyśmy mogli ładnie ją nazwać w naszych aplikacjach. Stwórzmy to teraz w src/Facades/Hydrator.php

declare(strict_types=1);
 
namespace JustSteveKing\DataObjects\Hydrator;
 
use EventSauce\ObjectHydrator\ObjectMapperUsingReflection;
use JustSteveKing\DataObjects\Contracts\DataObjectContract;
use JustSteveKing\DataObjects\Contracts\HydratorContract;
 
class Hydrate implements HydratorContract
{
    public function __construct(
        private readonly ObjectMapperUsingReflection $mapper = new ObjectMapperUsingReflection(),
    ) {}
 
    public function fill(string $class, array $properties): DataObjectContract
    {
        return $this->mapper->hydrateObject(
            className: $class,
            payload: $properties,
        );
    }
}

Więc nasza Fasada obecnie zwraca implementację sosu eventowego hydratora - co oznacza, że ​​nie możemy tego rozwiązać z poziomu kontenera, więc gdybyśmy zmienili implementację, musielibyśmy zmienić fasadę.Na razie nie jest to jednak wielka sprawa. Następnie musimy dodać ten alias do naszego pliku composer.json, aby Laravel wiedział o tym podczas instalacji pakietu.

public array $bindings = [
    HydratorContract::class => Hydrate::class,
];

Teraz że zarejestrowaliśmy naszą fasadę, musimy sprawdzić, czy działa zgodnie z oczekiwaniami. Przejdźmy przez to, jak możemy to przetestować. Utwórz nowy plik testowy pod tests/Facades/HydratorTest.php i zacznijmy:

declare(strict_types=1);
 
namespace JustSteveKing\DataObjects\Facades;
 
use Illuminate\Support\Facades\Facade;
use JustSteveKing\DataObjects\Contracts\DataObjectContract;
use JustSteveKing\DataObjects\Hydrator\Hydrate;
 
/**
 * @method static DataObjectContract fill(string $class, array $properties)
 *
 * @see \JustSteveKing\DataObjects\Hydrator\Hydrate;
 */
final class Hydrator extends Facade
{
    /**
     * @return class-string
     */
    protected static function getFacadeAccessor(): string
    {
        return Hydrate::class;
    }
}

Stworzyliśmy nowy zestaw danych o nazwie ciągi, który zwraca tablicę losowych ciągów do wykorzystania. Przekazujemy to do naszego testu i próbujemy wywołać metodę wypełnienia na naszej fasadzie. Przechodząc w klasie testowej, możemy stworzyć szereg właściwości do nawodnienia. Następnie sprawdzamy, czy instancja została utworzona i czy spełnia nasze oczekiwania, gdy wywołujemy metodę toArray w DTO.Możemy użyć interfejsu API refleksji, aby upewnić się, że nasze DTO jest tworzone zgodnie z oczekiwaniami dla naszego końcowego testu.

"extra": {
  "laravel": {
    "providers": [
      "JustSteveKing\\DataObjects\\Providers\\PackageServiceProvider"
    ],
    "aliases": [
      "JustSteveKing\\DataObjects\\Facades\\Hydrator"
    ]
  }
},

Możemy teraz być pewni, że nasz pakiet działa zgodnie z oczekiwaniami. Ostatnią rzeczą, którą musimy zrobić, jest skupienie się na jakości naszego kodu. W większości moich pakietów lubię się upewnić, że zarówno styl kodowania, jak i analiza statyczna są uruchomione, dzięki czemu mam niezawodny pakiet, któremu mogę zaufać.Zacznijmy od stylizacji kodu. Aby to zrobić, zainstalujemy pakiet o nazwie Laravel Pint, który jest stosunkowo nowy:

declare(strict_types=1);
 
use JustSteveKing\DataObjects\Facades\Hydrator;
use JustSteveKing\DataObjects\Tests\Stubs\Test;
 
it('can create a data transfer object', function (string $string) {
    expect(
        Hydrator::fill(
            class: Test::class,
            properties: ['name' => $string],
        ),
    )->toBeInstanceOf(Test::class)->toArray()->toEqual(['name' => $string]);
})->with('strings');

Lubię używać PSR-12 do mojego stylu kodu, więc utwórzmy pint.json w katalogu głównym naszego pakietu, aby upewnić się, że skonfigurujemy pint do uruchamiania standard, który chcemy uruchomić:

it('creates our data transfer object as we would expect', function (string $string) {
    $test = Hydrator::fill(
        class: Test::class,
        properties: ['name' => $string],
    );
 
    $reflection = new ReflectionClass(
        objectOrClass: $test,
    );
 
    expect(
        $reflection->getProperty(
            name: 'name',
        )->isReadOnly()
    )->toBeTrue()->and(
        $reflection->getProperty(
            name: 'name',
        )->isPrivate(),
    )->toBeTrue()->and(
        $reflection->getMethod(
            name: 'toArray',
        )->hasReturnType(),
    )->toBeTrue();
})->with('strings');

Teraz uruchom polecenie pint, aby naprawić wszelkie problemy ze stylami kodu, które nie są zgodne z PSR-12:

composer require --dev laravel/pint

Na koniec możemy zainstalować PHPStan, abyśmy mogli sprawdzić statyczną analizę naszej bazy kodu, aby upewnić się, że jesteśmy tak rygorystyczni i spójni z naszymi typami, jak to tylko możliwe:

{
  "preset": "psr12"
}

Aby skonfigurować PHPStan, musimy utworzyć phpstan.neonw katalogu głównym naszego pakietu, aby poznać używaną konfigurację.

./vendor/bin/pint

Na koniec możemy uruchomić PHPStan, aby upewnić się, że wyglądamy dobrze z perspektywy typu.

composer require --dev phpstan/phpstan

Jeśli wszystko poszło dobrze, powinniśmy teraz zobaczyć komunikat „[OK] Brak błędów”.

parameters:
    level: 9

    paths:
        - src

Ostateczny kroki, które lubię wykonywać w przypadku budowania dowolnego pakietu, to napisanie mojego README i dodanie określonych akcji GitHub, które mogę chcieć uruchomić na pakiecie.Nie będę ich tutaj dodawać, ponieważ są długie i pełne YAML. Możesz jednak zajrzeć do repozytorium, aby zobaczyć, jak zostały one utworzone.

./vendor/bin/phpstan analyse

Czy zbudowałeś jakieś pakiety Laravel lub PHP, o których chcesz, abyśmy się wiedzieli? Jak podchodzisz do tworzenia pakietów? Daj nam znać na Twitterze!

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297