gsmanager-cloud/route-attributes

Auto register routes using PHP attributes

v1 2025-07-07 16:09 UTC

This package is auto-updated.

Last update: 2025-07-07 16:37:31 UTC


README

Этот пакет предоставляет атрибуты для автоматической регистрации маршрутов. Вот краткий пример:

use GSManager\RouteAttributes\Attributes\Get;

class MyController
{
    #[Get('my-route')]
    public function myMethod()
    {
    }
}

Этот атрибут автоматически зарегистрирует этот маршрут:

Route::get('my-route', [MyController::class, 'myMethod']);

Установка

Вы можете установить пакет с помощью composer:

composer require gsmanager-cloud/route-attributes

Вы можете опубликовать конфигурационный файл с помощью:

php gsm vendor:publish --provider="GSManager\RouteAttributes\RouteAttributesServiceProvider" --tag="config"

Это содержимое опубликованного конфигурационного файла:

return [
    /*
     *  Automatic registration of routes will only happen if this setting is `true`
     */
    'enabled' => true,

    /*
     * Controllers in these directories that have routing attributes
     * will automatically be registered.
     *
     * Optionally, you can specify group configuration by using key/values
     */
    'directories' => [
        app_path('Http/Controllers'),

        app_path('Http/Controllers/Web') => [
            'middleware' => ['web']
        ],

        app_path('Http/Controllers/Api') => [
            'prefix' => 'api',
            'middleware' => 'api'
        ],
    ],
];

Для контроллеров, находящихся за пределами приложений, также можно добавить корневые каталоги пространства имен, используя шаблон namespace => path в массиве каталогов. В следующем примере будут включены контроллеры из Modules\Admin\Http\Controllers.

'directories' => [
    'Modules\Admin\Http\Controllers\\' => base_path('admin-module/Http/Controllers'),
    // Or
    base_path('admin-module/Http/Controllers') => [
        'namespace' => 'Modules\Admin\Http\Controllers\\'
    ],
    app_path('Http/Controllers'),
],

If you are using a directory structure where you co-locate multiple types of files in the same directory and want to be more specific about which files are checked for route attributes, you can use the patterns and not_patterns options. For example, if you are co-locating your tests with your controllers you could use the patterns option to only look in controller files, or you could use not_patterns to configure it to not look in test files for route attributes.

'directories' => [
    base_path('app-modules/Blog') => [
        // only register routes in files that match the patterns
        'patterns' => ['*Controller.php'],
        // do not register routes in files that match the patterns
        'not_patterns' => ['*Test.php'],
    ],
],

Использование

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

Добавление маршрута GET

use GSManager\RouteAttributes\Attributes\Get;

class MyController
{
    #[Get('my-route')]
    public function myMethod()
    {

    }
}

Этот атрибут автоматически зарегистрирует этот маршрут:

Route::get('my-route', [MyController::class, 'myMethod']);

Использование других HTTP-глаголов

Мы не оставили ни одного HTTP-глагола. Вы можете использовать эти атрибуты в методах контроллера.

#[GSManager\RouteAttributes\Attributes\Post('my-uri')]
#[GSManager\RouteAttributes\Attributes\Put('my-uri')]
#[GSManager\RouteAttributes\Attributes\Patch('my-uri')]
#[GSManager\RouteAttributes\Attributes\Delete('my-uri')]
#[GSManager\RouteAttributes\Attributes\Options('my-uri')]

Контроллеры ресурсов

Чтобы зарегистрировать контроллер ресурсов, используйте атрибут Resource, как показано в примере ниже.

Вы можете использовать параметры only или except для управления доступностью ваших ресурсных маршрутов.

Вы можете использовать параметр parameters для изменения параметров по умолчанию, установленных атрибутом resource.

Вы можете использовать параметр names, чтобы задать имена маршрутов для действий контроллера ресурсов. Передайте строковое значение, чтобы задать имя базового маршрута для каждого действия контроллера, или передайте значение массива, чтобы определить имя маршрута для каждого действия контроллера.

Вы можете использовать параметр shallow параметр для создания вложенного ресурса, который применяет вложенность только к маршрутам без уникального дочернего идентификатора (index, create, store).

Вы можете использовать параметр apiResource логический параметр, включающий только действия, используемые в API. В качестве альтернативы вы можете использовать ApiResource атрибут, который расширяет Resource класс атрибута, но параметр apiResource уже настроен на true.

С помощью Resource атрибут с Domain, Prefix и Middleware тоже работают.

use GSManager\RouteAttributes\Attributes\Resource;

#[Prefix('api/v1')]
#[Resource(
    resource: 'photos.comments',
    apiResource: true,
    shallow: true,
    parameters: ['comments' => 'comment:uuid'],
    names: 'api.v1.photoComments',
    except: ['destroy'],
)]
// OR #[ApiResource(resource: 'photos.comments', shallow: true, ...)]
class PhotoCommentController
{
    public function index(Photo $photo)
    {
    }

    public function store(Request $request, Photo $photo)
    {
    }

    public function show(Comment $comment)
    {
    }

    public function update(Request $request, Comment $comment)
    {
    }
}

Атрибут в приведенном выше примере автоматически зарегистрирует следующие маршруты:

Route::get('api/v1/photos/{photo}/comments', [PhotoCommentController::class, 'index'])->name('api.v1.photoComments.index');
Route::post('api/v1/photos/{photo}/comments', [PhotoCommentController::class, 'store'])->name('api.v1.photoComments.store');
Route::get('api/v1/comments/{comment}', [PhotoCommentController::class, 'show'])->name('api.v1.photoComments.show');
Route::match(['put', 'patch'], 'api/v1/comments/{comment}', [PhotoCommentController::class, 'update'])->name('api.v1.photoComments.update');

Использование нескольких глаголов

Чтобы зарегистрировать маршрут для всех глаголов, вы можете использовать атрибут Any:

#[GSManager\RouteAttributes\Attributes\Any('my-uri')]

Чтобы зарегистрировать маршрут сразу для нескольких глаголов, вы можете напрямую использовать атрибут Route:

#[GSManager\RouteAttributes\Attributes\Route(['put', 'patch'], 'my-uri')]

Укажите название маршрута

Все атрибуты HTTP verb принимают параметр с именем name, который принимает имя маршрута.

use GSManager\RouteAttributes\Attributes\Get;

class MyController
{
    #[Get('my-route', name: "my-route-name")]
    public function myMethod()
    {
    }
}

This attribute will automatically register this route:

Route::get('my-route', [MyController::class, 'myMethod'])->name('my-route-name');

Добавление промежуточного программного обеспечения

Все атрибуты HTTP verb принимают параметр с именем middleware который принимает класс промежуточного программного обеспечения или массив классов промежуточного программного обеспечения.

use GSManager\RouteAttributes\Attributes\Get;

class MyController
{
    #[Get('my-route', middleware: MyMiddleware::class)]
    public function myMethod()
    {

    }
}

Эта аннотация автоматически зарегистрирует этот маршрут:

Route::get('my-route', [MyController::class, 'myMethod'])->middleware(MyMiddleware::class);

Чтобы применить промежуточное программное обеспечение ко всем методам класса, вы можете использовать атрибут Middleware. Вы можете использовать его для применения атрибута к методу.

use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Middleware;

#[Middleware(MyMiddleware::class)]
class MyController
{
    #[Get('my-route')]
    public function firstMethod()
    {
    }

    #[Get('my-other-route', middleware: MyOtherMiddleware::class)]
    public function secondMethod()
    {
    }
}

Эти аннотации автоматически зарегистрируют эти маршруты:

Route::get('my-route', [MyController::class, 'firstMethod'])->middleware(MyMiddleware::class);
Route::get('my-other-route', [MyController::class, 'secondMethod'])->middleware([MyMiddleware::class, MyOtherMiddleware::class]);

Specifying a prefix

Вы можете использовать аннотацию Prefix в классе для префиксизации маршрутов всех методов этого класса.

use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Post;
use GSManager\RouteAttributes\Attributes\Prefix;

#[Prefix('my-prefix')]
class MyController
{
    #[Get('my-get-route')]
    public function myGetMethod()
    {
    }

    #[Post('my-post-route')]
    public function myPostMethod()
    {
    }
}

Эти аннотации автоматически зарегистрируют эти маршруты:

Route::get('my-prefix/my-get-route', [MyController::class, 'myGetMethod']);
Route::post('my-prefix/my-post-route', [MyController::class, 'myPostMethod']);

Указание домена

Вы можете использовать аннотацию Domain в классе для префикса маршрутов всех методов этого класса..

use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Post;
use GSManager\RouteAttributes\Attributes\Domain;

#[Domain('my-subdomain.localhost')]
class MyController
{
    #[Get('my-get-route')]
    public function myGetMethod()
    {
    }

    #[Post('my-post-route')]
    public function myPostMethod()
    {
    }
}

Эти аннотации автоматически зарегистрируют эти маршруты:

Route::get('my-get-route', [MyController::class, 'myGetMethod'])->domain('my-subdomain.localhost');
Route::post('my-post-route', [MyController::class, 'myPostMethod'])->domain('my-subdomain.localhost');

Указание домена с помощью конфигурационного ключа

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

// config/domains.php
return [
    'main' => env('SITE_URL', 'example.com'),
    'subdomain' => env('SUBDOMAIN_URL', 'subdomain.example.com')
];
use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Post;
use GSManager\RouteAttributes\Attributes\DomainFromConfig;

#[DomainFromConfig('domains.main')]
class MyController
{
    #[Get('my-get-route')]
    public function myGetMethod()
    {
    }
}

Когда это будет проанализировано, он получит значение domains.main из файла конфигурации и зарегистрирует маршрут следующим образом;

Route::get('my-get-route', [MyController::class, 'myGetMethod'])->domain('example.com');

Привязки к области действия

При неявном связывании нескольких моделей Eloquent в одном определении маршрута вы можете захотеть изменить область действия второй модели Eloquent таким образом, чтобы она была дочерней по отношению к предыдущей модели Eloquent.

Добавив аннотацию ScopeBindings, вы можете включить это поведение:

use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\ScopeBindings;

class MyController
{
    #[Get('users/{user}/posts/{post}')]
    #[ScopeBindings]
    public function getUserPost(User $user, Post $post)
    {
        return $post;
    }
}

Это похоже на использование метода ->scopeBindings() в регистраторе маршрутов вручную:

Route::get('/users/{user}/posts/{post}', function (User $user, Post $post) {
    return $post;
})->scopeBindings();

По умолчанию GSManager включает привязки к области действия на маршруте при использовании неявной привязки с пользовательским ключом в качестве вложенного параметра маршрута, такого как /users/{user}/posts/{post:slug}.

Чтобы отключить это поведение, вы можете передать атрибуту значение false:

#[ScopeBindings(false)]

Это эквивалентно вызову ->withoutScopedBindings() в регистраторе маршрутов вручную.

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

Указывающий, где

Вы можете использовать аннотацию Where в классе или методе, чтобы ограничить формат параметров вашего маршрута.

use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Post;
use GSManager\RouteAttributes\Attributes\Where;
use GSManager\RouteAttributes\Attributes\WhereAlphaNumeric;

#[Where('my-where', '[0-9]+')]
class MyController
{
    #[Get('my-get-route/{my-where}')]
    public function myGetMethod()
    {
    }

    #[Post('my-post-route/{my-where}/{my-alpha-numeric}')]
    #[WhereAlphaNumeric('my-alpha-numeric')]
    public function myPostMethod()
    {
    }
}

Эти аннотации автоматически зарегистрируют эти маршруты:

Route::get('my-get-route/{my-where}', [MyController::class, 'myGetMethod'])->where(['my-where' => '[0-9]+']);
Route::post('my-post-route/{my-where}/{my-alpha-numeric}', [MyController::class, 'myPostMethod'])->where(['my-where' => '[0-9]+', 'my-alpha-numeric' => '[a-zA-Z0-9]+']);

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

#[WhereAlpha('alpha')]
#[WhereAlphaNumeric('alpha-numeric')]
#[WhereIn('in', ['value1', 'value2'])]
#[WhereNumber('number')]
#[WhereUlid('ulid')]
#[WhereUuid('uuid')]

Specifying a group

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

use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Post;
use GSManager\RouteAttributes\Attributes\Domain;

#[Group(domain: 'my-subdomain.localhost', prefix: 'my-prefix')]
#[Group(domain: 'my-second-subdomain.localhost', prefix: 'my-second-prefix')]
class MyController
{
    #[Get('my-get-route')]
    public function myGetMethod()
    {
    }

    #[Post('my-post-route')]
    public function myPostMethod()
    {
    }
}

Эти аннотации автоматически зарегистрируют эти маршруты:

Route::get('my-get-route', [MyController::class, 'myGetMethod'])->prefix('my-prefix')->domain('my-subdomain.localhost');
Route::post('my-post-route', [MyController::class, 'myPostMethod'])->prefix('my-prefix')->domain('my-subdomain.localhost');
Route::get('my-get-route', [MyController::class, 'myGetMethod'])->prefix('my-second-prefix')->domain('my-second-subdomain.localhost');
Route::post('my-post-route', [MyController::class, 'myPostMethod'])->prefix('my-second-prefix')->domain('my-second-subdomain.localhost');

Указание значений по умолчанию

Вы можете использовать аннотацию Defaults для класса или метода, чтобы определить значения по умолчанию для ваших необязательных параметров маршрута.

use GSManager\RouteAttributes\Attributes\Defaults;
use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Post;

#[Defaults('param', 'controller-default')]
class MyController extends Controller
{
    #[Get('my-get-route/{param?}')]
    public function myGetMethod($param)
    {
    }

    #[Post('my-post-route/{param?}/{param2?}')]
    #[Defaults('param2', 'method-default')]
    public function myPostMethod($param, $param2)
    {
    }

    #[Get('my-default-route/{param?}/{param2?}/{param3?}')]
    #[Defaults('param2', 'method-default-first')]
    #[Defaults('param3', 'method-default-second')]
    public function myDefaultMethod($param, $param2, $param3)
    {
    }

    #[Get('my-override-route/{param?}')]
    #[Defaults('param', 'method-default')]
    public function myOverrideMethod($param)
    {
    }
}

Эти аннотации автоматически зарегистрируют эти маршруты:

Route::get('my-get-route/{param?}', [MyController::class, 'myGetMethod'])->setDefaults(['param', 'controller-default']);
Route::post('my-post-route/{param?}/{param2?}', [MyController::class, 'myPostMethod'])->setDefaults(['param', 'controller-default', 'param2' => 'method-default']);
Route::get('my-default-route/{param?}/{param2?}/{param3?}', [MyController::class, 'myDefaultMethod'])->setDefaults(['param', 'controller-default', 'param2' => 'method-default-first', 'param3' => 'method-default-second']);
Route::get('my-override-route/{param?}', [MyController::class, 'myOverrideMethod'])->setDefaults(['param', 'method-default']);

С разгромленным

Вы можете использовать аннотацию WithTrashed для класса или метода, чтобы включить привязки WithTrashed к модели. Вы можете явно переопределить поведение, используя WithTrashed(false), если оно применяется на уровне класса

use GSManager\RouteAttributes\Attributes\Get;
use GSManager\RouteAttributes\Attributes\Post;
use GSManager\RouteAttributes\Attributes\WithTrashed;

#[WithTrashed]
class MyController extends Controller
{
    #[Get('my-get-route/{param}')]
    #[WithTrashed]
    public function myGetMethod($param)
    {
    }

    #[Post('my-post-route/{param}')]
    #[WithTrashed(false)]    
    public function myPostMethod($param)
    {
    }

    #[Get('my-default-route/{param}')]
    public function myDefaultMethod($param)
    {
    }    
}

Эти аннотации автоматически зарегистрируют эти маршруты:

Route::get('my-get-route/{param}', [MyController::class, 'myGetMethod'])->WithTrashed();
Route::post('my-post-route/{param}', [MyController::class, 'myPostMethod'])->withTrashed(false);
Route::get('my-default-route/{param}', [MyController::class, 'myDefaultMethod'])->withTrashed();

Тестирование

composer test