Tạo và chạy dự án Webman trên ServBay
Webman là gì?
Webman là một framework PHP web hiệu năng cao dựa trên Workerman và được thiết kế để xây dựng ứng dụng web có khả năng xử lý đồng thời và hiệu năng vượt trội. Khác biệt với các framework đồng bộ truyền thống, Webman sử dụng mô hình xử lý sự kiện và I/O bất đồng bộ không chặn, đảm bảo khả năng đáp ứng xuất sắc khi phục vụ lượng lớn yêu cầu đồng thời. Webman cung cấp API thân thiện, dễ sử dụng và hệ thống mở rộng linh hoạt, rất phù hợp để xây dựng ứng dụng realtime, API services, microservices, v.v.
Tính năng và ưu điểm nổi bật của Webman
- Hiệu năng cao: Xây dựng trên Workerman, tận dụng cơ chế sự kiện và I/O bất đồng bộ, xử lý hàng nghìn kết nối đồng thời, thông lượng vượt trội so với framework truyền thống.
- Dễ sử dụng: API đơn giản, rõ ràng và đủ tính năng, giúp lập trình viên nhanh chóng bắt tay vào phát triển ứng dụng.
- Hỗ trợ nhiều giao thức: Tích hợp sẵn HTTP, WebSocket và các giao thức tầng ứng dụng phổ biến – tiện lợi cho nhiều loại dịch vụ.
- Khả năng mở rộng linh hoạt: Hỗ trợ mở rộng qua package Composer, plugins, middleware.
- Tiết kiệm tài nguyên: Hoạt động như tiến trình thường trú trên bộ nhớ, tiết kiệm hơn so với mô hình server web truyền thống + PHP-FPM.
- Cộng đồng mạnh mẽ: Sở hữu cộng đồng phát triển sôi động và đa dạng tài liệu hỗ trợ.
Webman giúp bạn xây dựng nhanh chóng những ứng dụng web và API hiệu năng, độ ổn định cao, đặc biệt thích hợp cho các bài toán cần xử lý đồng thời lớn, độ trễ thấp.
Tạo và chạy dự án Webman đơn giản với ServBay
Hướng dẫn này sẽ trình bày chi tiết cách tạo và chạy một dự án Webman đơn giản trong môi trường phát triển cục bộ ServBay. Bạn sẽ biết cách cài đặt Webman, viết code route và controller cơ bản, tích hợp với các dịch vụ database (MySQL, PostgreSQL) và bộ nhớ đệm (Redis, Memcached) mà ServBay cung cấp.
TIP
ServBay khuyến nghị bạn lưu tất cả project website cục bộ tại thư mục /Applications/ServBay/www
để thuận tiện cho việc quản lý, cấu hình website (hay còn gọi là “host cục bộ”).
Yêu cầu trước khi bắt đầu
Hãy chắc chắn bạn đã chuẩn bị những điều sau:
- Cài đặt ServBay: Bạn đã cài thành công ServBay trên macOS. ServBay là môi trường phát triển tích hợp, bao gồm PHP, Composer, MySQL, PostgreSQL, Redis, Memcached, v.v. – đủ mọi công cụ cần thiết cho bài hướng dẫn này.
- Kích hoạt các gói phần mềm cần thiết: Kiểm tra bằng bảng điều khiển ServBay, những gói sau đã được cài đặt và đang hoạt động:
- Phiên bản PHP bạn chọn (Khuyến nghị PHP 8.x trở lên)
- Composer (có sẵn trong ServBay)
- MySQL
- PostgreSQL
- Redis
- Memcached
- Đảm bảo PHP bạn chọn đã bật các extension quan trọng như
memcached
,redis
,pdo_mysql
,pdo_pgsql
. Thông thường ServBay sẽ bật sẵn, nhưng bạn có thể kiểm tra lại trong giao diện cấu hình PHP của ServBay.
- Truy cập terminal: Thành thạo thao tác với terminal của macOS.
Cài đặt Webman
Kiểm tra Composer đã hoạt động
ServBay tích hợp Composer sẵn, bạn có thể kiểm tra bằng lệnh dưới đây trong Terminal:
bashcomposer --version
1Thấy hiện đúng phiên bản Composer nghĩa là đã sẵn sàng.
Di chuyển đến thư mục website của ServBay
Mở Terminal và chuyển đến thư mục gốc dự án theo khuyến nghị:
bashcd /Applications/ServBay/www
1Tạo dự án Webman bằng Composer
Dùng lệnh
create-project
của Composer để cài đặt Webman vào một thư mục, đặt tên làservbay-webman-app
:bashcomposer create-project workerman/webman servbay-webman-app
1Composer sẽ tải Webman cùng các dependency về thư mục
servbay-webman-app
.Đi vào thư mục dự án mới
Sau khi hoàn tất, di chuyển vào thư mục dự án bạn vừa tạo:
bashcd servbay-webman-app
1Cài đặt các package cần thiết
Để demo database và cache, hãy cài thêm một số package qua Composer. Webman thường dùng
illuminate/database
(của Laravel) vàilluminate/redis
... Tham số-W
(--with-dependencies
) giúp tự động giải quyết các xung đột dependency.bashcomposer require -W illuminate/database illuminate/redis illuminate/pagination illuminate/events symfony/var-dumper
1Lệnh trên sẽ thêm ORM cho DB, Redis client, phân trang, dispatcher sự kiện và công cụ debug VarDumper.
Tạo cơ sở dữ liệu và bảng
Để sample code hoạt động, bạn cần tạo database và bảng users
trên cả MySQL và PostgreSQL của ServBay. Mặc định ServBay, user root
có password là password
.
Dùng công cụ quản trị database tích hợp của ServBay (như phpMyAdmin hoặc pgAdmin, mở từ panel ServBay) hoặc chạy lệnh SQL sau qua terminal.
Tạo database
webman_app
- MySQL:sql
CREATE DATABASE IF NOT EXISTS webman_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
1 - PostgreSQL:sql
CREATE DATABASE webman_app;
1
- MySQL:
Tạo bảng
users
trongwebman_app
- MySQL:sql
USE webman_app; CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
1
2
3
4
5
6
7 - PostgreSQL:sql
\c webman_app; -- Kết nối vào database vừa tạo CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
1
2
3
4
5
6
7
- MySQL:
Viết mã nguồn cho dự án web
Giờ chúng ta sẽ thêm code cho route, tạo controller và thực hiện logic giao tiếp database, cache.
Cấu hình route
Sửa file
config/route.php
tại thư mục gốc dự án và thêm đoạn sau:php<?php use Webman\Route; use app\controller\IndexController; use app\controller\CacheController; use app\controller\DatabaseController; // Định nghĩa route gốc, trỏ đến phương thức index của IndexController Route::any('/', [IndexController::class, 'index']); // Các route liên quan đến bộ nhớ đệm Route::any('/memcached', [CacheController::class, 'memcached']); Route::any('/redis', [CacheController::class, 'redis']); // Các route liên quan đến database Route::any('/mysql-add', [DatabaseController::class, 'mysqlAdd']); Route::any('/mysql', [DatabaseController::class, 'mysqlGet']); Route::any('/pgsql-add', [DatabaseController::class, 'pgsqlAdd']); Route::any('/pgsql', [DatabaseController::class, 'pgsqlGet']); // Có thể bổ sung các route khác tại đây...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21Tạo các file controller
Tạo các file
IndexController.php
,CacheController.php
vàDatabaseController.php
trong thư mụcapp/controller
và dán code dưới đây.app/controller/IndexController.php
: Xử lý request ở route/
.php<?php namespace app\controller; use support\Request; use support\Response; // Import lớp Response class IndexController { /** * Ví dụ xử lý request cho route gốc * @param Request $request Đối tượng Request hiện tại * @return Response Trả về một đối tượng Response */ public function index(Request $request): Response // Xác định rõ kiểu trả về { // Trả về nội dung text đơn giản return response('Hello ServBay & Webman!'); // Cập nhật thông báo chào mừng } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20app/controller/CacheController.php
: Demo dùng Memcached và Redis.php<?php namespace app\controller; use support\Request; use support\Response; use Memcached; // Import class Memcached use support\Redis; // Import Facade Redis của Webman class CacheController { /** * Demo sử dụng Memcached * @param Request $request * @return Response */ public function memcached(Request $request): Response { // Kết nối đến server Memcached, mặc định ServBay: 127.0.0.1:11211 $memcached = new Memcached(); $memcached->addServer('127.0.0.1', 11211); // Đặt giá trị vào cache, hiệu lực 60s $success = $memcached->set('servbay_key', 'Hello Memcached from ServBay!', 60); // Đặt key và value mẫu if (!$success) { return response('Failed to set Memcached key', 500); } // Lấy giá trị từ cache $value = $memcached->get('servbay_key'); // Lấy theo key // Trả về giá trị lấy được, hoặc thông báo không tìm thấy/nội dung hết hạn return response($value ?: 'Memcached key not found or expired'); // Bổ sung thông báo khi không có dữ liệu } /** * Demo sử dụng Redis * @param Request $request * @return Response */ public function redis(Request $request): Response { // Đặt giá trị key vào cache sử dụng Redis Facade của Webman Redis::set('servbay_redis_key', 'Hello Redis from ServBay!'); // Key và value mẫu // Lấy giá trị từ Redis $value = Redis::get('servbay_redis_key'); // Lấy theo key // Trả về giá trị lấy được hoặc báo không tìm thấy return response($value ?: 'Redis key not found'); // Thông báo khi không có dữ liệu } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52app/controller/DatabaseController.php
: Demo thao tác với MySQL và PostgreSQL.php<?php namespace app\controller; use support\Request; use support\Response; use support\Db; // Import Db Facade của Webman class DatabaseController { /** * Thêm user vào MySQL * @param Request $request * @return Response */ public function mysqlAdd(Request $request): Response { try { // Dùng Db Facade để insert user vào MySQL Db::connection('mysql')->table('users')->insert([ 'name' => 'ServBay Webman MySQL User', // Tên mẫu 'email' => '[email protected]', // Email mẫu 'created_at' => date('Y-m-d H:i:s') // Ngày tạo ]); return response('User added to MySQL'); // Phản hồi } catch (\Exception $e) { return response('Error adding user to MySQL: ' . $e->getMessage(), 500); // Báo lỗi nếu có } } /** * Lấy danh sách user từ MySQL * @param Request $request * @return Response */ public function mysqlGet(Request $request): Response { try { // Lấy tất cả user từ bảng users (MySQL) $users = Db::connection('mysql')->table('users')->get(); // Trả về danh sách dưới dạng JSON, kèm Content-Type ứng dụng JSON return response(json_encode($users), 200, ['Content-Type' => 'application/json']); } catch (\Exception $e) { return response('Error getting users from MySQL: ' . $e->getMessage(), 500); } } /** * Thêm user vào PostgreSQL * @param Request $request * @return Response */ public function pgsqlAdd(Request $request): Response { try { // Dùng Db Facade để insert user vào PostgreSQL Db::connection('pgsql')->table('users')->insert([ 'name' => 'ServBay Webman PgSQL User', // Tên mẫu 'email' => '[email protected]', // Email mẫu 'created_at' => date('Y-m-d H:i:s') // Ngày tạo ]); return response('User added to PostgreSQL'); // Phản hồi } catch (\Exception $e) { return response('Error adding user to PostgreSQL: ' . $e->getMessage(), 500); } } /** * Lấy danh sách user từ PostgreSQL * @param Request $request * @return Response */ public function pgsqlGet(Request $request): Response { try { // Lấy tất cả user từ bảng users (PostgreSQL) $users = Db::connection('pgsql')->table('users')->get(); // Trả về danh sách dưới dạng JSON, kèm Content-Type ứng dụng JSON return response(json_encode($users), 200, ['Content-Type' => 'application/json']); } catch (\Exception $e) { return response('Error getting users from PostgreSQL: ' . $e->getMessage(), 500); } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
Cấu hình kết nối cơ sở dữ liệu
Sửa file
config/database.php
ở thư mục dự án, điền thông tin kết nối của MySQL và PostgreSQL:- Host mặc định ServBay:
127.0.0.1
- Cổng:
3306
(MySQL),5432
(PostgreSQL) - User:
root
- Password:
password
php<?php /** * Cấu hình cơ sở dữ liệu */ return [ // Kết nối mặc định 'default' => 'mysql', // Danh sách cấu hình các kết nối 'connections' => [ 'mysql' => [ 'driver' => 'mysql', // Host và port mặc định của MySQL trên ServBay 'host' => '127.0.0.1', 'port' => 3306, // Tên database vừa tạo 'database' => 'webman_app', // Username mặc định MySQL của ServBay 'username' => 'root', // Password mặc định MySQL của ServBay 'password' => 'password', 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, 'engine' => null, ], 'pgsql' => [ 'driver' => 'pgsql', // Host và port mặc định PostgreSQL trên ServBay 'host' => '127.0.0.1', 'port' => 5432, // Tên database vừa tạo 'database' => 'webman_app', // Username mặc định PostgreSQL của ServBay 'username' => 'root', // Password mặc định PostgreSQL của ServBay 'password' => 'password', 'charset' => 'utf8', 'prefix' => '', 'schema' => 'public', 'sslmode' => 'prefer', // hoặc require, verify-ca, verify-full ], // Có thể bổ sung các kết nối khác tại đây... ], ];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46Lưu ý quan trọng: Trong môi trường production (triển khai thật), luôn thay đổi password mặc định và tránh để thông tin nhạy cảm hardcode trong code.
- Host mặc định ServBay:
Chạy dự án Webman
Webman được khởi động thông qua script start.php
để bật tiến trình Workerman – khác với mô hình PHP-FPM/Nginx/Apache truyền thống, Webman luôn thường trú trên bộ nhớ với I/O bất đồng bộ.
Ở thư mục gốc dự án (/Applications/ServBay/www/servbay-webman-app
), chạy lệnh sau để khởi động:
php start.php start
Bạn sẽ thấy thông báo khởi động Webman, mặc định lắng nghe HTTP tại 127.0.0.1:8787
.
- Lưu ý: Lệnh
php
ở đây sử dụng phiên bản PHP đã cài cùng ServBay. ServBay sẽ tự thêm PHP vào môi trường terminal của bạn. - Để chạy Webman dưới nền (daemon), bổ sung tham số
-d
:php start.php start -d
. - Dừng server:
php start.php stop
. - Khởi động lại:
php start.php restart
. - Reload (tái khởi động nhẹ, không ngắt kết nối hiện tại):
php start.php reload
.
Kiểm tra hoạt động của dự án
Khi Webman đã chạy và lắng nghe tại 127.0.0.1:8787
, hãy dùng trình duyệt truy cập những đường dẫn sau để kiểm tra:
http://localhost:8787/
: Trang sẽ hiện ra thông điệpHello ServBay & Webman!
.http://localhost:8787/memcached
: Sẽ hiển thịHello Memcached from ServBay!
– xác nhận kết nối Memcached hoạt động.http://localhost:8787/redis
: Sẽ hiển thịHello Redis from ServBay!
– xác nhận kết nối Redis hoạt động.http://localhost:8787/mysql-add
: Hiện thông báoUser added to MySQL
, đồng thời thêm một record vào bảngusers
của MySQL.http://localhost:8787/mysql
: Trả về danh sách user dạng JSON lấy từ bảngusers
của MySQL.http://localhost:8787/pgsql-add
: Hiện thông báoUser added to PostgreSQL
, đồng thời thêm một record vào bảngusers
của PostgreSQL.http://localhost:8787/pgsql
: Trả về danh sách user dạng JSON lấy từ bảngusers
của PostgreSQL.
Nếu xảy ra lỗi khi truy cập các URL trên, hãy kiểm tra terminal của Webman để tìm thông báo lỗi, xác nhận các dịch vụ MySQL, PostgreSQL, Redis, Memcached trên ServBay đã được bật và các extension PHP đã được kích hoạt đầy đủ.
Câu hỏi thường gặp (FAQ)
- Q: Không chạy được lệnh
php start.php start
?- A: Đảm bảo bạn đã dùng terminal chuyển thư mục đúng tới dự án (
cd servbay-webman-app
). Đồng thời, xác nhận PHP của ServBay đã nằm trong biến PATH (bình thường ServBay sẽ tự xử lý).
- A: Đảm bảo bạn đã dùng terminal chuyển thư mục đúng tới dự án (
- Q: Truy cập
localhost:8787
báo lỗi không kết nối được?- A: Kiểm tra terminal chạy Webman có thông báo lỗi không. Đảm bảo port
8787
không bị chương trình khác chiếm dụng. Nếu bị, sửa lại file cấu hình Webman (ví dụconfig/server.php
) để thay port khác.
- A: Kiểm tra terminal chạy Webman có thông báo lỗi không. Đảm bảo port
- Q: Không kết nối được database?
- A: Kiểm tra xem MySQL và PostgreSQL trên ServBay đã bật chưa. Kiểm tra file
config/database.php
đạt đúng thông tin (host, port, dbname, username, password) giống ServBay (root
/password
). Đồng thời chắc chắn bạn đã tạo database và bảngusers
.
- A: Kiểm tra xem MySQL và PostgreSQL trên ServBay đã bật chưa. Kiểm tra file
- Q: Memcached hoặc Redis báo không kết nối?
- A: Đảm bảo Memcached, Redis trên ServBay đang chạy. Kiểm tra địa chỉ, cổng cấu hình trong file
app/controller/CacheController.php
đúng (mặc định là127.0.0.1:11211
và127.0.0.1:6379
). Đảm bảo PHP đã bật extensionmemcached
vàredis
.
- A: Đảm bảo Memcached, Redis trên ServBay đang chạy. Kiểm tra địa chỉ, cổng cấu hình trong file
Tổng kết
Làm theo các bước trên, bạn đã thiết lập và vận hành thành công dự án Webman cơ bản trong môi trường phát triển cục bộ ServBay. Bạn học được cách tận dụng ưu thế của ServBay để dựng môi trường Webman nhanh chóng, tích hợp cả database lẫn cache. Khả năng hiệu năng của Webman kết hợp cùng sự tiện lợi của ServBay, sẽ giúp bạn phát triển ứng dụng PHP bất đồng bộ mạnh mẽ và hiện đại. Mong rằng hướng dẫn này giúp bạn khai thác tối đa sức mạnh của ServBay và Webman để xây dựng những sản phẩm web xuất sắc!