gsmanager-cloud / route-attributes
Auto register routes using PHP attributes
Requires
- php: ^8.0
- gsmanager-cloud/contracts: v1
- nesbot/carbon: ^2.63|^3.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^9.5.10|^10.5|^11.5.3
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