Framework Slim 4 cho người mới bắt đầu
- Kiến thức công nghệ 10-09-2024 22:04
- PHP 8
- Composer
Giới thiệu Chào mừng đến với hướng dẫn Slim 4!
Trong hướng dẫn này, chúng ta sẽ khám phá những kiến thức cơ bản về Slim 4, một micro-framework PHP nhẹ và mạnh mẽ, giúp xây dựng các ứng dụng web và RESTful API hiệu quả và dễ mở rộng.
Cài đặt Để thiết lập dự án Slim 4 của bạn, thực hiện các bước sau:
-
Tạo một thư mục dự án mới.
-
Cài đặt gói Slim chính bằng Composer:
composer require slim/slim
Slim 4 đã tách rời hầu hết các triển khai khỏi lõi của App.
Tiếp theo, chúng ta cần các gói để quản lý các yêu cầu và phản hồi HTTP trong ứng dụng. Các gói Nyholm PSR-7 cung cấp việc triển khai tiêu chuẩn PSR-7 nhanh nhất và chặt chẽ nhất cho các thông điệp HTTP.
Cài đặt các gói, chạy lệnh sau:
composer require nyholm/psr7
composer require nyholm/psr7-server
Bây giờ chúng ta đã cài đặt các phụ thuộc cơ bản nhất cho dự án. Sau này chúng ta sẽ thêm các phụ thuộc khác.
Lưu ý không bao gồm thư mục vendor/
vào kho Git của bạn. Để tránh điều này, tạo một file .gitignore
trong thư mục gốc của dự án và thêm các dòng sau:
vendor/
.idea/
.env
Cấu trúc thư mục Một cấu trúc thư mục được tổ chức tốt là rất cần thiết cho việc tổ chức mã và tăng cường bảo mật tổng thể của ứng dụng.
Trong một ứng dụng web, điều quan trọng là phải phân biệt giữa các khu vực công khai và không công khai.
Thư mục public/
có thể truy cập trực tiếp từ web bởi tất cả các trình duyệt và khách hàng API.
Tất cả các thư mục khác (trong thư mục gốc của dự án) phải không công khai và không được truy cập từ web.
Tạo thư mục mới: public/
Trong các bước tiếp theo của hướng dẫn này, chúng ta sẽ tạo một cấu trúc thư mục dự án như sau:
.
├── config/ Các tệp cấu hình
├── public/ Các tệp máy chủ web (DocumentRoot)
│ └── index.php Bộ điều khiển chính
├── src/ Mã nguồn PHP (Namespace App)
├── vendor/ Dành riêng cho composer
├── .gitignore Quy tắc git ignore
└── composer.json Các phụ thuộc dự án
Tự động tải (Autoloader) Để quản lý việc tải các lớp PHP trong dự án, chúng ta cần một Autoloader PSR-4.
PSR-4 định nghĩa tiêu chuẩn cho việc đặt tên và cấu trúc thư mục lớp, giúp dễ dàng tổ chức và tải tự động các lớp mà không cần lệnh require
thủ công.
Tạo thư mục mới: src/
Thêm phần tự động tải sau vào file composer.json
của bạn:
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
Với cấu hình này, ứng dụng của bạn sẽ tự động tải tất cả các lớp trong namespace \App
từ thư mục src/
.
Đây là cách file composer.json
hoàn chỉnh của bạn sẽ trông như thế nào:
{
"require": {
"nyholm/psr7": "^1",
"nyholm/psr7-server": "^1",
"slim/slim": "^4"
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}
Chạy composer update
để áp dụng thay đổi.
Cấu hình Hãy thiết lập các tệp cấu hình.
Thư mục dành cho tất cả các tệp cấu hình là: config/
Tạo thư mục config/
trong dự án của bạn.
Bên trong thư mục config/
, tạo tệp tên là settings.php
.
Sao chép và dán nội dung sau vào config/settings.php
:
<?php
// Nên đặt thành 0 trong môi trường sản xuất
error_reporting(E_ALL);
// Nên đặt thành '0' trong môi trường sản xuất
ini_set('display_errors', '1');
// Cài đặt
$settings = [];
// ...
return $settings;
Tệp settings.php
này đóng vai trò là tệp cấu hình chính, hợp nhất các cài đặt mặc định với các cài đặt dành riêng cho môi trường.
Bạn có thể điền thêm mảng $settings
với các tùy chọn cấu hình cụ thể của dự án.
Container DI
Tiêm phụ thuộc là một kỹ thuật lập trình tách việc tạo đối tượng khỏi việc sử dụng chúng, nhằm mục tiêu tạo ra các chương trình lỏng lẻo gắn kết.
Không sử dụng tiêm phụ thuộc, các lớp thường mã hóa cứng các phụ thuộc của chúng.
Tiêm phụ thuộc tách các mối quan tâm bằng cách đảm bảo rằng các đối tượng nhận được các phụ thuộc cần thiết từ "bên ngoài". Tiêm phụ thuộc qua constructor là hình thức phổ biến nhất, nơi các phụ thuộc được truyền qua constructor.
Ví dụ:
final class Logger
{
public function log(string $message): void
{
echo "Logging: " . $message . "\n";
}
}
final class UserCreator
{
private Logger $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function createUser(string $username): void
{
// ...
$this->logger->log("User created: " . $username);
}
}
// Sử dụng
$logger = new Logger();
$userCreator = new UserCreator($logger);
$userCreator->createUser('john.doe');
Việc xây dựng phụ thuộc một cách thủ công có thể trở nên phức tạp, trong khi một Container Tiêm Phụ Thuộc (DI Container) như PHP-DI có thể tự động hóa quá trình này, xem thêm Autowiring.
Để cài đặt PHP-DI, chạy lệnh:
composer require php-di/php-di
Định Nghĩa Container DI
Tạo một tệp mới cho các mục trong container DI: config/container.php
và sao chép/dán nội dung sau:
<?php
use Psr\Container\ContainerInterface;
use Slim\App;
use Slim\Factory\AppFactory;
return [
'settings' => function () {
return require __DIR__ . '/settings.php';
},
App::class => function (ContainerInterface $container) {
$app = AppFactory::createFromContainer($container);
// Đăng ký các route
(require __DIR__ . '/routes.php')($app);
// Đăng ký middleware
(require __DIR__ . '/middleware.php')($app);
return $app;
},
];
Lưu ý rằng chúng ta sử dụng container DI để xây dựng instance của Slim App và tải các cài đặt ứng dụng. Điều này cho phép chúng ta cấu hình các dịch vụ hạ tầng, như kết nối cơ sở dữ liệu, mailer, v.v., trong container DI. Tất cả các cài đặt chỉ được truyền dưới dạng một mảng đơn giản, vì vậy chúng ta không có định danh lớp đặc biệt (FQCN) ở đây.
Định danh App::class
được cần để đảm bảo rằng chúng ta sử dụng cùng một đối tượng App trên toàn bộ ứng dụng và đảm bảo rằng đối tượng App sử dụng cùng một đối tượng container DI.
Hãy chắc chắn rằng bạn thêm các lệnh use
cần thiết ở đầu tệp PHP để đảm bảo rằng các namespace đúng được định nghĩa.
Khởi Động (Bootstrap)
Quá trình khởi động ứng dụng chứa mã được thực thi khi ứng dụng (yêu cầu) bắt đầu.
Quy trình bootstrap bao gồm autoloader của Composer và sau đó tiếp tục xây dựng container DI, tạo ứng dụng và đăng ký các route + middleware.
Tạo tệp bootstrap: config/bootstrap.php
và sao chép/dán nội dung sau:
<?php
use DI\ContainerBuilder;
use Slim\App;
require_once __DIR__ . '/../vendor/autoload.php';
// Xây dựng instance của container DI
$container = (new ContainerBuilder())
->addDefinitions(__DIR__ . '/container.php')
->build();
// Tạo instance của App
return $container->get(App::class);
Bộ Điều Khiển Chính (Front Controller)
Bộ điều khiển chính là điểm nhập của ứng dụng Slim của bạn và xử lý tất cả các yêu cầu bằng cách chuyển hướng các yêu cầu qua một đối tượng xử lý duy nhất.
Vì lý do bảo mật, bạn luôn nên đặt bộ điều khiển chính (index.php
) vào thư mục public/
. Bạn không bao giờ nên đặt bộ điều khiển chính trực tiếp vào thư mục gốc của dự án.
Tạo tệp bộ điều khiển chính: public/index.php
và sao chép/dán nội dung sau:
<?php
(require __DIR__ . '/../config/bootstrap.php')->run();
Lưu ý: Thư mục public/
chỉ là DocumentRoot
của máy chủ web của bạn, nhưng nó không bao giờ là phần của đường dẫn cơ bản và URL chính thức.
URL tốt:
https://www.example.com
https://www.example.com/users
https://www.example.com/my-app
https://www.example.com/my-app/users
URL không tốt:
https://www.example.com/public
https://www.example.com/public/users
https://www.example.com/public/index.php
https://www.example.com/my-app/public
https://www.example.com/my-app/public/users
Middleware
Middleware có thể được thực thi trước và sau khi ứng dụng Slim của bạn để đọc hoặc thao tác đối tượng yêu cầu và phản hồi.
Để chạy Slim, chúng ta cần thêm RoutingMiddleware
và ErrorMiddleware
của Slim.
- RoutingMiddleware sẽ định tuyến và phân phối các yêu cầu đến.
- ErrorMiddleware có thể bắt tất cả các ngoại lệ để hiển thị một trang lỗi đẹp mắt.
- BodyParsingMiddleware là tùy chọn, nhưng khuyến nghị nếu bạn làm việc với dữ liệu JSON hoặc form.
Tạo tệp: config/middleware.php
để thiết lập các middleware toàn cục và sao chép/dán nội dung sau:
<?php
use Slim\App;
return function (App $app) {
// Phân tích json, dữ liệu form và xml
$app->addBodyParsingMiddleware();
// Thêm middleware định tuyến tích hợp của Slim
$app->addRoutingMiddleware();
// Xử lý ngoại lệ
$app->addErrorMiddleware(true, true, true);
};
Routes
Một route là một đường dẫn URL có thể ánh xạ đến một trình xử lý cụ thể. Trình xử lý đó có thể là một hàm đơn giản hoặc một lớp có thể gọi được (invokable class). Bên dưới, Slim sử dụng gói nikic/FastRoute
, nhưng cũng thêm một số tính năng hay cho các nhóm định tuyến, tên và middleware, v.v.
Các route của ứng dụng sẽ được định nghĩa trong các tệp PHP thuần túy.
Tạo tệp: config/routes.php
và sao chép/dán nội dung sau:
<?php
use Slim\App;
return function (App $app) {
// trống
};
Route đầu tiên
Mở tệp config/routes.php
và chèn mã cho route đầu tiên:
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\App;
return function (App $app) {
$app->get('/', function (ServerRequestInterface $request, ResponseInterface $response) {
$response->getBody()->write('Hello, World!');
return $response;
});
};
Mở một cửa sổ console mới và khởi động máy chủ phát triển tích hợp bằng lệnh sau:
php -S localhost:8080 -t public/
Terminal sẽ hiển thị:
[Sat Aug 6 10:38:50 2022] PHP 8.x Development Server (http://localhost:8080) started
Lưu ý: Máy chủ web này được thiết kế để hỗ trợ phát triển ứng dụng. Nó cũng có thể hữu ích cho mục đích kiểm thử hoặc cho các trình diễn ứng dụng được chạy trong các môi trường kiểm soát. Nó không được thiết kế để làm máy chủ web đầy đủ tính năng và không nên được sử dụng trong mạng công cộng.
- Tham số
-S localhost:8080
xác định tên máy chủ và cổng. - Tham số
-t public/
chỉ định thư mục gốc tài liệu với tệpindex.php
.
Bây giờ, mở trang web của bạn, ví dụ: http://localhost:8080 và bạn sẽ thấy thông điệp: Hello, World!
Để đơn giản hóa bước này, bạn có thể thêm một lệnh script start
và khóa process-timeout
vào tệp composer.json
của mình:
"config": {
"process-timeout": 0
},
"scripts": {
"start": "php -S localhost:8080 -t public/"
}
Để dừng máy chủ web tích hợp, nhấn: Ctrl+C
.
Để khởi động lại máy chủ web tích hợp, bạn có thể sử dụng lệnh:
composer start
Controller Hành Động Đơn (Single Action Controller)
Slim cung cấp một số phương pháp để thêm logic controller trực tiếp trong callback route. Đối tượng yêu cầu/phản hồi (và tùy chọn là các đối số route) được Slim truyền cho một hàm callback như sau:
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
// ...
$app->get('/', function (ServerRequestInterface $request, ResponseInterface $response) {
$response->getBody()->write('Hello, World!');
return $response;
});
Giao diện như vậy có thể trông trực quan, nhưng không phù hợp cho các kịch bản phức tạp hơn.
Các hàm ẩn danh (anonymous functions) như trình xử lý định tuyến khá "đắt đỏ", vì PHP phải tạo tất cả các hàm cho mỗi yêu cầu. Việc sử dụng tên lớp nhẹ hơn, nhanh hơn và mở rộng tốt hơn cho các ứng dụng lớn hơn. Trừ khi logic của bạn rất đơn giản, tôi không khuyến nghị sử dụng các hàm callback. Đây là lúc Controller Hành Động Đơn (Single Action Controller) xuất hiện.
Mỗi Controller Hành Động Đơn được đại diện bởi một lớp riêng và chỉ có một phương thức công khai duy nhất.
Action chỉ làm những việc sau:
- Thu thập đầu vào từ yêu cầu HTTP (nếu cần)
- Gọi Domain với các đầu vào đó (nếu yêu cầu) và giữ lại kết quả
- Xây dựng một phản hồi HTTP (thường với kết quả gọi Domain)
Tất cả các logic khác, bao gồm tất cả các hình thức xác thực đầu vào, xử lý lỗi, v.v., do đó được đẩy ra khỏi Action và vào Domain (cho các vấn đề logic domain) hoặc bộ xử lý phản hồi (cho các vấn đề logic trình bày).
Một phản hồi có thể được hiển thị dưới dạng HTML cho một yêu cầu web tiêu chuẩn; hoặc có thể là JSON cho một RESTful API.
Tạo thư mục con: src/Action
Tạo lớp action này trong: src/Action/HomeAction.php
<?php
namespace App\Action;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class HomeAction
{
public function __invoke(Request $request, Response $response): Response
{
$response->getBody()->write('Hello, World!');
return $response;
}
}
Sau đó, mở config/routes.php
và thay thế closure của route /
bằng dòng sau:
$app->get('/', \App\Action\HomeAction::class);
Tệp config/routes.php
hoàn chỉnh bây giờ sẽ trông như sau:
<?php
use Slim\App;
return function (App $app) {
$app->get('/', \App\Action\HomeAction::class);
};
Bây giờ, mở URL của bạn, ví dụ: http://localhost:8080 và bạn sẽ thấy thông điệp Hello, World!
Tạo Phản Hồi JSON
Để tạo một phản hồi JSON hợp lệ, bạn có thể viết chuỗi đã mã hóa JSON vào thân phản hồi và đặt tiêu đề Content-Type
thành application/json
:
<?php
namespace App\Action;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class HomeAction
{
public function __invoke(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['hello' => 'world']));
return $response->withHeader('Content-Type', 'application/json');
}
}
Mở trang web của bạn, ví dụ: http://localhost:8080 và bạn sẽ thấy phản hồi JSON:
{"hello":"world"}
Kết Luận
Nhớ các mối quan hệ:
- Slim: Để xử lý định tuyến và phân phối
- Single Action Controllers: Xử lý yêu cầu và phản hồi
Slim tuân theo triết lý Unix về việc lựa chọn phần mềm và lập trình trong thời đại hiện đại, chọn và viết các chương trình thực hiện một việc và thực hiện nó tốt.
Slim cung cấp một nền tảng vững chắc cho các gói có thể được cài đặt khi cần. Nhờ các interface PSR, Composer và container DI, các gói có thể được thay thế một cách dễ dàng. Các bản cập nhật có thể được thực hiện theo các bước nhỏ mà không gây rủi ro quá nhiều.
Slim không ép buộc bạn phải tuân theo các khuôn khổ nghiêm ngặt như các framework lớn khác. Bạn cũng không bị ép buộc sử dụng bất kỳ anti-pattern nào (ví dụ: facade hoặc active-record), và bạn có thể xây dựng mã hiện đại, sạch sẽ.
Hatonet kết nối doanh nghiệp ITO toàn cầu.
Giúp các doanh nghiệp IT Việt Nam tiết kiệm chi phí,tìm kiếm
đối tác,mở rộng mạng lưới.
- Mở rộng kênh tìm kiếm khách hàng gia tăng doanh thu.
- Tiết kiệm chi phí quan hệ tìm đối tác.
- Ứng tuyển trực tuyến bất cứ lúc nào khi có yêu cầu.
- Trực tiếp liên kết với công ty quốc tế
Liên hệ :
Email: hello@hatonet.vn
Zalo: https://zalo.me/hatonet
Copy URL