Route

XinAdmin implements controller attribute-based routing, defining routes, middleware, and permissions by adding PHP Attribute annotations to controllers.

How It Works

AnnoRouteService scans all controller classes with #[RequestAttribute] annotation, parses class-level and method-level annotations, and automatically registers corresponding routes.

Core Components

ComponentNamespaceDescription
RequestAttributeXin\AnnoRoute\RequestAttributeController class-level annotation
GetRouteXin\AnnoRoute\Route\GetRouteGET request route annotation
PostRouteXin\AnnoRoute\Route\PostRoutePOST request route annotation
PutRouteXin\AnnoRoute\Route\PutRoutePUT request route annotation
DeleteRouteXin\AnnoRoute\Route\DeleteRouteDELETE request route annotation
QueryXin\AnnoRoute\Crud\QueryCRUD query list annotation
FindXin\AnnoRoute\Crud\FindCRUD find single annotation
CreateXin\AnnoRoute\Crud\CreateCRUD create annotation
UpdateXin\AnnoRoute\Crud\UpdateCRUD update annotation
DeleteXin\AnnoRoute\Crud\DeleteCRUD delete annotation

Controller Class Annotation

Use #[RequestAttribute] on controller class:

<?php

namespace App\Http\Controllers\Admin;

use Xin\AnnoRoute\RequestAttribute;

#[RequestAttribute(
    routePrefix: '/admin/user',
    abilitiesPrefix: 'admin',
    middleware: ['admin.auth'],
    authGuard: 'admin'
)]
class UserController extends Controller
{
    // Controller methods
}

Parameters:

ParameterTypeDefaultDescription
routePrefixstring''Route prefix, full route address is composed of this prefix + method annotation route
abilitiesPrefixstring''Permission abilities prefix, final permission is composed of this prefix + authorize
middlewarestring|array''Controller middleware
authGuardstring|nullnullAuthentication guard provider

Method Route Annotations

Use route annotations on controller methods to define individual routes:

GetRoute - GET Request

use Xin\AnnoRoute\Route\GetRoute;

#[GetRoute(
    route: '/list',
    authorize: 'user.list',
    middleware: ['throttle:60,1'],
    where: ['id' => '[0-9]+']
)]
public function list(): JsonResponse
{
    // ...
}

PostRoute - POST Request

use Xin\AnnoRoute\Route\PostRoute;

#[PostRoute(
    route: '/create',
    authorize: 'user.create',
    middleware: [],
    where: []
)]
public function create(): JsonResponse
{
    // ...
}

PutRoute - PUT Request

use Xin\AnnoRoute\Route\PutRoute;

#[PutRoute(
    route: '/{id}',
    authorize: 'user.update',
    where: ['id' => '[0-9]+']
)]
public function update(int $id): JsonResponse
{
    // ...
}

DeleteRoute - DELETE Request

use Xin\AnnoRoute\Route\DeleteRoute;

#[DeleteRoute(
    route: '/{id}',
    authorize: 'user.delete',
    where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
    // ...
}

Route Annotation Parameters:

ParameterTypeDefaultDescription
routestring''Route address, relative to class-level routePrefix
authorizestring|booltruePermission ability string, true means no permission required, false means no login required
middlewarestring|array''Route middleware
wherearray[]Route parameter regex constraints, e.g., ['id' => '[0-9]+']

CRUD Annotations

CRUD annotations are class-level annotations. When used, they automatically look for $service property in the controller as the repository class and generate corresponding route handler closures.

Define Repository Service

Controller must define $service property:

<?php

namespace App\Http\Controllers\Admin;

use App\Repository\UserRepository;
use Xin\AnnoRoute\RequestAttribute;
use Xin\AnnoRoute\Crud\Query;
use Xin\AnnoRoute\Crud\Find;
use Xin\AnnoRoute\Crud\Create;
use Xin\AnnoRoute\Crud\Update;
use Xin\AnnoRoute\Crud\Delete;

#[RequestAttribute(routePrefix: '/admin/user', abilitiesPrefix: 'admin')]
#[Query, Find, Create, Update, Delete]
class UserController extends Controller
{
    protected string $service = UserRepository::class;
}

Query - Query List

#[Query(
    middleware: ['throttle:60,1'],
    where: []
)]
  • HTTP Method: GET
  • Route Address: /
  • Default Permission: query
  • Repository Method: query($request->query())

Find - Find Single

#[Find(
    middleware: [],
    where: ['id' => '[0-9]+']
)]
  • HTTP Method: GET
  • Route Address: /{id}
  • Default Permission: find
  • Route Constraint: id must be numeric
  • Repository Method: find($id)

Create - Create New

#[Create(
    middleware: [],
    where: []
)]
  • HTTP Method: POST
  • Route Address: /
  • Default Permission: create
  • Repository Method: create($request->all())

Update - Update

#[Update(
    middleware: [],
    where: ['id' => '[0-9]+']
)]
  • HTTP Method: PUT
  • Route Address: /{id}
  • Default Permission: update
  • Route Constraint: id must be numeric
  • Repository Method: update($id, $request->all())

Delete - Delete

#[Delete(
    middleware: [],
    where: ['id' => '[0-9]+']
)]
  • HTTP Method: DELETE
  • Route Address: /{id}
  • Default Permission: delete
  • Route Constraint: id must be numeric
  • Repository Method: delete($id)

Complete Examples

Example 1: Using CRUD Annotations

<?php

namespace App\Http\Controllers\Admin;

use App\Repository\ArticleRepository;
use Xin\AnnoRoute\RequestAttribute;
use Xin\AnnoRoute\Crud\Query;
use Xin\AnnoRoute\Crud\Find;
use Xin\AnnoRoute\Crud\Create;
use Xin\AnnoRoute\Crud\Update;
use Xin\AnnoRoute\Crud\Delete;

#[RequestAttribute(
    routePrefix: '/admin/article',
    abilitiesPrefix: 'admin',
    middleware: ['admin.auth']
)]
#[Query, Find, Create, Update, Delete]
class ArticleController extends Controller
{
    public function __construct(
        protected ArticleService $service
    ) {}
}

Generated Routes:

MethodRoutePermissionDescription
GET/admin/articleadmin.queryQuery article list
GET/admin/article/{id}admin.findFind single article
POST/admin/articleadmin.createCreate article
PUT/admin/article/{id}admin.updateUpdate article
DELETE/admin/article/{id}admin.deleteDelete article

Generated Routes:

MethodRoutePermissionDescription
GET/admin/useradmin.queryQuery user list
GET/admin/user/{id}admin.findFind single user
POST/admin/user/importuser.importImport users
GET/admin/user/exportuser.exportExport users
POST/admin/user/toggle-status/{id}user.toggleToggle user status

Example 2: Public Endpoints Without Permission Control

<?php

namespace App\Http\Controllers\Api;

use Xin\AnnoRoute\RequestAttribute;
use Xin\AnnoRoute\Route\GetRoute;
use Xin\AnnoRoute\Route\PostRoute;

#[RequestAttribute(routePrefix: '/api/public')]
class PublicController extends Controller
{
    #[GetRoute(route: '/banner')]
    public function banner(): JsonResponse
    {
        // Requires login...
    }

    #[PostRoute(route: '/feedback', authorize: false)]
    public function feedback(): JsonResponse
    {
        // No permission verification...
    }
}

authorize Parameter:

ValueDescription
trueRequires login, uses default permission check
falseRequires login, but does not check specific permission ability
stringRequires login, and checks specified permission ability

Route Annotation Common Properties

All route annotations inherit from BaseAttribute with the following properties:

PropertyTypeDescription
routestringRoute address
middlewarestring|arrayMiddleware
httpMethodstringHTTP request method
authorizestring|boolPermission ability
wherearrayRoute parameter regex constraints

Middleware Composition

Middleware can be set globally (class-level) and locally (method-level), and will be merged:

#[RequestAttribute(
    routePrefix: '/admin/user',
    middleware: ['admin.auth']  // Global middleware
)]
class UserController extends Controller
{
    #[PostRoute(
        route: '/create',
        middleware: ['throttle:60,1']  // Additional local middleware
    )]
    public function create(): JsonResponse
    {
        // Final middleware: ['admin.auth', 'throttle:60,1']
    }
}

Permission Ability Composition

Permission ability is composed of abilitiesPrefix and authorize:

#[RequestAttribute(
    routePrefix: '/admin/user',
    abilitiesPrefix: 'admin'  // Abilities prefix
)]
#[Create]
class UserController extends Controller
{
    // Create annotation's authorize defaults to 'create'
    // Final permission ability: 'admin.create'
}