Hướng dẫn cakePHP 4 routing

  • September 1, 2022
  • 920

Mặc định cakePHP framework đã build sẵn, có thể tự động matching url mà không cần khai báo route. Điều này chúng ta đã biết khi tìm hiểu về cakephp conventions. Ngoài ra, cakePHP cũng cho phép chúng ta tự khai báo route. Hôm nay chúng ta cùng tìm hiểu về cakePHP routing nhé.

Define routing cakePHP 4

Các routing được định nghĩa trong file config/routes.php. Cakephp 4 sử dụng class Cake\Routing\RouterBuilder để mapping URL với controller action. Định nghĩa 1 route lấy tất cả các bài viết


$routes->connect('/articles', ['controller' => 'Articles', 'action' => 'index']);

Giờ khi truy cập vào url {domain}/articles sẽ mapping đến method index trong controller Articles.

Các khai báo route hay dùng

1. Truyền tham số cho action


// routes.php
$routes->connect(
    '/articles/{id}',
    ['controller' => 'Articles', 'action' => 'view']
)
->setPass(['id'])
->setPatterns([
    'id' => '\d+',
]);

// Viết ngắn ngọn hơn
$routes->connect(
    '/articles/{id}',
    ['controller' => 'Articles', 'action' => 'view'],
    ['id' => '\d+', 'pass' => ['id']]
);
// src/Controller/ArticlesController.php
public function view($id = null)
{
    // Some code here...
}

Với khai báo trên ta đã validate {id} trên url bắt buộc phải là số, khi truy cập vào url /articles/{id} mapping với controller Articles action view và tham số id trên url sẽ là đối số $id của action view.

2. Đặt tên cho route


// Đặt tên cho route dùng hàm connect.
$routes->connect(
    '/login',
    ['controller' => 'Members', 'action' => 'login'],
    ['_name' => 'login']
);

// Đặt tên khi sử dụng specific route
$routes->post(
    '/logout',
    ['controller' => 'Members', 'action' => 'logout'],
    'logout'
);

3. Định nghĩa route theo group

Để group các route lại với nhau cakePHP sử dụng hàm scope(). Việc gom nhóm giúp không bị lặp code


// Code chưa gom nhóm
$routes->connect('/articles', ['controller' => 'Articles', 'action' => 'index']);
$routes->connect(
    '/articles/{id}',
    ['controller' => 'Articles', 'action' => 'view'],
    ['id' => '\d+', 'pass' => ['id']]
  );

// Code đã gom nhóm
$routes->scope('/articles', function (RouteBuilder $routes) {
  $routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);
  $routes->connect(
    '/{id}',
    ['controller' => 'Articles', 'action' => 'view'],
    ['id' => '\d+', 'pass' => ['id']]
  );
})

// Gom nhóm và set sub namespace cho controller
$routes->scope('/admins', ['prefix' => 'Admins'], function (RouteBuilder $routes) {
  $routes->scope('/articles', function (RouteBuilder $routes) {
    $routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);
    $routes->connect(
      '/{id}',
      ['controller' => 'Articles', 'action' => 'view'],
      ['id' => '\d+', 'pass' => ['id']]
    );
  })
})

4. Matching Specific HTTP Methods

Phần này giúp giới hạn http request đến controller action, có thể chỉ cho phép 1 phương thức HTTP hoặc nhiều.


$routes->scope('/articles', function (RouteBuilder $routes) {
    // route này cho mapping với POST request.
    $routes->post(
        '/',
        ['controller' => 'Articles', 'action' => 'store']
    );

    // route này cho mapping với POST hoặc PUT request.
    $routes->connect(
        '/{id}',
        [
            'controller' => 'Articles',
            'action' => 'edit',
        ]
    )->setMethods(['POST', 'PUT']);
});

5. Route middleware

Khi muốn sử dụng middleware trong 1 scope đầu tiên bạn cần đăng kí middleware đó.


use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Http\Middleware\EncryptedCookieMiddleware;

$routes->scope('/', function (RouteBuilder $routes) {
  $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
  $routes->registerMiddleware('cookies', new EncryptedCookieMiddleware());
});

Sau đó mới có thể sử dụng middleware


use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Http\Middleware\EncryptedCookieMiddleware;

$routes->scope('/', function (RouteBuilder $routes) {
  $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
  $routes->registerMiddleware('cookies', new EncryptedCookieMiddleware());
  $routes->scope('/cms', function (RouteBuilder $routes) {
    // Enable CSRF & cookies middleware
    $routes->applyMiddleware('csrf', 'cookies');
    $routes->get('/articles/{action}/*', ['controller' => 'Articles'])
  });
});

// Gom nhóm middleware
$routes->registerMiddleware('cookie', new EncryptedCookieMiddleware());
$routes->registerMiddleware('auth', new AuthenticationMiddleware());
$routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
$routes->middlewareGroup('web', ['cookie', 'auth', 'csrf']);

// Apply the group
$routes->applyMiddleware('web');

6. RESTful Routing

Khai báo routing dùng cho restful api. Khi viết resfull api chúng ta sẽ rất hay sử dụng resource route, và cakePhp 4 cũng có luôn.


$routes->scope('/api', function (RouteBuilder $routes) {
    $routes->setExtensions(['json']);
    $routes->resources('articles');
});

Nhưng vậy là đã khai báo được resourec api cho controler Articles


/api/articles
/api/articles/{id}

7. Resource Routes


// Nested Resource Route
$routes->scope('/api', function (RouteBuilder $routes) {
    $routes->resources('Articles', function (RouteBuilder $routes) {
        $routes->resources('Comments');
    });
});

// Mapching with url
/api/articles/{article_id}/comments
/api/articles/{article_id}/comments/{id}

// Định nghĩa thêm route cho Resource Route
$routes->resources('Articles', [
   'map' => [
       'deleteAll' => [
           'action' => 'deleteAll',
           'method' => 'DELETE'
       ]
   ]
]);
// This would connect /articles/deleteAll

// Giới hạn route resources
$routes->resources('Articles', [
    'only' => ['index', 'view']
]);

8. Redirect Routing


$routes->scope('/', function (RouteBuilder $routes) {
    $routes->redirect('/articles/*', 'https://google.com', ['status' => 302]);
});
9. Custom route

Chia file route thành nhiều file nhỏ, tạo thư mục config/Routes để gom nhóm các route cùng chức năng sau đó require vào file route


// Chia nhỏ file route
// Router api v1
if (file_exists(CONFIG . 'Routers/Api/version1.php')) {
    require(CONFIG . 'Routers/Api/version1.php');
}

// Router api v2
if (file_exists(CONFIG . 'Routers/Api/version2.php')) {
    require(CONFIG . 'Routers/Api/version2.php');
}
// Router admin
if (file_exists(CONFIG . 'Routers/admin.php')) {
    require(CONFIG . 'Routers/admin.php');
}

Tạo file config/Routers/Api/version1.php để định nghĩa các route cho api version 1


<?php
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;

/** @var \Cake\Routing\RouteBuilder $routes */
$routes->setRouteClass(DashedRoute::class);
$routes->scope('/api/v1', ['prefix' => 'Api/V1'], function (RouteBuilder $routes) {
    $routes->setExtensions(['json']);

    // Devices
    $routes->resources('Devices');
});

Tạo file config/Routers/admin.php định nghĩa các route cho admin


<?php
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use App\Middleware\BasicAuthMiddleware;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;

/** @var \Cake\Routing\RouteBuilder $routes */
$routes->setRouteClass(DashedRoute::class);

$routes->scope('/admin', ['prefix' => 'Admin'], function (RouteBuilder $routes) {
    $csrf = new CsrfProtectionMiddleware([
        'httponly' => true,
    ]);
    $routes->registerMiddleware('csrf', $csrf);
    $routes->registerMiddleware('basicAuth', new BasicAuthMiddleware());
    $routes->middlewareGroup('web', ['csrf', 'basicAuth']);
    $routes->applyMiddleware('web');

    // Admins.
    $routes->connect('/',
        ['controller' => 'Admins', 'action' => 'index'],
        ['_name' => 'admins.index']);

    $routes->fallbacks();
});

Generating URLs

Nếu bạn muốn tạo url thì dùng các phương thức sau


// Tạo link /articles/view/{$id}
$this->Html->link('View', '/articles/view/' . $id);
$this->Html->link(
    'View',
    ['controller' => 'Articles', 'action' => 'view', $id]
);

// Tạo url /articles/index?page=1#top
$routes->url([
    'controller' => 'Articles',
    'action' => 'index',
    '?' => ['page' => 1],
    '#' => 'top'
]);

Như vậy là chúng ta đã tự định nghĩa route cho ứng dụng xong. Hi vọng bài viết giúp ích được cho bạn. Thanks for reading...